From cd53fd042f0aac44d3ba93d02376cbb101af7be0 Mon Sep 17 00:00:00 2001 From: suzuki Date: Wed, 17 Jun 2026 07:21:04 +0000 Subject: [PATCH 001/113] docs: update AGENTS.md --- AGENTS.md | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 213623d..a011445 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,27 +21,29 @@ - When stuck on a goal, search closing lemmas with `lean_state_search` / `lean_hammer_premise`, then verify with `lean_multi_attempt` before editing. -- If Lean reports `expected '{' or indented tactic sequence`, fix indentation - first — almost always a whitespace issue, not a tactic bug. - **Why:** tactics that compile by accident can mask unsoundness; this - project mandates a fully axiom-free codebase. - -**Simplicity first.** -- Formalize only what the current task requires. No speculative - generalizations, no helper lemmas "for later", no premature abstraction - across `CStarAlgebra` / `StarAlgebra` / `NormedAlgebra`. -- Prefer the most direct proof that closes the goal over the cleverest one. - If `simp` / `linarith` / `aesop` suffices, do not unfold by hand. - **Why:** every extra declaration is surface area to maintain and to keep - axiom-free; speculative API decays faster than it earns interest. - -**Surgical changes.** -- Edit only files demanded by the task. Resist opportunistic renames, - whitespace fixes, or namespace reshuffles in unrelated proofs. -- Do not rewrite existing proofs that already compile. If a proof is ugly - but correct, leave it; flag it in review rather than touching it. - **Why:** Mathlib-style review is line-noise sensitive, and unrelated edits - break `git blame` and inflate merge conflicts. + +**Abstraction first.** +- Aim for the abstraction level used in the source literature and the mathematically conventional form + from the *first* commit, not as a later refactor. +- Do not specialise to a concrete model because the + immediate task uses only that case, and do not weaken hypotheses to + match whatever fragment Mathlib currently has the most lemmas for — + follow the literature, even when it forces you to build supporting + API that Mathlib does not yet provide. + +**Prove what is provable; do not *defer* it.** +- Do not introduce a `class` / `structure` field (or a `def … : Prop` + hypothesis) that stands in for a theorem when that theorem has a known + mathematical proof — *even when Mathlib lacks the supporting lemmas, and + even when proving it is out of scope for the current change.* +- A hypothesis class is acceptable **only** for genuinely model-dependent + inputs that are false for some objects in the class *and* for which no known + universal proof exists. + **Why:** deferred hypotheses became permanent here. Once a + `Has…` field is wired in, discharging it later costs far more than proving it + up front and the trusted base grows silently. Restricting hypotheses to the + irreducible (a) inputs — and proving or descoping everything else — is what + keeps that base bounded. **Goal-driven verification (Definition of Done).** - A change is done only when `lake build` completes with no new errors or @@ -53,10 +55,6 @@ - When a tactic fails to close a goal, do not stack `try` / `<;>` to silence the error — re-inspect the goal with `lean_goal` and address the actual mismatch. -- Never report a task as successful until the above checks pass. - **Why:** "looks right" is not a soundness gate; the kernel is, and - downstream modules can still break even when the edited file type-checks - in isolation. ## Editing Hygiene From 072275e37c6aa476d4525ea12365325bbbd0e105 Mon Sep 17 00:00:00 2001 From: suzuki Date: Wed, 17 Jun 2026 20:24:14 +0000 Subject: [PATCH 002/113] feat(LocalNet): build AQFT net properties and organize by module Build the AQFT local-net layer on the isotony embedding: functoriality, locality (disjoint regions commute), the quasi-local C*-algebra (C*-inductive limit) and covariance (symmetry action). Relax `LocalNet.sites` to an arbitrary (possibly infinite) type so the quasi-local algebra is a genuine inductive limit. Generalize the C*-inductive-limit construction into `ForMathlib` (`DirectLimit` *-algebra and C*-norm, `Completion` C*-algebra), and organize `LocalNet/` by net property: Basic / Isotony / Locality / QuasiLocal / Covariance. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 9 +- .../{LocalNet.lean => LocalNet/Basic.lean} | 292 +++--------------- .../Algebra/LocalNet/Covariance.lean | 162 ++++++++++ QuantumSystem/Algebra/LocalNet/Isotony.lean | 284 +++++++++++++++++ QuantumSystem/Algebra/LocalNet/Locality.lean | 127 ++++++++ .../Algebra/LocalNet/QuasiLocal.lean | 171 ++++++++++ .../Analysis/Entropy/Regularize.lean | 2 +- .../Analysis/Matrix/PartialTrace.lean | 15 +- .../Algebra/Colimit/DirectLimitStar.lean | 94 ++++++ .../Analysis/CStarAlgebra/DirectLimit.lean | 73 +++++ .../Topology/Algebra/CStarCompletion.lean | 117 +++++++ QuantumSystem/Notation.lean | 2 +- 12 files changed, 1084 insertions(+), 264 deletions(-) rename QuantumSystem/Algebra/{LocalNet.lean => LocalNet/Basic.lean} (60%) create mode 100644 QuantumSystem/Algebra/LocalNet/Covariance.lean create mode 100644 QuantumSystem/Algebra/LocalNet/Isotony.lean create mode 100644 QuantumSystem/Algebra/LocalNet/Locality.lean create mode 100644 QuantumSystem/Algebra/LocalNet/QuasiLocal.lean create mode 100644 QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean create mode 100644 QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean create mode 100644 QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 2f72535..039c6a5 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -10,7 +10,11 @@ public import QuantumSystem.Algebra.CStarAlgebra.QuasiState public import QuantumSystem.Algebra.CStarAlgebra.State public import QuantumSystem.Algebra.CStarAlgebra.State.Continuity public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful -public import QuantumSystem.Algebra.LocalNet +public import QuantumSystem.Algebra.LocalNet.Basic +public import QuantumSystem.Algebra.LocalNet.Covariance +public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.Algebra.LocalNet.Locality +public import QuantumSystem.Algebra.LocalNet.QuasiLocal public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal @@ -27,8 +31,10 @@ public import QuantumSystem.Analysis.Matrix.PartialTrace public import QuantumSystem.Analysis.Matrix.Pinching public import QuantumSystem.Analysis.Matrix.PosDef public import QuantumSystem.Channel +public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar public import QuantumSystem.ForMathlib.Analysis.Calculus.Deriv.Sign public import QuantumSystem.ForMathlib.Analysis.Complex.Basic +public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.HilbertSpace public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Ideal public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.NonUnital @@ -51,6 +57,7 @@ public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.StarAlgEquiv public import QuantumSystem.ForMathlib.LinearAlgebra.Span.Def public import QuantumSystem.ForMathlib.RingTheory.RootsOfUnity.Complex +public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion public import QuantumSystem.ForMathlib.Topology.DenseLinear public import QuantumSystem.ForMathlib.Topology.MetricSpace.Completion public import QuantumSystem.Notation diff --git a/QuantumSystem/Algebra/LocalNet.lean b/QuantumSystem/Algebra/LocalNet/Basic.lean similarity index 60% rename from QuantumSystem/Algebra/LocalNet.lean rename to QuantumSystem/Algebra/LocalNet/Basic.lean index c2594ae..7cdec7a 100644 --- a/QuantumSystem/Algebra/LocalNet.lean +++ b/QuantumSystem/Algebra/LocalNet/Basic.lean @@ -3,54 +3,28 @@ module public import QuantumSystem.Channel /-! -# Local Net of Matrix Algebras (finite-dim) +# Local Net of Matrix Algebras — basic data -This file defines the data of a **local net of matrix algebras** on a finite lattice. -An AQFT system assigns to each spacetime / lattice region `Λ` an -algebra `𝔄(Λ)` of observables, with **isotony** (`Λ₁ ⊆ Λ₂ ⟹ 𝔄(Λ₁) ⊆ 𝔄(Λ₂)`), **locality** -(disjoint regions commute), and—in the spacetime version—**covariance**. +This file carries the **data** of a local net of matrix algebras and the region-index +combinatorics on which the AQFT net properties are built. An AQFT system assigns to each +lattice region `Λ` an algebra `𝔄(Λ)` of observables; for finite-dimensional quantum spin +systems this specialises to: -For finite-dimensional quantum spin systems, the construction specialises to: - -- a finite set of **sites** `L`, -- a local index type `ℂ^{n_x}` at each site `x ∈ L`, -- regions `Λ ∈ 𝒫(L)` (`Finset L.sites`), -- local algebra `𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` realised concretely as +- a lattice of **sites** `L` (an arbitrary type with `DecidableEq`), +- a finite local index type `ℂ^{n_x}` at each site `x`, +- regions `Λ : Finset L.sites`, +- local algebra `𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` realised as `Matrix (Π s ∈ Λ, idx s) (Π s ∈ Λ, idx s) ℂ`. -This file provides: - -1. the structure carrying the lattice + per-site Hilbert-space data, the derived region index - types, and the index-combiner equivalence relating `regionIdx Λ_total` to the product - `regionIdx Λ × regionIdx (Λ_total \ Λ)`; -2. the **restriction** (Schrödinger-picture partial trace): given regions `Λ ⊆ Λ_total`, - the restriction of a state on `𝔄(Λ_total)` to `𝔄(Λ)`. In density-matrix language this is - exactly the partial trace over the complementary region `Λ_total \ Λ`. - The restriction is the Schrödinger-picture dual of the algebra - inclusion `𝔄(Λ) ↪ 𝔄(Λ_total)`. There is no positional ("left/right") concept — the - operation is parameterised by the region itself. - -## Main definitions - -* `LocalNet` — data carrier: sites + per-site finite index types -* `LocalNet.regionIdx` — index type of a region (dependent product) -* `LocalNet.localAlgebra` — the matrix algebra at a region -* `LocalNet.densityMatrix` — density matrices at a region -* `LocalNet.combineIdx` — `regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ regionIdx Λ_total` -* `LocalNet.includeAlgebra` — isotony embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` -* `LocalNet.regionIdxInsertEquiv` — recursive split: `regionIdx (insert s Λ) ≃ localIdx s × regionIdx Λ` -* `LocalNet.regionIdxPairEquiv` / `regionIdxTripleEquiv` / `regionIdxTripleEquiv'` — - factorisation of `n`-element regions into per-site product types -* `LocalNet.regionIdxComplLeftSite` / `regionIdxComplRightSite` — - `regionIdx ({a, b} \ {a}) ≃ localIdx b` and its right-site dual - -The generic primitives above subsume any partite count; the bipartite / tripartite -factorisation specialisations are exposed below as `regionIdxPairEquiv`, -`regionIdxTripleEquiv`, and `regionIdxTripleEquiv'`. - -The partial-trace / restriction operations (`Matrix.restrict`, `Matrix.restrictKraus`, -`Matrix.QuantumChannel.restrict`, `DensityMatrix.restrict`, and the paper notation -`ρ ↾ Λ`) are defined in `QuantumSystem/Analysis/Matrix/PartialTrace.lean`. +This file provides the carrier structure, the derived region-index types, the index-combiner +equivalence `combineIdx` realising `regionIdx Λ_total ≃ regionIdx Λ × regionIdx (Λ_total \ Λ)`, +the cardinality factorisation, the transport `regionIdxCongr`, and the `n`-partite region +factorisation equivalences (`regionIdxPairEquiv`, `regionIdxTripleEquiv`, `regionIdxCompl*`). + +The net **properties** built on this data live in sibling modules: +`LocalNet.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `LocalNet.Locality` +(disjoint regions commute), `LocalNet.QuasiLocal` (quasi-local C⋆-algebra), `LocalNet.Covariance` +(symmetry action). Restriction / partial trace lives in `Analysis/Matrix/PartialTrace.lean`. ## References @@ -60,14 +34,17 @@ The partial-trace / restriction operations (`Matrix.restrict`, `Matrix.restrictK @[expose] public section -/-- Data for a finite-dimensional **local net of matrix algebras** on a finite lattice. +/-- Data for a **local net of matrix algebras** on a (possibly infinite) lattice of sites. Each site `s : sites` carries a finite index type `localIdx s` whose cardinality is the - local Hilbert-space dimension. The local algebra at a region `Λ ⊆ sites` is then the - matrix algebra on the dependent product `Π s ∈ Λ, localIdx s`. -/ + local Hilbert-space dimension. The local algebra at a *finite* region `Λ : Finset sites` + is then the matrix algebra on the dependent product `Π s ∈ Λ, localIdx s` — finite even + when `sites` is infinite, since regions are finite subsets. Leaving `sites` unrestricted + (only `DecidableEq`) is what allows the quasi-local algebra to be a genuine inductive + limit over the directed set of finite regions, as in Naaijkens 2012 §1.3 and + Bratteli–Robinson Vol.2 §6.2. -/ structure LocalNet where - /-- Lattice of sites — `Fintype` for the finite-dim project scope. -/ + /-- Lattice of sites — an arbitrary type; regions are its finite subsets. -/ sites : Type* - [sitesFintype : Fintype sites] [sitesDecEq : DecidableEq sites] /-- Local Hilbert-space index type at each site. -/ localIdx : sites → Type* @@ -76,7 +53,7 @@ structure LocalNet where namespace LocalNet -attribute [instance] sitesFintype sitesDecEq localFintype localDecEq +attribute [instance] sitesDecEq localFintype localDecEq variable (L : LocalNet) @@ -152,199 +129,6 @@ theorem card_regionIdx_total {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total rw [← Fintype.card_prod] exact Fintype.card_congr (L.combineIdx h).symm -/-! ### Isotony embedding (algebra inclusion) - -The isotony embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` is realised concretely as the tensor with -identity on the complement, `A ↦ A ⊗ I_{Λ_total \ Λ}`. We bundle it as a unital -`*`-algebra homomorphism (`StarAlgHom`) so that the AQFT axioms (Naaijkens 2012 §1.3 -line 211, Verch 2025 §1.2 axiom (i), Bratteli–Robinson Vol.2 §6.2) — preservation of -unit, product, and adjoint — are guaranteed at the type level. - -Pipeline: entry-wise underlying function `includeAlgebraFun` → algebraic identities -`includeAlgebraFun_{one,mul,star,...}` → bundled `includeAlgebra : _ →⋆ₐ[ℂ] _`. -/ - -/-- Entry-wise underlying function for `includeAlgebra`, defined separately so the - structural simp lemmas (`includeAlgebraFun_apply`, `..._apply_combineIdx`) reduce - by `rfl`/`simp` without going through the `StarAlgHom` coercion. -/ -noncomputable def includeAlgebraFun {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) : L.localAlgebra Λ_total := - Matrix.of fun s s' => - if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then - X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 - else 0 - -@[simp] lemma includeAlgebraFun_apply {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) (s s' : L.regionIdx Λ_total) : - L.includeAlgebraFun h X s s' = - if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then - X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 - else 0 := rfl - -/-- Entry-wise behaviour of `includeAlgebraFun` at combined indices: the off-diagonal - components in the complementary region vanish, leaving `X a a'` on the diagonal. -/ -@[simp] lemma includeAlgebraFun_apply_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) - (a a' : L.regionIdx Λ) (b b' : L.regionIdx (Λ_total \ Λ)) : - L.includeAlgebraFun h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) = - if b = b' then X a a' else 0 := by - simp [includeAlgebraFun, Equiv.symm_apply_apply] - -lemma includeAlgebraFun_zero {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.includeAlgebraFun h 0 = 0 := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.zero_apply] - split_ifs <;> rfl - -lemma includeAlgebraFun_add {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X Y : L.localAlgebra Λ) : - L.includeAlgebraFun h (X + Y) = - L.includeAlgebraFun h X + L.includeAlgebraFun h Y := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.add_apply] - split_ifs with hbb - · rfl - · rw [add_zero] - -lemma includeAlgebraFun_smul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (c : ℂ) (X : L.localAlgebra Λ) : - L.includeAlgebraFun h (c • X) = c • L.includeAlgebraFun h X := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.smul_apply, smul_eq_mul] - split_ifs with hbb - · rfl - · rw [mul_zero] - -lemma includeAlgebraFun_one {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.includeAlgebraFun h 1 = 1 := by - ext s s' - by_cases hss : s = s' - · subst hss - rw [includeAlgebraFun_apply, if_pos rfl, Matrix.one_apply_eq, Matrix.one_apply_eq] - · rw [includeAlgebraFun_apply, Matrix.one_apply_ne hss] - -- Translate `s ≠ s'` to a disjunction on the two coordinates of `(combineIdx h).symm`. - have hne : (L.combineIdx h).symm s ≠ (L.combineIdx h).symm s' := fun heq => - hss ((L.combineIdx h).symm.injective heq) - rw [Ne, Prod.ext_iff, not_and_or] at hne - by_cases h2 : ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 - · rw [if_pos h2] - rcases hne with h1 | h2' - · rw [Matrix.one_apply_ne h1] - · exact absurd h2 h2' - · rw [if_neg h2] - -lemma includeAlgebraFun_star {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) : - L.includeAlgebraFun h (star X) = star (L.includeAlgebraFun h X) := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.star_apply] - by_cases h2 : ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 - · rw [if_pos h2, if_pos h2.symm] - · rw [if_neg h2, if_neg (fun hh => h2 hh.symm), star_zero] - -lemma includeAlgebraFun_mul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X Y : L.localAlgebra Λ) : - L.includeAlgebraFun h (X * Y) = - L.includeAlgebraFun h X * L.includeAlgebraFun h Y := by - ext s s' - -- Express both rows/columns through `combineIdx` so the `_apply_combineIdx` simp lemma fires. - set sa := ((L.combineIdx h).symm s).1 with hsa - set sb := ((L.combineIdx h).symm s).2 with hsb - set s'a := ((L.combineIdx h).symm s').1 with hs'a - set s'b := ((L.combineIdx h).symm s').2 with hs'b - have hs : s = L.combineIdx h (sa, sb) := by - simp [sa, sb, Equiv.apply_symm_apply] - have hs' : s' = L.combineIdx h (s'a, s'b) := by - simp [s'a, s'b, Equiv.apply_symm_apply] - rw [hs, hs', includeAlgebraFun_apply_combineIdx, Matrix.mul_apply] - -- Reindex the RHS sum (over `regionIdx Λ_total`) via `combineIdx`. - rw [show ((L.includeAlgebraFun h X * L.includeAlgebraFun h Y) - (L.combineIdx h (sa, sb)) (L.combineIdx h (s'a, s'b))) = - ∑ p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ), - L.includeAlgebraFun h X (L.combineIdx h (sa, sb)) (L.combineIdx h p) * - L.includeAlgebraFun h Y (L.combineIdx h p) (L.combineIdx h (s'a, s'b)) from by - rw [Matrix.mul_apply] - exact ((L.combineIdx h).sum_comp _).symm] - rw [Fintype.sum_prod_type] - simp_rw [includeAlgebraFun_apply_combineIdx] - -- Goal: - -- (if sb = s'b then ∑ a'', X sa a'' * Y a'' s'a else 0) - -- = ∑ a'', ∑ b'', (if sb = b'' then X sa a'' else 0) * (if b'' = s'b then Y a'' s'a else 0) - by_cases hbb : sb = s'b - · rw [if_pos hbb] - refine Finset.sum_congr rfl fun a'' _ => ?_ - rw [Finset.sum_eq_single sb - (fun b'' _ hb'' => by rw [if_neg fun heq => hb'' heq.symm, zero_mul]) - (fun h_not_mem => absurd (Finset.mem_univ sb) h_not_mem)] - rw [if_pos rfl, ← hbb, if_pos rfl] - · rw [if_neg hbb] - refine (Finset.sum_eq_zero fun a'' _ => ?_).symm - refine Finset.sum_eq_zero fun b'' _ => ?_ - by_cases hb_sb : sb = b'' - · subst hb_sb - rw [if_neg hbb, mul_zero] - · rw [if_neg hb_sb, zero_mul] - -lemma includeAlgebraFun_algebraMap {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) (c : ℂ) : - L.includeAlgebraFun h ((algebraMap ℂ (L.localAlgebra Λ)) c) = - (algebraMap ℂ (L.localAlgebra Λ_total)) c := by - rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, - includeAlgebraFun_smul, includeAlgebraFun_one] - -/-- **Isotony embedding** `𝔄(Λ) ↪ 𝔄(Λ_total)`: tensor a local matrix with the identity on - the complementary region. Realises the inclusion `A ↦ A ⊗ I_{Λ_total \ Λ}` from - Naaijkens 2012 §1.3 line 211, Verch 2025 §1.2 axiom (i), Bratteli–Robinson Vol.2 §6.2. - Bundled as a unital `*`-algebra homomorphism so that `map_one`, `map_mul`, `map_star` - are available via the `StarAlgHom` API. Entry-wise: - `(includeAlgebra h X) s s' = X (combineIdx⁻¹ s).1 (combineIdx⁻¹ s').1` when the - complementary indices match, else `0`. -/ -noncomputable def includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.localAlgebra Λ →⋆ₐ[ℂ] L.localAlgebra Λ_total where - toFun := L.includeAlgebraFun h - map_zero' := L.includeAlgebraFun_zero h - map_add' := L.includeAlgebraFun_add h - map_one' := L.includeAlgebraFun_one h - map_mul' := L.includeAlgebraFun_mul h - commutes' := L.includeAlgebraFun_algebraMap h - map_star' := L.includeAlgebraFun_star h - -/-- Entry-wise unfolding of `includeAlgebra h X`: at indices `(s, s')` of the larger - region, the embedded matrix equals `X` on the diagonal (in the complementary index) - and zero off-diagonal. -/ -@[simp] lemma includeAlgebra_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) (s s' : L.regionIdx Λ_total) : - L.includeAlgebra h X s s' = - if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then - X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 - else 0 := rfl - -/-- **Injectivity of the isotony embedding** (the `↪` of `𝔄(Λ) ↪ 𝔄(Λ_total)`): under - the standing AQFT non-degeneracy assumption that the complementary region has a - non-empty index type, `includeAlgebra h` is injective as a map of `*`-algebras. -/ -theorem includeAlgebra_injective {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - [hne : Nonempty (L.regionIdx (Λ_total \ Λ))] : - Function.Injective (L.includeAlgebra h) := by - rw [injective_iff_map_eq_zero] - intro X hX - ext a a' - obtain ⟨b⟩ := hne - have heq : L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = - 0 := by rw [hX]; rfl - have key : L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = - X a a' := by - change L.includeAlgebraFun h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = X a a' - rw [includeAlgebraFun_apply_combineIdx, if_pos rfl] - rw [key] at heq - simpa using heq - -/-! ### Region equivalences - -Generic equivalences over arbitrary `Fintype` site sets — used both directly (for any -finite site set) and as building blocks for the bipartite (`regionIdxPairEquiv`) and -tripartite (`regionIdxTripleEquiv`, `regionIdxTripleEquiv'`) factorisations below. -/ - -variable (L : LocalNet) - /-- Transport `regionIdx` along a Finset equality. -/ def regionIdxCongr {Λ Λ' : Finset L.sites} (h : Λ = Λ') : L.regionIdx Λ ≃ L.regionIdx Λ' := @@ -357,6 +141,14 @@ def regionIdxCongr {Λ Λ' : Finset L.sites} (h : Λ = Λ') : subst h rfl +/-! ### Region equivalences + +Generic equivalences over arbitrary site types — used both directly (for any finite region) +and as building blocks for the bipartite (`regionIdxPairEquiv`) and tripartite +(`regionIdxTripleEquiv`, `regionIdxTripleEquiv'`) factorisations below. -/ + +variable (L : LocalNet) + /-- Singleton region: `regionIdx {s} ≃ localIdx s`. -/ def singletonRegionIdxEquiv (s : L.sites) : L.regionIdx ({s} : Finset L.sites) ≃ L.localIdx s where @@ -376,10 +168,11 @@ def singletonRegionIdxEquiv (s : L.sites) : /-! ### Generic n-partite primitives -Building blocks for any finite site set: `regionIdx ∅ ≃ PUnit`, an `insert`-based -recursive split, and the universal product form `regionIdx Finset.univ ≃ Π s, localIdx s`. -Two- and three-element factor equivs are derived from the recursive split — adding more -partite counts (4, 5, ...) is now a one-liner with no new boilerplate. -/ +Building blocks for any finite region: `regionIdx ∅ ≃ PUnit`, an `insert`-based recursive +split, and (for finite site types) the universal product form +`regionIdx Finset.univ ≃ Π s, localIdx s`. Two- and three-element factor equivs are derived +from the recursive split — adding more partite counts (4, 5, ...) is now a one-liner with no +new boilerplate. -/ /-- The empty region: `regionIdx ∅ ≃ PUnit`. The dependent product over the empty subtype has a unique element. -/ @@ -409,8 +202,9 @@ def regionIdxInsertEquiv {s : L.sites} {Λ : Finset L.sites} (hs : s ∉ Λ) : (Equiv.prodCongr (L.singletonRegionIdxEquiv s) (L.regionIdxCongr h_compl_eq)) /-- The universal region: `regionIdx Finset.univ ≃ Π s : sites, localIdx s`. - Collapses the `Finset.univ`-subtype back to the underlying type. -/ -def regionIdxUnivEquiv : L.regionIdx (Finset.univ : Finset L.sites) ≃ + Collapses the `Finset.univ`-subtype back to the underlying type. Requires `Fintype sites` + (the only place a finite site set is needed; the rest of the API runs on infinite lattices). -/ +def regionIdxUnivEquiv [Fintype L.sites] : L.regionIdx (Finset.univ : Finset L.sites) ≃ ∀ s : L.sites, L.localIdx s where toFun f s := f ⟨s, Finset.mem_univ s⟩ invFun g := fun ⟨s, _⟩ => g s diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean new file mode 100644 index 0000000..74b7790 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -0,0 +1,162 @@ +module + +public import QuantumSystem.Algebra.LocalNet.QuasiLocal + +/-! +# Covariance of the local net + +A **symmetry** of a `LocalNet` is a permutation `σ` of the sites together with, for each site, +an equivalence `localIdx s ≃ localIdx (σ s)` matching the local dimensions. Such data induces a +`*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` between the local algebras of a region and its image, +realising the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σ Λ)` (Naaijkens 2012 §3.2, Verch 2025 §1.2). + +Symmetries compose (identity and composition below), so any group acting on the sites with +matching local dimensions acts on the net by `*`-isomorphisms. The per-region isomorphisms are +natural with respect to isotony (`relabelAlgebra_includeAlgebra`), so they assemble into a +`*`-endomorphism `quasiLocalRelabel` of the quasi-local algebra (the covariance action). +-/ + +@[expose] public section + +namespace LocalNet + +/-- Pointwise value of the complement projection of `combineIdx.symm` (holds by `rfl`). -/ +@[simp] theorem combineIdx_symm_snd_apply {L : LocalNet} {Λ Λ_total : Finset L.sites} + (h : Λ ⊆ Λ_total) (f : L.regionIdx Λ_total) (w : ↥(Λ_total \ Λ)) : + ((L.combineIdx h).symm f).2 w = f ⟨w.val, (Finset.mem_sdiff.mp w.property).1⟩ := rfl + +/-- A symmetry of a local net: a site permutation together with dimension-matching equivalences + on the local index types. A group acting on the net is a homomorphism into these. -/ +structure Symmetry (L : LocalNet) where + /-- The underlying permutation of the sites. -/ + σ : L.sites ≃ L.sites + /-- Dimension matching: relabel the local index type at each site. -/ + idx : ∀ s, L.localIdx s ≃ L.localIdx (σ s) + +namespace Symmetry + +variable {L : LocalNet} (a : L.Symmetry) + +/-- The image of a region under a symmetry. -/ +def region (Λ : Finset L.sites) : Finset L.sites := Λ.map a.σ.toEmbedding + +variable (L) in +/-- The identity symmetry. -/ +def id : L.Symmetry where + σ := Equiv.refl _ + idx _ := Equiv.refl _ + +/-- Composition of symmetries: apply `b`, then `a`. The per-site equivalences compose, with the + intermediate site type aligning definitionally. -/ +def comp (a b : L.Symmetry) : L.Symmetry where + σ := b.σ.trans a.σ + idx s := (b.idx s).trans (a.idx (b.σ s)) + +@[simp] theorem region_id (Λ : Finset L.sites) : (Symmetry.id L).region Λ = Λ := by + simp [region, Symmetry.id] + +@[simp] theorem region_comp (a b : L.Symmetry) (Λ : Finset L.sites) : + (a.comp b).region Λ = a.region (b.region Λ) := by + simp [region, comp, Finset.map_map, Equiv.trans_toEmbedding] + +/-- Relabelling of region indices: transport along the site permutation and the per-site + dimension equivalences. -/ +def relabelRegionIdx (Λ : Finset L.sites) : + L.regionIdx Λ ≃ L.regionIdx (a.region Λ) := + Equiv.piCongr + (Equiv.subtypeEquiv a.σ (fun _ => (Finset.mem_map' a.σ.toEmbedding).symm)) + (fun s => a.idx s.val) + +/-- The **covariance `*`-isomorphism** `β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)`, obtained by reindexing the + matrix algebra along `relabelRegionIdx`. Realises `β_a(𝔄(Λ)) = 𝔄(a Λ)`. -/ +noncomputable def relabelAlgebra (Λ : Finset L.sites) : + L.localAlgebra Λ ≃⋆ₐ[ℂ] L.localAlgebra (a.region Λ) := + StarAlgEquiv.ofAlgEquiv (Matrix.reindexAlgEquiv ℂ ℂ (a.relabelRegionIdx Λ)) + (fun X => by + simp only [Matrix.reindexAlgEquiv_apply, Matrix.star_eq_conjTranspose, + Matrix.conjTranspose_reindex]) + +@[simp] theorem relabelAlgebra_apply (Λ : Finset L.sites) (X : L.localAlgebra Λ) : + a.relabelAlgebra Λ X = Matrix.reindex (a.relabelRegionIdx Λ) (a.relabelRegionIdx Λ) X := + rfl + +/-- The `Λ`-coordinate of decomposing a relabelled index equals relabelling the `aΛ`-coordinate: + `relabelRegionIdx` commutes with the isotony split `combineIdx`. Holds definitionally. -/ +private theorem relabelRegionIdx_symm_combineIdx_fst {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') + (t : L.regionIdx (a.region Λ')) : + ((L.combineIdx h).symm ((a.relabelRegionIdx Λ').symm t)).1 = + (a.relabelRegionIdx Λ).symm ((L.combineIdx (Finset.map_subset_map.mpr h)).symm t).1 := by + funext u + rfl + +/-- **Covariance / naturality**: the symmetry `*`-isomorphism intertwines the isotony + embeddings, so `β_a` is an automorphism of the *net* — `β_a(𝔄(Λ)) = 𝔄(a Λ)` compatibly with + inclusions (Naaijkens 2012 §3.2 covariance axiom). -/ +theorem relabelAlgebra_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') + (X : L.localAlgebra Λ) : + a.relabelAlgebra Λ' (L.includeAlgebra h X) = + L.includeAlgebra (Finset.map_subset_map.mpr h) (a.relabelAlgebra Λ X) := by + ext s s' + simp only [relabelAlgebra_apply, Matrix.reindex_apply, Matrix.submatrix_apply, + includeAlgebra_apply] + rw [a.relabelRegionIdx_symm_combineIdx_fst h s, a.relabelRegionIdx_symm_combineIdx_fst h s'] + have key2 : (((L.combineIdx h).symm ((a.relabelRegionIdx Λ').symm s)).2 = + ((L.combineIdx h).symm ((a.relabelRegionIdx Λ').symm s')).2) + ↔ (((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = + ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2) := by + constructor + · intro H + funext v + obtain ⟨vv, hvv⟩ := v + have hv := Finset.mem_sdiff.mp hvv + have hΛ' : a.σ.symm vv ∈ Λ' := Finset.mem_map_equiv.mp hv.1 + have hΛ : a.σ.symm vv ∉ Λ := fun hc => hv.2 (Finset.mem_map_equiv.mpr hc) + have hcong := congrFun H ⟨a.σ.symm vv, Finset.mem_sdiff.mpr ⟨hΛ', hΛ⟩⟩ + simp only [combineIdx_symm_snd_apply, relabelRegionIdx, Equiv.piCongr_symm_apply, + Equiv.subtypeEquiv_apply, EmbeddingLike.apply_eq_iff_eq] at hcong + change s ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ = s' ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ + convert hcong using 2 <;> + first + | exact (a.σ.apply_symm_apply vv).symm + | exact Subtype.ext (a.σ.apply_symm_apply vv).symm + · intro H + funext w + have hw := Finset.mem_sdiff.mp w.property + have hv : a.σ w.val ∈ a.region Λ' \ a.region Λ := Finset.mem_sdiff.mpr + ⟨Finset.mem_map' _ |>.mpr hw.1, fun hc => hw.2 (Finset.mem_map' _ |>.mp hc)⟩ + have hcong := congrFun H ⟨a.σ w.val, hv⟩ + simpa [combineIdx_symm_snd_apply, relabelRegionIdx, Equiv.piCongr_symm_apply, + Equiv.subtypeEquiv_apply, Equiv.symm_apply_apply, + EmbeddingLike.apply_eq_iff_eq] using hcong + by_cases hc : ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = + ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2 + · rw [if_pos (key2.mpr hc), if_pos hc] + · rw [if_neg (fun hcc => hc (key2.mp hcc)), if_neg hc] + +/-! ### Covariance action on the quasi-local algebra + +The per-region symmetry `*`-isomorphisms, being natural with respect to isotony, assemble into +a `*`-endomorphism of the algebra of local observables `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧`. +Well-definedness is exactly `relabelAlgebra_includeAlgebra`. This is the AQFT covariance action +on the (pre-completion) quasi-local algebra. -/ + +/-- The action of a symmetry on the algebra of local observables, as a ring homomorphism: + `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, relabel X⟩⟧`. Well-defined by net-covariance + (`relabelAlgebra_includeAlgebra`). -/ +noncomputable def quasiLocalRelabel : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := + DirectLimit.Ring.lift (fun Λ : Finset L.sites => L.localAlgebra Λ) + (fun _ _ h => L.includeAlgebra h) L.quasiLocalAlgebra + (fun Λ => (L.ιLocal (a.region Λ)).comp + ((a.relabelAlgebra Λ).toAlgEquiv.toAlgHom.toRingHom)) + (fun Λ Λ' h X => by + simp only [RingHom.comp_apply, AlgHom.toRingHom_eq_coe, RingHom.coe_coe, + AlgEquiv.coe_algHom, StarAlgEquiv.coe_toAlgEquiv, a.relabelAlgebra_includeAlgebra h] + exact L.ιLocal_includeAlgebra _ _) + +@[simp] theorem quasiLocalRelabel_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.relabelAlgebra Λ X⟩⟧ := + rfl + +end Symmetry + +end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/Isotony.lean b/QuantumSystem/Algebra/LocalNet/Isotony.lean new file mode 100644 index 0000000..0437c96 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/Isotony.lean @@ -0,0 +1,284 @@ +module + +public import QuantumSystem.Algebra.LocalNet.Basic + +/-! +# Isotony embedding of the local net + +The **isotony** axiom of an AQFT net: for `Λ ⊆ Λ_total` there is a unital `*`-algebra inclusion +`𝔄(Λ) ↪ 𝔄(Λ_total)`, realised concretely as the tensor with identity on the complement +`A ↦ A ⊗ I_{Λ_total \ Λ}` (Naaijkens 2012 §1.3, Verch 2025 §1.2 axiom (i), Bratteli–Robinson +Vol.2 §6.2). This file builds the embedding `includeAlgebra` (as a `StarAlgHom`), proves it is +injective, and establishes its **functoriality** (`includeAlgebra_trans` / `includeAlgebra_refl`), +which makes the net a directed system of `*`-algebras. + +Pipeline: entry-wise underlying function `includeAlgebraFun` → algebraic identities +`includeAlgebraFun_{one,mul,star,...}` → bundled `includeAlgebra : _ →⋆ₐ[ℂ] _`. +-/ + +@[expose] public section + +namespace LocalNet + +variable (L : LocalNet) + +/-! ### Isotony embedding (algebra inclusion) -/ + +/-- Entry-wise underlying function for `includeAlgebra`, defined separately so the + structural simp lemmas (`includeAlgebraFun_apply`, `..._apply_combineIdx`) reduce + by `rfl`/`simp` without going through the `StarAlgHom` coercion. -/ +noncomputable def includeAlgebraFun {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X : L.localAlgebra Λ) : L.localAlgebra Λ_total := + Matrix.of fun s s' => + if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then + X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 + else 0 + +@[simp] lemma includeAlgebraFun_apply {Λ Λ_total : Finset L.sites} + (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) (s s' : L.regionIdx Λ_total) : + L.includeAlgebraFun h X s s' = + if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then + X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 + else 0 := rfl + +/-- Entry-wise behaviour of `includeAlgebraFun` at combined indices: the off-diagonal + components in the complementary region vanish, leaving `X a a'` on the diagonal. -/ +@[simp] lemma includeAlgebraFun_apply_combineIdx + {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) + (a a' : L.regionIdx Λ) (b b' : L.regionIdx (Λ_total \ Λ)) : + L.includeAlgebraFun h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) = + if b = b' then X a a' else 0 := by + simp [includeAlgebraFun, Equiv.symm_apply_apply] + +lemma includeAlgebraFun_zero {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : + L.includeAlgebraFun h 0 = 0 := by + ext s s' + simp only [includeAlgebraFun_apply, Matrix.zero_apply] + split_ifs <;> rfl + +lemma includeAlgebraFun_add {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X Y : L.localAlgebra Λ) : + L.includeAlgebraFun h (X + Y) = + L.includeAlgebraFun h X + L.includeAlgebraFun h Y := by + ext s s' + simp only [includeAlgebraFun_apply, Matrix.add_apply] + split_ifs with hbb + · rfl + · rw [add_zero] + +lemma includeAlgebraFun_smul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (c : ℂ) (X : L.localAlgebra Λ) : + L.includeAlgebraFun h (c • X) = c • L.includeAlgebraFun h X := by + ext s s' + simp only [includeAlgebraFun_apply, Matrix.smul_apply, smul_eq_mul] + split_ifs with hbb + · rfl + · rw [mul_zero] + +lemma includeAlgebraFun_one {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : + L.includeAlgebraFun h 1 = 1 := by + ext s s' + by_cases hss : s = s' + · subst hss + rw [includeAlgebraFun_apply, if_pos rfl, Matrix.one_apply_eq, Matrix.one_apply_eq] + · rw [includeAlgebraFun_apply, Matrix.one_apply_ne hss] + -- Translate `s ≠ s'` to a disjunction on the two coordinates of `(combineIdx h).symm`. + have hne : (L.combineIdx h).symm s ≠ (L.combineIdx h).symm s' := fun heq => + hss ((L.combineIdx h).symm.injective heq) + rw [Ne, Prod.ext_iff, not_and_or] at hne + by_cases h2 : ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 + · rw [if_pos h2] + rcases hne with h1 | h2' + · rw [Matrix.one_apply_ne h1] + · exact absurd h2 h2' + · rw [if_neg h2] + +lemma includeAlgebraFun_star {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X : L.localAlgebra Λ) : + L.includeAlgebraFun h (star X) = star (L.includeAlgebraFun h X) := by + ext s s' + simp only [includeAlgebraFun_apply, Matrix.star_apply] + by_cases h2 : ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 + · rw [if_pos h2, if_pos h2.symm] + · rw [if_neg h2, if_neg (fun hh => h2 hh.symm), star_zero] + +lemma includeAlgebraFun_mul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X Y : L.localAlgebra Λ) : + L.includeAlgebraFun h (X * Y) = + L.includeAlgebraFun h X * L.includeAlgebraFun h Y := by + ext s s' + -- Express both rows/columns through `combineIdx` so the `_apply_combineIdx` simp lemma fires. + set sa := ((L.combineIdx h).symm s).1 with hsa + set sb := ((L.combineIdx h).symm s).2 with hsb + set s'a := ((L.combineIdx h).symm s').1 with hs'a + set s'b := ((L.combineIdx h).symm s').2 with hs'b + have hs : s = L.combineIdx h (sa, sb) := by + simp [sa, sb, Equiv.apply_symm_apply] + have hs' : s' = L.combineIdx h (s'a, s'b) := by + simp [s'a, s'b, Equiv.apply_symm_apply] + rw [hs, hs', includeAlgebraFun_apply_combineIdx, Matrix.mul_apply] + -- Reindex the RHS sum (over `regionIdx Λ_total`) via `combineIdx`. + rw [show ((L.includeAlgebraFun h X * L.includeAlgebraFun h Y) + (L.combineIdx h (sa, sb)) (L.combineIdx h (s'a, s'b))) = + ∑ p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ), + L.includeAlgebraFun h X (L.combineIdx h (sa, sb)) (L.combineIdx h p) * + L.includeAlgebraFun h Y (L.combineIdx h p) (L.combineIdx h (s'a, s'b)) from by + rw [Matrix.mul_apply] + exact ((L.combineIdx h).sum_comp _).symm] + rw [Fintype.sum_prod_type] + simp_rw [includeAlgebraFun_apply_combineIdx] + -- Goal: + -- (if sb = s'b then ∑ a'', X sa a'' * Y a'' s'a else 0) + -- = ∑ a'', ∑ b'', (if sb = b'' then X sa a'' else 0) * (if b'' = s'b then Y a'' s'a else 0) + by_cases hbb : sb = s'b + · rw [if_pos hbb] + refine Finset.sum_congr rfl fun a'' _ => ?_ + rw [Finset.sum_eq_single sb + (fun b'' _ hb'' => by rw [if_neg fun heq => hb'' heq.symm, zero_mul]) + (fun h_not_mem => absurd (Finset.mem_univ sb) h_not_mem)] + rw [if_pos rfl, ← hbb, if_pos rfl] + · rw [if_neg hbb] + refine (Finset.sum_eq_zero fun a'' _ => ?_).symm + refine Finset.sum_eq_zero fun b'' _ => ?_ + by_cases hb_sb : sb = b'' + · subst hb_sb + rw [if_neg hbb, mul_zero] + · rw [if_neg hb_sb, zero_mul] + +lemma includeAlgebraFun_algebraMap {Λ Λ_total : Finset L.sites} + (h : Λ ⊆ Λ_total) (c : ℂ) : + L.includeAlgebraFun h ((algebraMap ℂ (L.localAlgebra Λ)) c) = + (algebraMap ℂ (L.localAlgebra Λ_total)) c := by + rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, + includeAlgebraFun_smul, includeAlgebraFun_one] + +/-- **Isotony embedding** `𝔄(Λ) ↪ 𝔄(Λ_total)`: tensor a local matrix with the identity on + the complementary region. Realises the inclusion `A ↦ A ⊗ I_{Λ_total \ Λ}` from + Naaijkens 2012 §1.3 line 211, Verch 2025 §1.2 axiom (i), Bratteli–Robinson Vol.2 §6.2. + Bundled as a unital `*`-algebra homomorphism so that `map_one`, `map_mul`, `map_star` + are available via the `StarAlgHom` API. Entry-wise: + `(includeAlgebra h X) s s' = X (combineIdx⁻¹ s).1 (combineIdx⁻¹ s').1` when the + complementary indices match, else `0`. -/ +noncomputable def includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : + L.localAlgebra Λ →⋆ₐ[ℂ] L.localAlgebra Λ_total where + toFun := L.includeAlgebraFun h + map_zero' := L.includeAlgebraFun_zero h + map_add' := L.includeAlgebraFun_add h + map_one' := L.includeAlgebraFun_one h + map_mul' := L.includeAlgebraFun_mul h + commutes' := L.includeAlgebraFun_algebraMap h + map_star' := L.includeAlgebraFun_star h + +/-- Entry-wise unfolding of `includeAlgebra h X`: at indices `(s, s')` of the larger + region, the embedded matrix equals `X` on the diagonal (in the complementary index) + and zero off-diagonal. -/ +@[simp] lemma includeAlgebra_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X : L.localAlgebra Λ) (s s' : L.regionIdx Λ_total) : + L.includeAlgebra h X s s' = + if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then + X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 + else 0 := rfl + +/-- Combined-index unfolding of the bundled `includeAlgebra` (the `StarAlgHom` coercion is + definitionally `includeAlgebraFun`, so this is `includeAlgebraFun_apply_combineIdx`). -/ +@[simp] lemma includeAlgebra_apply_combineIdx {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X : L.localAlgebra Λ) (a a' : L.regionIdx Λ) (b b' : L.regionIdx (Λ_total \ Λ)) : + L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) = + if b = b' then X a a' else 0 := + L.includeAlgebraFun_apply_combineIdx h X a a' b b' + +/-- **Injectivity of the isotony embedding** (the `↪` of `𝔄(Λ) ↪ 𝔄(Λ_total)`): under + the standing AQFT non-degeneracy assumption that the complementary region has a + non-empty index type, `includeAlgebra h` is injective as a map of `*`-algebras. -/ +theorem includeAlgebra_injective {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + [hne : Nonempty (L.regionIdx (Λ_total \ Λ))] : + Function.Injective (L.includeAlgebra h) := by + rw [injective_iff_map_eq_zero] + intro X hX + ext a a' + obtain ⟨b⟩ := hne + have heq : L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = + 0 := by rw [hX]; rfl + have key : L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = + X a a' := by + change L.includeAlgebraFun h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = X a a' + rw [includeAlgebraFun_apply_combineIdx, if_pos rfl] + rw [key] at heq + simpa using heq + +/-! ### Functoriality (composition of the isotony net) + +The isotony embeddings compose: including `Λ₁ ↪ Λ₂ ↪ Λ₃` equals the direct inclusion +`Λ₁ ↪ Λ₃`. This upgrades `includeAlgebra` from a family of embeddings to a genuine functor +on the region poset — a directed system of `*`-algebras — matching the net structure of +Naaijkens 2012 §3.2 and Verch 2025 §1.2. -/ + +/-- The `Λ₁`-coordinate of a `Λ₃`-index is unchanged by routing through an intermediate + region `Λ₂`: restricting to `Λ₂` then to `Λ₁` equals restricting directly to `Λ₁`. + Holds definitionally by proof irrelevance of the `⊆` witnesses. -/ +private lemma combineIdx_symm_fst_trans {Λ₁ Λ₂ Λ₃ : Finset L.sites} + (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (s : L.regionIdx Λ₃) : + ((L.combineIdx h₁₂).symm ((L.combineIdx h₂₃).symm s).1).1 + = ((L.combineIdx (Finset.Subset.trans h₁₂ h₂₃)).symm s).1 := rfl + +/-- The complementary index of a `Λ₃`-index over `Λ₁` matches between `s` and `s'` iff it + matches both over `Λ₂` (the outer complement) and over `Λ₁` inside `Λ₂` (the inner + complement). This is the factorisation `Λ₃ \ Λ₁ = (Λ₃ \ Λ₂) ⊔ (Λ₂ \ Λ₁)` at the level + of region indices, and is the bookkeeping core of functoriality. -/ +private lemma combineIdx_symm_snd_trans_iff {Λ₁ Λ₂ Λ₃ : Finset L.sites} + (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (s s' : L.regionIdx Λ₃) : + (((L.combineIdx (Finset.Subset.trans h₁₂ h₂₃)).symm s).2 + = ((L.combineIdx (Finset.Subset.trans h₁₂ h₂₃)).symm s').2) + ↔ (((L.combineIdx h₂₃).symm s).2 = ((L.combineIdx h₂₃).symm s').2 + ∧ ((L.combineIdx h₁₂).symm ((L.combineIdx h₂₃).symm s).1).2 + = ((L.combineIdx h₁₂).symm ((L.combineIdx h₂₃).symm s').1).2) := by + constructor + · intro h + refine ⟨?_, ?_⟩ + · funext t + exact congrFun h ⟨t.val, Finset.mem_sdiff.mpr + ⟨(Finset.mem_sdiff.mp t.property).1, + fun hh => (Finset.mem_sdiff.mp t.property).2 (h₁₂ hh)⟩⟩ + · funext t + exact congrFun h ⟨t.val, Finset.mem_sdiff.mpr + ⟨h₂₃ (Finset.mem_sdiff.mp t.property).1, (Finset.mem_sdiff.mp t.property).2⟩⟩ + · rintro ⟨hA, hB⟩ + funext t + by_cases ht2 : t.val ∈ Λ₂ + · exact congrFun hB ⟨t.val, Finset.mem_sdiff.mpr ⟨ht2, (Finset.mem_sdiff.mp t.property).2⟩⟩ + · exact congrFun hA ⟨t.val, Finset.mem_sdiff.mpr ⟨(Finset.mem_sdiff.mp t.property).1, ht2⟩⟩ + +/-- Pointwise form of functoriality: including `X` from `Λ₁` into `Λ₃` directly equals first + including into `Λ₂`, then into `Λ₃`. -/ +theorem includeAlgebra_trans_apply {Λ₁ Λ₂ Λ₃ : Finset L.sites} + (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (X : L.localAlgebra Λ₁) : + L.includeAlgebra h₂₃ (L.includeAlgebra h₁₂ X) + = L.includeAlgebra (Finset.Subset.trans h₁₂ h₂₃) X := by + ext s s' + simp only [includeAlgebra_apply] + rw [combineIdx_symm_fst_trans, combineIdx_symm_fst_trans, ← ite_and] + simp only [L.combineIdx_symm_snd_trans_iff h₁₂ h₂₃ s s'] + +/-- **Functoriality of the isotony net**: the inclusions compose. For `Λ₁ ⊆ Λ₂ ⊆ Λ₃`, + `includeAlgebra` of the composite subset equals the composition of the two embeddings, + so the net is a directed system of `*`-algebras (Naaijkens 2012 §3.2). -/ +theorem includeAlgebra_trans {Λ₁ Λ₂ Λ₃ : Finset L.sites} + (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) : + (L.includeAlgebra h₂₃).comp (L.includeAlgebra h₁₂) + = L.includeAlgebra (Finset.Subset.trans h₁₂ h₂₃) := + StarAlgHom.ext fun X => by rw [StarAlgHom.comp_apply, includeAlgebra_trans_apply] + +/-- The identity inclusion `Λ ⊆ Λ` acts as the identity: `includeAlgebra (subset_refl Λ)` + is the identity `*`-algebra map. The complementary region `Λ \ Λ` is empty, so the + diagonal condition is vacuously satisfied. -/ +theorem includeAlgebra_refl_apply {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + L.includeAlgebra (subset_refl Λ) X = X := by + ext s s' + have hc : ((L.combineIdx (subset_refl Λ)).symm s).2 + = ((L.combineIdx (subset_refl Λ)).symm s').2 := by + funext t + exact absurd (Finset.mem_sdiff.mp t.property).1 (Finset.mem_sdiff.mp t.property).2 + rw [includeAlgebra_apply, if_pos hc] + rfl + +end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/Locality.lean b/QuantumSystem/Algebra/LocalNet/Locality.lean new file mode 100644 index 0000000..e46d305 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/Locality.lean @@ -0,0 +1,127 @@ +module + +public import QuantumSystem.Algebra.LocalNet.Isotony + +/-! +# Locality (Einstein causality) of the local net + +Observables localised in **disjoint** regions commute. For finite-dimensional spin systems this +is the concrete realisation of the AQFT locality axiom (Naaijkens 2012 §3.2: spacelike-separated +— here disjoint — regions commute; Verch 2025 §1.2). The proof reduces to the union region +`Λ₁ ∪ Λ₂`, where the two embeddings act on complementary tensor factors, and ultimately to +commutativity of the scalar matrix entries in `ℂ`. +-/ + +@[expose] public section + +namespace LocalNet + +variable (L : LocalNet) + +/-- The right-region embedding `𝔄(Λ₂) ↪ 𝔄(Λ₁ ∪ Λ₂)` evaluated at indices factored through + the *left* split `combineIdx (Λ₁ ⊆ Λ₁ ∪ Λ₂)`: since `Λ₁` and `Λ₂` are disjoint, the + complement `(Λ₁ ∪ Λ₂) \ Λ₁` is exactly `Λ₂`, so the value is `Y` on the complementary + coordinate, with the diagonal condition now living on the `Λ₁` coordinate. -/ +private lemma includeAlgebra_union_right_combineIdx_left + {Λ₁ Λ₂ : Finset L.sites} (hd : Disjoint Λ₁ Λ₂) (Y : L.localAlgebra Λ₂) + (a a' : L.regionIdx Λ₁) (b b' : L.regionIdx ((Λ₁ ∪ Λ₂) \ Λ₁)) : + L.includeAlgebra Finset.subset_union_right Y + (L.combineIdx Finset.subset_union_left (a, b)) + (L.combineIdx Finset.subset_union_left (a', b')) + = if a = a' then + Y (L.regionIdxCongr (Finset.union_sdiff_cancel_left hd) b) + (L.regionIdxCongr (Finset.union_sdiff_cancel_left hd) b') else 0 := by + have hcompl : (Λ₁ ∪ Λ₂) \ Λ₁ = Λ₂ := Finset.union_sdiff_cancel_left hd + -- The `Λ₂`-coordinate (first projection under `combineIdx Λ₂⊆U`) of a left-combined index + -- is the complement coordinate, transported along `hcompl`. + have hdR : ∀ (c : L.regionIdx Λ₁) (d : L.regionIdx ((Λ₁ ∪ Λ₂) \ Λ₁)), + ((L.combineIdx Finset.subset_union_right).symm + (L.combineIdx Finset.subset_union_left (c, d))).1 + = L.regionIdxCongr hcompl d := by + intro c d + funext w + obtain ⟨wv, wp⟩ := w + have hw1 : wv ∉ Λ₁ := fun hh => (Finset.disjoint_left.mp hd hh) wp + change L.combineIdx Finset.subset_union_left (c, d) + ⟨wv, Finset.subset_union_right wp⟩ = _ + rw [combineIdx_apply_not_mem Finset.subset_union_left c d ⟨wv, _⟩ hw1, + L.regionIdxCongr_apply hcompl d + (Finset.mem_sdiff.mpr ⟨Finset.subset_union_right wp, hw1⟩) wp] + -- The `(U\Λ₂)`-coordinate (second projection under `combineIdx Λ₂⊆U`) only sees `Λ₁`, + -- transported along `(Λ₁ ∪ Λ₂) \ Λ₂ = Λ₁`. + have hcR : ∀ (c : L.regionIdx Λ₁) (d : L.regionIdx ((Λ₁ ∪ Λ₂) \ Λ₁)), + ((L.combineIdx Finset.subset_union_right).symm + (L.combineIdx Finset.subset_union_left (c, d))).2 + = L.regionIdxCongr (Finset.union_sdiff_cancel_right hd).symm c := by + intro c d + funext w + obtain ⟨wv, wp⟩ := w + have hwU : wv ∈ Λ₁ ∪ Λ₂ := (Finset.mem_sdiff.mp wp).1 + have hw1 : wv ∈ Λ₁ := by + rcases Finset.mem_union.mp hwU with h | h + · exact h + · exact absurd h (Finset.mem_sdiff.mp wp).2 + change L.combineIdx Finset.subset_union_left (c, d) ⟨wv, hwU⟩ = _ + rw [combineIdx_apply_mem Finset.subset_union_left c d ⟨wv, hwU⟩ hw1, + L.regionIdxCongr_apply (Finset.union_sdiff_cancel_right hd).symm c hw1 wp] + have hcond : (((L.combineIdx Finset.subset_union_right).symm + (L.combineIdx Finset.subset_union_left (a, b))).2 + = ((L.combineIdx Finset.subset_union_right).symm + (L.combineIdx Finset.subset_union_left (a', b'))).2) ↔ a = a' := by + rw [hcR a b, hcR a' b'] + exact (L.regionIdxCongr (Finset.union_sdiff_cancel_right hd).symm).apply_eq_iff_eq + rw [includeAlgebra_apply, hdR a b, hdR a' b'] + simp only [hcond] + +/-- **Bipartite locality**: in the union region `Λ₁ ∪ Λ₂` of two disjoint regions, a + `Λ₁`-observable and a `Λ₂`-observable commute. The two embeddings act on complementary + tensor factors, so the matrix entries collapse to commuting scalar products in `ℂ`. -/ +private lemma includeAlgebra_commute_union {Λ₁ Λ₂ : Finset L.sites} (hd : Disjoint Λ₁ Λ₂) + (X : L.localAlgebra Λ₁) (Y : L.localAlgebra Λ₂) : + Commute (L.includeAlgebra Finset.subset_union_left X) + (L.includeAlgebra Finset.subset_union_right Y) := by + suffices h : L.includeAlgebra Finset.subset_union_left X * + L.includeAlgebra Finset.subset_union_right Y = + L.includeAlgebra Finset.subset_union_right Y * + L.includeAlgebra Finset.subset_union_left X from h + ext s s' + obtain ⟨⟨a, b⟩, rfl⟩ := (L.combineIdx Finset.subset_union_left).surjective s + obtain ⟨⟨a', b'⟩, rfl⟩ := (L.combineIdx Finset.subset_union_left).surjective s' + rw [Matrix.mul_apply, Matrix.mul_apply, + ← (L.combineIdx Finset.subset_union_left).sum_comp + (fun t => L.includeAlgebra Finset.subset_union_left X + (L.combineIdx Finset.subset_union_left (a, b)) t * + L.includeAlgebra Finset.subset_union_right Y t + (L.combineIdx Finset.subset_union_left (a', b'))), + ← (L.combineIdx Finset.subset_union_left).sum_comp + (fun t => L.includeAlgebra Finset.subset_union_right Y + (L.combineIdx Finset.subset_union_left (a, b)) t * + L.includeAlgebra Finset.subset_union_left X t + (L.combineIdx Finset.subset_union_left (a', b'))), + Fintype.sum_prod_type, Fintype.sum_prod_type] + simp only [includeAlgebra_apply_combineIdx, + L.includeAlgebra_union_right_combineIdx_left hd, + ite_mul, mul_ite, zero_mul, mul_zero, Finset.sum_ite_irrel, Finset.sum_const_zero, + Finset.sum_ite_eq, Finset.sum_ite_eq', Finset.mem_univ, if_true] + ring + +/-- **Locality / Einstein causality (spin systems)**: observables localised in disjoint + regions commute inside any common total region. The finite-dimensional concrete form of + the AQFT locality axiom (Naaijkens 2012 §3.2; Verch 2025 §1.2). Reduces to the bipartite + case via functoriality (`includeAlgebra_trans_apply`) and the ring-hom property of the + embedding into the union. -/ +theorem includeAlgebra_commute_of_disjoint {Λ₁ Λ₂ Λ_total : Finset L.sites} + (h₁ : Λ₁ ⊆ Λ_total) (h₂ : Λ₂ ⊆ Λ_total) (hd : Disjoint Λ₁ Λ₂) + (X : L.localAlgebra Λ₁) (Y : L.localAlgebra Λ₂) : + Commute (L.includeAlgebra h₁ X) (L.includeAlgebra h₂ Y) := by + have hU : Λ₁ ∪ Λ₂ ⊆ Λ_total := Finset.union_subset h₁ h₂ + have e1 : L.includeAlgebra h₁ X + = L.includeAlgebra hU (L.includeAlgebra Finset.subset_union_left X) := by + rw [includeAlgebra_trans_apply] + have e2 : L.includeAlgebra h₂ Y + = L.includeAlgebra hU (L.includeAlgebra Finset.subset_union_right Y) := by + rw [includeAlgebra_trans_apply] + rw [e1, e2] + exact (L.includeAlgebra_commute_union hd X Y).map (L.includeAlgebra hU) + +end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean new file mode 100644 index 0000000..e755173 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean @@ -0,0 +1,171 @@ +module + +public import QuantumSystem.Algebra.LocalNet.Locality +public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar +public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit +public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion +public import Mathlib.Analysis.CStarAlgebra.Matrix + +/-! +# Quasi-local algebra of the local net + +For a `LocalNet` on a (possibly infinite) lattice of sites, the **algebra of local observables** +is the algebraic inductive limit of the directed system of finite-region matrix algebras +`{𝔄(Λ) : Λ : Finset sites}` with the isotony embeddings `includeAlgebra (h : Λ ⊆ Λ')` as +connecting maps, and the **quasi-local C⋆-algebra** is its norm completion (Naaijkens 2012 §1.3, +Bratteli–Robinson Vol.2 §6.2). + +* The directed system is genuine: the connecting maps compose (`includeAlgebra_trans_apply`) + and the identity inclusion is the identity (`includeAlgebra_refl_apply`). +* `quasiLocalAlgebra` (the algebraic inductive limit) is a `ℂ`-`*`-algebra with cocone `ιLocal`, + exhaustion `exists_ιLocal`, and locality `ιLocal_commute_of_disjoint`. +* In `section CStar` (assuming each site has a non-empty local index type, so the embeddings are + injective hence isometric), the C⋆-norm makes it a pre-C⋆-algebra and `quasiLocalCStarAlgebra` + (its completion) is a `CStarAlgebra`, with dense embeddings `ιLocalCStar`. +-/ + +@[expose] public section + +namespace LocalNet + +variable (L : LocalNet) + +/-- The local net forms a directed system of `*`-algebras: the isotony embeddings compose + and the identity inclusion is the identity (Phase 1 functoriality). -/ +instance directedSystem : + DirectedSystem (fun Λ : Finset L.sites => L.localAlgebra Λ) + (fun _ _ h => ⇑(L.includeAlgebra h)) where + map_self _ x := L.includeAlgebra_refl_apply x + map_map _ _ _ hij hjk x := L.includeAlgebra_trans_apply hij hjk x + +/-- The **algebra of local observables**: the algebraic inductive limit of the finite-region + matrix algebras along the isotony embeddings. Its C*-completion is the quasi-local + algebra of AQFT. -/ +noncomputable abbrev quasiLocalAlgebra : Type _ := + DirectLimit (fun Λ : Finset L.sites => L.localAlgebra Λ) + (fun _ _ h => L.includeAlgebra h) + +/-- Componentwise behaviour of the involution (from the general `DirectLimit` `*`-ring + instance in `ForMathlib`). The quasi-local algebra is a `*`-algebra over `ℂ`: its + `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general + direct-limit constructions, since `localAlgebra` is a `ℂ`-`*`-algebra and `includeAlgebra` + is a `*`-algebra homomorphism. -/ +@[simp] theorem star_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + star (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl + +/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the quasi-local algebra, + as a unital ring homomorphism (the cocone of the inductive limit). -/ +noncomputable def ιLocal (Λ : Finset L.sites) : + L.localAlgebra Λ →+* L.quasiLocalAlgebra := + DirectLimit.Ring.of (fun Λ : Finset L.sites => L.localAlgebra Λ) + (fun _ _ h => L.includeAlgebra h) Λ + +/-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the + larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ +@[simp] theorem ιLocal_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') (X : L.localAlgebra Λ) : + L.ιLocal Λ' (L.includeAlgebra h X) = L.ιLocal Λ X := + DirectLimit.Ring.of_f (G := fun Λ : Finset L.sites => L.localAlgebra Λ) + (f := fun _ _ h => L.includeAlgebra h) h X + +/-- The cocone is a `*`-homomorphism: it intertwines the local adjoint with the quasi-local + adjoint. -/ +@[simp] theorem ιLocal_star {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + L.ιLocal Λ (star X) = star (L.ιLocal Λ X) := + (star_mk (L := L) X).symm + +/-- **Exhaustion**: every element of the quasi-local algebra is the image of a local + observable from some finite region — the union of the local algebras is the whole limit. -/ +theorem exists_ιLocal (z : L.quasiLocalAlgebra) : ∃ (Λ : Finset L.sites) (X : L.localAlgebra Λ), + z = L.ιLocal Λ X := by + induction z using DirectLimit.induction with + | _ Λ X => exact ⟨Λ, X, rfl⟩ + +/-- **Locality in the quasi-local algebra**: observables localised in disjoint regions commute + inside `𝔄_loc`. Lifts the bipartite locality (`includeAlgebra_commute_union`) along the + ring-hom cocone. -/ +theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset L.sites} (hd : Disjoint Λ₁ Λ₂) + (X : L.localAlgebra Λ₁) (Y : L.localAlgebra Λ₂) : + Commute (L.ιLocal Λ₁ X) (L.ιLocal Λ₂ Y) := by + have h1 : L.ιLocal Λ₁ X + = L.ιLocal (Λ₁ ∪ Λ₂) (L.includeAlgebra Finset.subset_union_left X) := + (L.ιLocal_includeAlgebra Finset.subset_union_left X).symm + have h2 : L.ιLocal Λ₂ Y + = L.ιLocal (Λ₁ ∪ Λ₂) (L.includeAlgebra Finset.subset_union_right Y) := + (L.ιLocal_includeAlgebra Finset.subset_union_right Y).symm + rw [h1, h2] + exact (L.includeAlgebra_commute_of_disjoint Finset.subset_union_left + Finset.subset_union_right hd X Y).map (L.ιLocal (Λ₁ ∪ Λ₂)) + +/-! ### Quasi-local C⋆-algebra + +Equipping the algebra of local observables with the C⋆-norm of the inductive limit (the isotony +embeddings are injective — using non-empty local dimensions — hence isometric) and completing +yields the quasi-local C⋆-algebra. The general construction lives in `ForMathlib` +(`DirectLimit.cstarNormedRing`, `UniformSpace.Completion.instCStarAlgebra`); here we supply the +net-specific inputs (matrix C⋆-algebras + injectivity). -/ + +section CStar + +open scoped Matrix.Norms.L2Operator + +variable [∀ s, Nonempty (L.localIdx s)] + +/-- Each finite-region matrix algebra is a (complex) C⋆-algebra under the `L2Operator` norm. + Stated for `localAlgebra` so the choice of the `L2Operator` norm does not leak to arbitrary + matrices. -/ +noncomputable instance instCStarAlgebraLocal (Λ : Finset L.sites) : + CStarAlgebra (L.localAlgebra Λ) where + +/-- The algebra of local observables is a normed ring under the C⋆-norm of the inductive limit. -/ +noncomputable instance : NormedRing (L.quasiLocalAlgebra) := + DirectLimit.cstarNormedRing (fun _ _ h => L.includeAlgebra_injective h) + +@[simp] theorem norm_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + ‖(⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra)‖ = ‖X‖ := rfl + +/-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ +noncomputable instance : NormedAlgebra ℂ (L.quasiLocalAlgebra) where + norm_smul_le c x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X + +/-- `star` is isometric on the algebra of local observables. -/ +instance : NormedStarGroup (L.quasiLocalAlgebra) where + norm_star_le x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le + +/-- The C⋆-identity holds on the algebra of local observables. -/ +instance : CStarRing (L.quasiLocalAlgebra) where + norm_mul_self_le x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] + exact CStarRing.norm_mul_self_le X + +/-- The **quasi-local C⋆-algebra** of the net: the completion of the algebra of local + observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, + Bratteli–Robinson Vol.2 §6.2), obtained as the C⋆-inductive limit of the finite-region + matrix algebras. -/ +noncomputable abbrev quasiLocalCStarAlgebra : Type _ := + UniformSpace.Completion L.quasiLocalAlgebra + +noncomputable example : CStarAlgebra L.quasiLocalCStarAlgebra := inferInstance + +/-- The canonical embedding `𝔄(Λ) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, + as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ +noncomputable def ιLocalCStar (Λ : Finset L.sites) : + L.localAlgebra Λ → L.quasiLocalCStarAlgebra := + (↑) ∘ L.ιLocal Λ + +/-- The local algebras are dense in the quasi-local C⋆-algebra: the union of the images of the + `ιLocalCStar Λ` is dense (every element is a norm-limit of local observables). -/ +theorem denseRange_iUnion_ιLocalCStar : + Dense (⋃ Λ : Finset L.sites, Set.range (L.ιLocalCStar Λ)) := by + refine UniformSpace.Completion.denseRange_coe.mono ?_ + rintro _ ⟨z, rfl⟩ + obtain ⟨Λ, X, rfl⟩ := L.exists_ιLocal z + exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ + +end CStar + +end LocalNet diff --git a/QuantumSystem/Analysis/Entropy/Regularize.lean b/QuantumSystem/Analysis/Entropy/Regularize.lean index b9f4760..c8bd037 100644 --- a/QuantumSystem/Analysis/Entropy/Regularize.lean +++ b/QuantumSystem/Analysis/Entropy/Regularize.lean @@ -14,7 +14,7 @@ The structural definitions (`maximallyMixed`, `regularize`, `regularize_eq_cfc`, This file specialises that infrastructure to a `LocalNet`. It proves compatibility of regularization with restriction (partial trace), which is the key fact behind extending PosDef-only theorems to PosSemidef. The cardinality factorisation for region indices now -lives next to `LocalNet.combineIdx` in `LocalNet.lean`. +lives next to `LocalNet.combineIdx` in `LocalNet/Basic.lean`. -/ @[expose] public section diff --git a/QuantumSystem/Analysis/Matrix/PartialTrace.lean b/QuantumSystem/Analysis/Matrix/PartialTrace.lean index de3f0dc..0498a0b 100644 --- a/QuantumSystem/Analysis/Matrix/PartialTrace.lean +++ b/QuantumSystem/Analysis/Matrix/PartialTrace.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet +public import QuantumSystem.Algebra.LocalNet.Isotony /-! # Partial trace as restriction (matrix-level) @@ -314,15 +314,6 @@ theorem restrict_restrict {Λ' Λ Λ_total : Finset L.sites} The matrix-level dual of the restriction: tracing `ρ` against an embedded observable `includeAlgebra h X` equals tracing the marginal `restrict h ρ` against `X`. -/ -/-- Entry-wise behaviour of `includeAlgebra` at combined indices: the off-diagonal - components in the complementary region vanish, leaving `X a a'` on the diagonal. -/ -@[simp] private lemma includeAlgebra_apply_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) - (a a' : L.regionIdx Λ) (b b' : L.regionIdx (Λ_total \ Λ)) : - L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) = - if b = b' then X a a' else 0 := by - simp [LocalNet.includeAlgebra_apply, Equiv.symm_apply_apply] - /-- **Heisenberg-picture trace identity**: `Tr(ρ · includeAlgebra h X) = Tr((restrict h ρ) · X)`. This is the AQFT-natural form of `trace_mul_kronecker_one`. -/ @@ -369,9 +360,9 @@ theorem trace_mul_includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_t L.includeAlgebra h X (L.combineIdx h (a', b')) (L.combineIdx h (a, b))) = ρ (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) * X a' a from by rw [Finset.sum_eq_single b] - · rw [includeAlgebra_apply_combineIdx]; simp + · rw [LocalNet.includeAlgebra_apply_combineIdx]; simp · intro b' _ hb' - rw [includeAlgebra_apply_combineIdx, if_neg hb'] + rw [LocalNet.includeAlgebra_apply_combineIdx, if_neg hb'] ring · simp] -- Combine: LHS = ∑ a, ∑ b, ∑ a', ... = ∑ a, ∑ a', ∑ b, ... = RHS diff --git a/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean b/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean new file mode 100644 index 0000000..569bc7d --- /dev/null +++ b/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean @@ -0,0 +1,94 @@ +module + +public import Mathlib.Algebra.Algebra.Basic +public import Mathlib.Algebra.Colimit.DirectLimit +public import Mathlib.Algebra.Star.Basic + +/-! +# Star and algebra structure on a direct limit + +The direct limit of a directed system of `*`-rings (resp. `𝕜`-algebras) with `*`-homomorphism +(resp. algebra-homomorphism) connecting maps is again a `*`-ring (resp. `𝕜`-algebra), with the +operations acting componentwise. Mathlib already provides the `Ring`/`Module` structure on +`DirectLimit`; this file adds the `Star`, `StarRing`, `Algebra` and `StarModule` instances. + +These are general facts about direct limits and are candidates for upstreaming to Mathlib. +-/ + +@[expose] public section + +namespace DirectLimit + +variable {ι : Type*} [Preorder ι] {F : ι → Type*} +variable {T : ∀ ⦃i j : ι⦄, i ≤ j → Type*} {f : ∀ _ _ h, T h} +variable [∀ i j (h : i ≤ j), FunLike (T h) (F i) (F j)] [DirectedSystem F (f · · ·)] +variable [IsDirectedOrder ι] + +section Star + +variable [∀ i, Star (F i)] [∀ i j (h : i ≤ j), StarHomClass (T h) (F i) (F j)] + +/-- Componentwise involution on a direct limit of `*`-magmas. -/ +noncomputable instance : Star (DirectLimit F f) where + star := DirectLimit.map (F₁ := F) (F₂ := F) f f (fun _ => star) + (fun _ _ h x => map_star (f _ _ h) x) + +@[simp] theorem star_mk (i) (x : F i) : + star (⟦⟨i, x⟩⟧ : DirectLimit F f) = ⟦⟨i, star x⟩⟧ := rfl + +end Star + +section StarRing + +variable [Nonempty ι] [∀ i, Ring (F i)] [∀ i, StarRing (F i)] + [∀ i j (h : i ≤ j), RingHomClass (T h) (F i) (F j)] + [∀ i j (h : i ≤ j), StarHomClass (T h) (F i) (F j)] + +/-- The direct limit of a directed system of `*`-rings is a `*`-ring. -/ +noncomputable instance : StarRing (DirectLimit F f) where + star_involutive z := by + induction z using DirectLimit.induction with + | _ i x => simp only [star_mk, star_star] + star_mul a b := by + induction a, b using DirectLimit.induction₂ with + | _ i x y => simp only [DirectLimit.mul_def, star_mk, star_mul] + star_add a b := by + induction a, b using DirectLimit.induction₂ with + | _ i x y => simp only [DirectLimit.add_def, star_mk, star_add] + +end StarRing + +section Algebra + +variable {𝕜 : Type*} [Nonempty ι] [CommSemiring 𝕜] [∀ i, Semiring (F i)] [∀ i, Algebra 𝕜 (F i)] + [∀ i j (h : i ≤ j), RingHomClass (T h) (F i) (F j)] + [∀ i j (h : i ≤ j), LinearMapClass (T h) 𝕜 (F i) (F j)] + +/-- The direct limit of a directed system of `𝕜`-algebras is a `𝕜`-algebra. -/ +noncomputable instance : Algebra 𝕜 (DirectLimit F f) := + Algebra.ofModule + (fun _ a b => by + induction a, b using DirectLimit.induction₂ with + | _ i x y => simp only [DirectLimit.smul_def, DirectLimit.mul_def, smul_mul_assoc]) + (fun _ a b => by + induction a, b using DirectLimit.induction₂ with + | _ i x y => simp only [DirectLimit.smul_def, DirectLimit.mul_def, mul_smul_comm]) + +end Algebra + +section StarModule + +variable {𝕜 : Type*} [Nonempty ι] [CommSemiring 𝕜] [Star 𝕜] [∀ i, Semiring (F i)] + [∀ i, Algebra 𝕜 (F i)] [∀ i, Star (F i)] [∀ i, StarModule 𝕜 (F i)] + [∀ i j (h : i ≤ j), LinearMapClass (T h) 𝕜 (F i) (F j)] + [∀ i j (h : i ≤ j), StarHomClass (T h) (F i) (F j)] + +/-- The involution on a direct limit of `𝕜`-`*`-algebras is conjugate-linear. -/ +instance : StarModule 𝕜 (DirectLimit F f) where + star_smul c z := by + induction z using DirectLimit.induction with + | _ i x => simp only [DirectLimit.smul_def, star_mk, star_smul] + +end StarModule + +end DirectLimit diff --git a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean new file mode 100644 index 0000000..a348531 --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean @@ -0,0 +1,73 @@ +module + +public import Mathlib.Algebra.Colimit.DirectLimit +public import Mathlib.Analysis.CStarAlgebra.Hom +public import Mathlib.Analysis.Normed.Unbundled.RingSeminorm + +/-! +# The C⋆-inductive limit of a directed system of C⋆-algebras + +For a directed system of (complex) C⋆-algebras whose connecting maps are *injective* unital +`*`-homomorphisms, the connecting maps are isometric (`NonUnitalStarAlgHom.norm_map`), so the +algebraic direct limit carries a well-defined C⋆-norm `‖⟦⟨i, x⟩⟧‖ = ‖x‖`. Its completion is the +**C⋆-inductive limit** (Bratteli–Robinson Vol.1 §2.6), a `CStarAlgebra`. + +This file provides the norm `cstarNorm`, the bundled `cstarRingNorm`, and the resulting +`NormedRing` structure (`cstarNormedRing`) on `DirectLimit F f`, all parametrised by injectivity +of the connecting maps. The `*`-algebra-over-`ℂ` structure is supplied by `DirectLimitStar`. + +These are general facts and are candidates for upstreaming to Mathlib. +-/ + +@[expose] public section + +namespace DirectLimit + +variable {ι : Type*} [Preorder ι] [IsDirectedOrder ι] [Nonempty ι] {F : ι → Type*} + {T : ∀ ⦃i j : ι⦄, i ≤ j → Type*} {f : ∀ _ _ h, T h} + [∀ i j (h : i ≤ j), FunLike (T h) (F i) (F j)] [DirectedSystem F (f · · ·)] + [∀ i, CStarAlgebra (F i)] [∀ i j (h : i ≤ j), AlgHomClass (T h) ℂ (F i) (F j)] + [∀ i j (h : i ≤ j), StarHomClass (T h) (F i) (F j)] + (hf : ∀ i j (h : i ≤ j), Function.Injective (f i j h)) + +/-- The C⋆-norm on the direct limit: `‖⟦⟨i, x⟩⟧‖ = ‖x‖`, well defined since the connecting maps — + being injective unital `*`-homomorphisms of C⋆-algebras — are isometric + (`NonUnitalStarAlgHom.norm_map`). -/ +noncomputable def cstarNorm : DirectLimit F f → ℝ := + DirectLimit.lift f (fun _ x => ‖x‖) + (fun i j h x => (NonUnitalStarAlgHom.norm_map (f i j h) (hf i j h) x).symm) + +omit [Nonempty ι] in +@[simp] theorem cstarNorm_mk (i) (x : F i) : + cstarNorm hf (⟦⟨i, x⟩⟧ : DirectLimit F f) = ‖x‖ := rfl + +/-- The bundled ring norm on the direct limit. -/ +noncomputable def cstarRingNorm : RingNorm (DirectLimit F f) where + toFun := cstarNorm hf + map_zero' := by + rw [show (0 : DirectLimit F f) = ⟦⟨Classical.arbitrary _, 0⟩⟧ from + DirectLimit.zero_def _, cstarNorm_mk, norm_zero] + add_le' a b := by + induction a, b using DirectLimit.induction₂ with + | _ i x y => rw [DirectLimit.add_def, cstarNorm_mk, cstarNorm_mk, cstarNorm_mk] + exact norm_add_le x y + neg' a := by + induction a using DirectLimit.induction with + | _ i x => rw [DirectLimit.neg_def, cstarNorm_mk, cstarNorm_mk, norm_neg] + mul_le' a b := by + induction a, b using DirectLimit.induction₂ with + | _ i x y => rw [DirectLimit.mul_def, cstarNorm_mk, cstarNorm_mk, cstarNorm_mk] + exact norm_mul_le x y + eq_zero_of_map_eq_zero' a := by + induction a using DirectLimit.induction with + | _ i x => + intro hx + rw [cstarNorm_mk, norm_eq_zero] at hx + rw [hx] + exact (DirectLimit.zero_def i).symm + +/-- The `NormedRing` structure on the direct limit induced by the C⋆-norm. -/ +@[reducible] noncomputable def cstarNormedRing : NormedRing (DirectLimit F f) := + (cstarRingNorm hf).toNormedRing + +end DirectLimit diff --git a/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean b/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean new file mode 100644 index 0000000..d7fd0b2 --- /dev/null +++ b/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean @@ -0,0 +1,117 @@ +module + +public import Mathlib.Analysis.CStarAlgebra.Classes +public import Mathlib.Analysis.Normed.Module.Completion + +/-! +# C⋆-algebra structure on a completion + +The completion of a normed `*`-algebra is again a normed `*`-algebra, and the completion of a +(possibly incomplete) C⋆-normed algebra is a `CStarAlgebra`. Mathlib already provides the +`NormedRing`, `NormedAlgebra` and `CompleteSpace` instances on `UniformSpace.Completion`; this +file adds the missing `Star`, `StarRing`, `NormedStarGroup`, `CStarRing` and `StarModule` +instances, obtained by extending the operations on the dense image by continuity, and assembles +them into a `CStarAlgebra` instance. + +These are general facts about completions and are candidates for upstreaming to Mathlib. +-/ + +@[expose] public section + +namespace UniformSpace.Completion + +variable {A : Type*} + +section StarRing + +variable [NormedRing A] [StarRing A] [NormedStarGroup A] + +theorem uniformContinuous_star : UniformContinuous (star : A → A) := by + have h : Isometry (star : A → A) := + AddMonoidHomClass.isometry_of_norm (starAddEquiv (R := A)) fun x => norm_star x + exact h.uniformContinuous + +/-- Involution on a completion, the continuous extension of the involution on the dense image. -/ +noncomputable instance : Star (Completion A) := ⟨Completion.map star⟩ + +@[simp] theorem star_coe (a : A) : star (↑a : Completion A) = (↑(star a) : Completion A) := + map_coe uniformContinuous_star a + +instance : ContinuousStar (Completion A) := ⟨continuous_map⟩ + +noncomputable instance : InvolutiveStar (Completion A) where + star_involutive a := by + refine induction_on a (isClosed_eq (continuous_id.star.star) continuous_id) ?_ + intro a + rw [star_coe, star_coe, star_star] + +noncomputable instance : StarMul (Completion A) where + star_mul a b := by + refine induction_on₂ a b + (isClosed_eq continuous_mul.star ((continuous_snd.star).mul (continuous_fst.star))) ?_ + intro a b + rw [← coe_mul, star_coe, star_coe, star_coe, ← coe_mul, star_mul] + +noncomputable instance : StarRing (Completion A) where + star_add a b := by + refine induction_on₂ a b + (isClosed_eq continuous_add.star ((continuous_fst.star).add (continuous_snd.star))) ?_ + intro a b + rw [← coe_add, star_coe, star_coe, star_coe, ← coe_add, star_add] + +instance : NormedStarGroup (Completion A) where + norm_star_le a := by + refine induction_on a (isClosed_le continuous_id.star.norm continuous_norm) ?_ + intro a + rw [star_coe, norm_coe, norm_coe] + exact (norm_star a).le + +end StarRing + +section CStarRing + +variable [NormedRing A] [StarRing A] [NormedStarGroup A] [CStarRing A] + +instance : CStarRing (Completion A) where + norm_mul_self_le a := by + refine induction_on a + (isClosed_le (continuous_norm.mul continuous_norm) (continuous_id.star.mul continuous_id).norm) + ?_ + intro a + rw [star_coe, ← coe_mul, norm_coe, norm_coe] + exact CStarRing.norm_mul_self_le a + +end CStarRing + +section StarModule + +variable {𝕜 : Type*} [NormedField 𝕜] [StarRing 𝕜] [NormedRing A] [StarRing A] + [NormedStarGroup A] [NormedAlgebra 𝕜 A] [StarModule 𝕜 A] + +noncomputable instance : StarModule 𝕜 (Completion A) where + star_smul c a := by + refine induction_on a + (isClosed_eq (continuous_const_smul c).star (continuous_id.star.const_smul (star c))) ?_ + intro a + rw [← coe_smul, star_coe, star_coe, ← coe_smul, star_smul] + +end StarModule + +/-- The completion of a normed algebra over a normed field is a normed algebra. (Mathlib only + provides this for commutative base rings; here `A` may be non-commutative.) -/ +noncomputable instance instNormedAlgebraOfNormedRing {𝕜 : Type*} [NormedField 𝕜] [NormedRing A] + [NormedAlgebra 𝕜 A] : NormedAlgebra 𝕜 (Completion A) := + { Completion.algebra A 𝕜 with + norm_smul_le := fun c x => by + refine induction_on x (isClosed_le ?_ ?_) ?_ + · exact (continuous_const_smul c).norm + · exact continuous_const.mul continuous_norm + · intro a + rw [← coe_smul, norm_coe, norm_coe] + exact norm_smul_le c a } + +/-- The completion of a (possibly incomplete) C⋆-normed `ℂ`-algebra is a `CStarAlgebra`. -/ +noncomputable instance instCStarAlgebra [NormedRing A] [StarRing A] [NormedStarGroup A] + [CStarRing A] [NormedAlgebra ℂ A] [StarModule ℂ A] : CStarAlgebra (Completion A) where + +end UniformSpace.Completion diff --git a/QuantumSystem/Notation.lean b/QuantumSystem/Notation.lean index 5d8d090..776a3bb 100644 --- a/QuantumSystem/Notation.lean +++ b/QuantumSystem/Notation.lean @@ -17,7 +17,7 @@ Notations and abbreviations for quantum information theory. | `S(ρ)` | `Matrix.vonNeumannEntropy ρ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/VonNeumannEntropy.lean` | | `D(ρ ∥ σ)` | `Matrix.relativeEntropy ρ σ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/RelativeEntropy.lean` | | `⟪X, Y⟫_HS` | `Matrix.hsInnerProduct X Y` | `open scoped Matrix.QuantumInfo` | `Analysis/Matrix/LiebConcavity.lean` | -| `ρ ↾ Λ` | `DensityMatrix.restrict (by …) ρ` | `open scoped LocalNet.QuantumInfo` | `Algebra/LocalNet.lean` | +| `ρ ↾ Λ` | `DensityMatrix.restrict (by …) ρ` | `open scoped LocalNet.QuantumInfo` | `Algebra/LocalNet/Basic.lean` | `ρ ↾ Λ` is the AQFT-style **restriction of a density matrix to a sub-region** — equivalently, the partial trace over the complementary region. From d4ea1737683c630c279718be971d5c6779fc35a3 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 06:03:35 +0000 Subject: [PATCH 003/113] feat(LocalNet): formalize the operator tensor decomposition of the net MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promote the index bijection `combineIdx` to a genuine tensor factorisation of operators on Hilbert spaces. Add to ForMathlib the Euclidean-space tensor isometry (`EuclideanSpace.tensorEquiv`), the `End ⊗ End ≃ End(⊗)` algebra equivalence (`endTensorEndAlgEquiv`), and an explicit-subspace partial trace `LinearMap.partialTrace (e : ℋ ≃ₗ A ⊗ B)` with its ampliation `LinearMap.ampliate` and module ("pull-out") law `Tr_B((A⊗1)·ρ) = A·Tr_B(ρ)`. On the net, identify the local matrix algebra with operators on the region Hilbert space (`opEquiv`), build the operator tensor decomposition `tensorEquiv`, and prove that isotony is the ampliation (`opEquiv_includeAlgebra`) and the marginal `restrict` is the partial trace tracing out the complementary region (`opEquiv_restrict`), with the traced-out subspace named by `regionBipartition`. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 3 + QuantumSystem/Algebra/LocalNet/Basic.lean | 4 +- QuantumSystem/Algebra/LocalNet/Isotony.lean | 3 + .../Algebra/LocalNet/TensorDecomposition.lean | 118 ++++++++++++++++ .../Analysis/Matrix/PartialTraceOperator.lean | 92 ++++++++++++ .../InnerProductSpace/TensorProduct.lean | 72 ++++++++++ .../ForMathlib/LinearAlgebra/Trace.lean | 131 ++++++++++++++++++ 7 files changed, 422 insertions(+), 1 deletion(-) create mode 100644 QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean create mode 100644 QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean create mode 100644 QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 039c6a5..78272c2 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -15,6 +15,7 @@ public import QuantumSystem.Algebra.LocalNet.Covariance public import QuantumSystem.Algebra.LocalNet.Isotony public import QuantumSystem.Algebra.LocalNet.Locality public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal @@ -28,6 +29,7 @@ public import QuantumSystem.Analysis.Matrix.HermitianFunctionalCalculus public import QuantumSystem.Analysis.Matrix.LiebConcavity public import QuantumSystem.Analysis.Matrix.Order public import QuantumSystem.Analysis.Matrix.PartialTrace +public import QuantumSystem.Analysis.Matrix.PartialTraceOperator public import QuantumSystem.Analysis.Matrix.Pinching public import QuantumSystem.Analysis.Matrix.PosDef public import QuantumSystem.Channel @@ -56,6 +58,7 @@ public import QuantumSystem.ForMathlib.Analysis.SpecialFunctions.Pow.Real public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.StarAlgEquiv public import QuantumSystem.ForMathlib.LinearAlgebra.Span.Def +public import QuantumSystem.ForMathlib.LinearAlgebra.Trace public import QuantumSystem.ForMathlib.RingTheory.RootsOfUnity.Complex public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion public import QuantumSystem.ForMathlib.Topology.DenseLinear diff --git a/QuantumSystem/Algebra/LocalNet/Basic.lean b/QuantumSystem/Algebra/LocalNet/Basic.lean index 7cdec7a..f37eb48 100644 --- a/QuantumSystem/Algebra/LocalNet/Basic.lean +++ b/QuantumSystem/Algebra/LocalNet/Basic.lean @@ -78,7 +78,9 @@ abbrev densityMatrix (Λ : Finset L.sites) : Type _ := /-- For `Λ ⊆ Λ_total`, the index type of the larger region splits as a product: `regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ regionIdx Λ_total`. This realises the tensor - factorisation `ℋ_Λ_total = ℋ_Λ ⊗ ℋ_{Λ_total \ Λ}` underlying isotony and partial trace. -/ + factorisation `ℋ_Λ_total = ℋ_Λ ⊗ ℋ_{Λ_total \ Λ}` underlying isotony and partial trace. + The factorisation is made formal at the operator level by `LocalNet.tensorEquiv` + (`TensorDecomposition`), an algebra isomorphism of the corresponding operator algebras. -/ def combineIdx {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : (L.regionIdx Λ × L.regionIdx (Λ_total \ Λ)) ≃ L.regionIdx Λ_total where toFun ab s := diff --git a/QuantumSystem/Algebra/LocalNet/Isotony.lean b/QuantumSystem/Algebra/LocalNet/Isotony.lean index 0437c96..8ddb87d 100644 --- a/QuantumSystem/Algebra/LocalNet/Isotony.lean +++ b/QuantumSystem/Algebra/LocalNet/Isotony.lean @@ -155,6 +155,9 @@ lemma includeAlgebraFun_algebraMap {Λ Λ_total : Finset L.sites} /-- **Isotony embedding** `𝔄(Λ) ↪ 𝔄(Λ_total)`: tensor a local matrix with the identity on the complementary region. Realises the inclusion `A ↦ A ⊗ I_{Λ_total \ Λ}` from Naaijkens 2012 §1.3 line 211, Verch 2025 §1.2 axiom (i), Bratteli–Robinson Vol.2 §6.2. + That this embedding is literally `A ↦ A ⊗ 1` of operators on Hilbert spaces is proved in + `LocalNet.opEquiv_includeAlgebra` (`TensorDecomposition`); the dual marginal is the partial + trace `LocalNet.opEquiv_restrict` (`PartialTraceOperator`). Bundled as a unital `*`-algebra homomorphism so that `map_one`, `map_mul`, `map_star` are available via the `StarAlgHom` API. Entry-wise: `(includeAlgebra h X) s s' = X (combineIdx⁻¹ s).1 (combineIdx⁻¹ s').1` when the diff --git a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean new file mode 100644 index 0000000..5bd1282 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean @@ -0,0 +1,118 @@ +module + +public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct +public import QuantumSystem.ForMathlib.LinearAlgebra.Trace + +/-! +# Operator-level tensor decomposition of the local net + +The combinatorial index bijection `combineIdx h : regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ +regionIdx Λ_total` is promoted here to a genuine **tensor factorisation of operators on Hilbert +spaces**, rather than a matrix Kronecker product. + +For each finite region we take the Hilbert space `ℋ Λ := EuclideanSpace ℂ (regionIdx Λ)` and +identify the local matrix algebra `𝔄(Λ) = localAlgebra Λ` with the operator algebra +`End ℂ (ℋ Λ)` via `opEquiv`. The index bijection then induces a Hilbert-space tensor isometry +`ℋ Λ ⊗ ℋ (Λ_total \ Λ) ≃ ℋ Λ_total`, conjugation by which assembles, with +`endTensorEndAlgEquiv`, into an algebra isomorphism + + `tensorEquiv h : End ℂ (ℋ Λ) ⊗ End ℂ (ℋ (Λ_total \ Λ)) ≃ₐ End ℂ (ℋ Λ_total)`. + +The isotony embedding is then literally "tensoring with the identity on the complement" +(`opEquiv_includeAlgebra`): `includeAlgebra h X` corresponds to `(op X) ⊗ 1`. +-/ + +@[expose] public section + +open WithLp +open scoped TensorProduct Matrix + +namespace LocalNet + +variable (L : LocalNet) + +/-- The Hilbert space of a region: the Euclidean space on its index type. -/ +abbrev ℋ (Λ : Finset L.sites) : Type _ := EuclideanSpace ℂ (L.regionIdx Λ) + +/-- The local matrix algebra `𝔄(Λ)`, identified with the algebra of operators on the region +Hilbert space `ℋ Λ` (matrices acting by multiplication on `EuclideanSpace`). -/ +noncomputable def opEquiv (Λ : Finset L.sites) : + L.localAlgebra Λ ≃ₐ[ℂ] Module.End ℂ (L.ℋ Λ) := + Matrix.toLinAlgEquiv'.trans + ((EuclideanSpace.equiv (L.regionIdx Λ) ℂ).symm.toLinearEquiv.conjAlgEquiv ℂ) + +@[simp] +lemma ofLp_opEquiv (Λ : Finset L.sites) (X : L.localAlgebra Λ) (v : L.ℋ Λ) : + ofLp (L.opEquiv Λ X v) = X *ᵥ ofLp v := + rfl + +/-- The **operator tensor decomposition** induced by the index bijection `combineIdx h`: +`End ℂ (ℋ Λ) ⊗ End ℂ (ℋ (Λ_total \ Λ)) ≃ₐ End ℂ (ℋ Λ_total)`. It is the operator-algebra tensor +equivalence followed by conjugation along the Hilbert-space tensor isometry. -/ +noncomputable def tensorEquiv {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : + Module.End ℂ (L.ℋ Λ) ⊗[ℂ] Module.End ℂ (L.ℋ (Λ_total \ Λ)) ≃ₐ[ℂ] + Module.End ℂ (L.ℋ Λ_total) := + TensorProduct.endTensorEndAlgEquiv.trans + ((EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).toLinearEquiv.conjAlgEquiv ℂ) + +/-- Action of `tensorEquiv` on an operator tensor: conjugate `f ⊗ g` (as `TensorProduct.map f g`) +by the Hilbert-space tensor isometry. -/ +lemma tensorEquiv_tmul_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (f : Module.End ℂ (L.ℋ Λ)) (g : Module.End ℂ (L.ℋ (Λ_total \ Λ))) (v : L.ℋ Λ_total) : + L.tensorEquiv h (f ⊗ₜ[ℂ] g) v + = EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h) + (TensorProduct.map f g + ((EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).symm v)) := by + rw [tensorEquiv, AlgEquiv.trans_apply, TensorProduct.endTensorEndAlgEquiv_tmul, + LinearEquiv.conjAlgEquiv_apply, LinearMap.comp_apply, LinearMap.comp_apply] + rfl + +/-- The inverse Hilbert-space tensor isometry sends a combined basis vector `single (combineIdx h +(a, b))` back to the pure tensor `single a ⊗ single b`. -/ +lemma combineIdx_tensorEquiv_symm_single {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (a : L.regionIdx Λ) (b : L.regionIdx (Λ_total \ Λ)) : + (EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).symm + (EuclideanSpace.single (L.combineIdx h (a, b)) (1 : ℂ)) + = EuclideanSpace.single a (1 : ℂ) ⊗ₜ[ℂ] EuclideanSpace.single b (1 : ℂ) := by + rw [← EuclideanSpace.tensorEquiv_single_tmul (𝕜 := ℂ) (L.combineIdx h) a b] + exact (EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).symm_apply_apply _ + +/-- Internal: isotony embedding as `(op X) ⊗ 1` against the operator tensor decomposition +`tensorEquiv`. The public, explicit-subspace form is `opEquiv_includeAlgebra` below. -/ +private theorem opEquiv_includeAlgebra_aux {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X : L.localAlgebra Λ) : + L.opEquiv Λ_total (L.includeAlgebra h X) + = L.tensorEquiv h + (L.opEquiv Λ X ⊗ₜ[ℂ] (1 : Module.End ℂ (L.ℋ (Λ_total \ Λ)))) := by + refine (EuclideanSpace.basisFun (L.regionIdx Λ_total) ℂ).toBasis.ext fun s' => ?_ + obtain ⟨⟨a', b'⟩, rfl⟩ := (L.combineIdx h).surjective s' + rw [OrthonormalBasis.coe_toBasis, EuclideanSpace.basisFun_apply] + apply WithLp.ofLp_injective (p := 2) + funext s + obtain ⟨⟨a, b⟩, rfl⟩ := (L.combineIdx h).surjective s + rw [tensorEquiv_tmul_apply, L.combineIdx_tensorEquiv_symm_single h a' b', + TensorProduct.map_tmul, Module.End.one_apply, EuclideanSpace.ofLp_tensorEquiv_tmul, + Equiv.symm_apply_apply, ofLp_opEquiv, ofLp_opEquiv, PiLp.ofLp_single, PiLp.ofLp_single] + simp + +/-- The bipartition of the total Hilbert space induced by `combineIdx h`, with the complementary +factor `ℋ (Λ_total \ Λ)` as the (traced-out) second factor. Feeding this to +`LinearMap.partialTrace` / `LinearMap.ampliate` names the traced-out subspace explicitly. -/ +noncomputable def regionBipartition {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : + L.ℋ Λ_total ≃ₗ[ℂ] L.ℋ Λ ⊗[ℂ] L.ℋ (Λ_total \ Λ) := + (EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).toLinearEquiv.symm + +/-- **Isotony is the ampliation along the named bipartition**: `includeAlgebra h X` acts as `X` on +`ℋ Λ` and the identity on the traced-out factor `ℋ (Λ_total \ Λ)`. This is the formal sense in which +`combineIdx` realises the tensor factorisation, with the complementary subspace named by +`regionBipartition h`. -/ +theorem opEquiv_includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (X : L.localAlgebra Λ) : + L.opEquiv Λ_total (L.includeAlgebra h X) + = LinearMap.ampliate (L.regionBipartition h) (L.opEquiv Λ X) := by + rw [L.opEquiv_includeAlgebra_aux, LinearMap.ampliate, tensorEquiv, AlgEquiv.trans_apply, + TensorProduct.endTensorEndAlgEquiv_tmul, regionBipartition, LinearEquiv.symm_conjAlgEquiv, + LinearEquiv.symm_symm] + +end LocalNet diff --git a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean new file mode 100644 index 0000000..42af36d --- /dev/null +++ b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean @@ -0,0 +1,92 @@ +module + +public import QuantumSystem.Algebra.LocalNet.TensorDecomposition +public import QuantumSystem.Analysis.Matrix.PartialTrace +public import Mathlib.Analysis.InnerProductSpace.Trace + +/-! +# The partial trace is the operator form of `restrict` + +Completing the operator-level tensor decomposition (`LocalNet.tensorEquiv`, +`LocalNet.opEquiv_includeAlgebra`), this file shows that the marginal `Matrix.restrict` is, under +the operator identifications, exactly the **partial trace** over the complementary Hilbert-space +factor: tracing out `ℋ (Λ_total \ Λ)`. + +`opEquiv_restrict`: `opEquiv Λ (restrict h M) = LinearMap.partialTrace (regionBipartition h) +(opEquiv Λ_total M)`, with the traced-out subspace `ℋ (Λ_total \ Λ)` named explicitly by +`regionBipartition h` (defined in `TensorDecomposition`). + +Together with `opEquiv_includeAlgebra` (isotony as the ampliation `LinearMap.ampliate`), this is the +Schrödinger/Heisenberg pair witnessing that `combineIdx` is a genuine tensor factorisation of +operators on Hilbert spaces. +-/ + +@[expose] public section + +open WithLp +open scoped TensorProduct Matrix + +namespace LocalNet + +variable (L : LocalNet) + +/-- Matrix entries of `(opEquiv Λ).symm T`: the `(i, j)` entry is the `i`-coordinate of the image +of the `j`-th standard basis vector under the operator `T`. (Internal helper.) -/ +private lemma opEquiv_symm_apply_apply (Λ : Finset L.sites) (T : Module.End ℂ (L.ℋ Λ)) + (i j : L.regionIdx Λ) : + (L.opEquiv Λ).symm T i j = ofLp (T (EuclideanSpace.single j (1 : ℂ))) i := by + have hh := L.ofLp_opEquiv Λ ((L.opEquiv Λ).symm T) (EuclideanSpace.single j (1 : ℂ)) + rw [AlgEquiv.apply_symm_apply, PiLp.ofLp_single] at hh + simpa [Matrix.mulVec_single_one, Matrix.col_apply] using (congrFun hh i).symm + +/-- Internal: `restrict` as the `End A ⊗ End B`-level partial trace against the operator tensor +decomposition `tensorEquiv`. The public, explicit-subspace form is `opEquiv_restrict` below. -/ +private theorem opEquiv_restrict_aux {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (M : L.localAlgebra Λ_total) : + L.opEquiv Λ (Matrix.restrict h M) + = TensorProduct.partialTraceRight ((L.tensorEquiv h).symm (L.opEquiv Λ_total M)) := by + suffices H : ∀ T : Module.End ℂ (L.ℋ Λ) ⊗[ℂ] Module.End ℂ (L.ℋ (Λ_total \ Λ)), + L.opEquiv Λ (Matrix.restrict h ((L.opEquiv Λ_total).symm (L.tensorEquiv h T))) + = TensorProduct.partialTraceRight T by + have key := H ((L.tensorEquiv h).symm (L.opEquiv Λ_total M)) + rwa [AlgEquiv.apply_symm_apply, AlgEquiv.symm_apply_apply] at key + intro T + induction T using TensorProduct.induction_on with + | zero => simp + | add T₁ T₂ hT₁ hT₂ => + have hadd : ∀ A B : L.localAlgebra Λ_total, + Matrix.restrict h (A + B) = Matrix.restrict h A + Matrix.restrict h B := by + intro A B; ext a a'; simp [Matrix.restrict_apply, Finset.sum_add_distrib] + simp only [map_add, hadd, hT₁, hT₂] + | tmul Y Z => + rw [TensorProduct.partialTraceRight_tmul] + have htrace : LinearMap.trace ℂ (L.ℋ (Λ_total \ Λ)) Z + = ∑ b : L.regionIdx (Λ_total \ Λ), ofLp (Z (EuclideanSpace.single b (1 : ℂ))) b := by + rw [LinearMap.trace_eq_sum_inner Z (EuclideanSpace.basisFun (L.regionIdx (Λ_total \ Λ)) ℂ)] + refine Finset.sum_congr rfl fun b _ => ?_ + rw [EuclideanSpace.basisFun_apply, EuclideanSpace.inner_single_left, map_one, one_mul] + refine (EuclideanSpace.basisFun (L.regionIdx Λ) ℂ).toBasis.ext fun a' => ?_ + rw [OrthonormalBasis.coe_toBasis, EuclideanSpace.basisFun_apply] + apply WithLp.ofLp_injective (p := 2) + funext a + rw [ofLp_opEquiv, PiLp.ofLp_single, Matrix.mulVec_single_one, Matrix.col_apply, + Matrix.restrict_apply] + simp only [L.opEquiv_symm_apply_apply, tensorEquiv_tmul_apply, + L.combineIdx_tensorEquiv_symm_single, TensorProduct.map_tmul, + EuclideanSpace.ofLp_tensorEquiv_tmul, Equiv.symm_apply_apply, LinearMap.smul_apply] + rw [← Finset.mul_sum, ← htrace] + simp [mul_comm] + +/-- **`restrict` is the partial trace** that explicitly traces out `ℋ (Λ_total \ Λ)`, via the named +bipartition `regionBipartition h`. The operator analogue of `Matrix.partialTrace (e : X ≃ A × B)` +applied to the AQFT marginal: combined with `opEquiv_includeAlgebra` (isotony as the ampliation) +and `LinearMap.partialTrace_ampliate_mul`, it gives the `𝔄(Λ)`-module ("pull-out") law of the +conditional expectation `𝔄(Λ_total) → 𝔄(Λ)`. -/ +theorem opEquiv_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (M : L.localAlgebra Λ_total) : + L.opEquiv Λ (Matrix.restrict h M) + = LinearMap.partialTrace (L.regionBipartition h) (L.opEquiv Λ_total M) := by + rw [L.opEquiv_restrict_aux, LinearMap.partialTrace_apply] + congr 1 + +end LocalNet diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProduct.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProduct.lean index 6859b7c..eb12cdb 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProduct.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProduct.lean @@ -89,3 +89,75 @@ private lemma tensor_add_right (A : H →L[ℂ] H) (B₁ B₂ : K →L[ℂ] K) : | add a b ha hb => simp [map_add, ha, hb] end ContinuousLinearMap + +/-! ### Tensor factorisation of Euclidean spaces along an index bijection + +For an index bijection `e : m × n ≃ p`, the Hilbert-space tensor product +`EuclideanSpace 𝕜 m ⊗ EuclideanSpace 𝕜 n` is isometrically the Euclidean space +`EuclideanSpace 𝕜 p`. This realises, at the level of Hilbert spaces, the factorisation +underlying any bijective splitting of the index set. -/ + +section EuclideanTensor + +open WithLp + +variable {𝕜 : Type*} [RCLike 𝕜] {m n p : Type*} + [Fintype m] [Fintype n] [Fintype p] [DecidableEq m] [DecidableEq n] [DecidableEq p] + +/-- The Hilbert-space tensor factorisation along an index bijection `e : m × n ≃ p`: the tensor +product of `EuclideanSpace 𝕜 m` and `EuclideanSpace 𝕜 n`, transported along `e`, as a linear +isometry equivalence onto `EuclideanSpace 𝕜 p`. Built as the orthonormal-basis representation of +the (reindexed) tensor of the standard bases. -/ +noncomputable def EuclideanSpace.tensorEquiv (e : (m × n) ≃ p) : + EuclideanSpace 𝕜 m ⊗[𝕜] EuclideanSpace 𝕜 n ≃ₗᵢ[𝕜] EuclideanSpace 𝕜 p := + (((EuclideanSpace.basisFun m 𝕜).tensorProduct (EuclideanSpace.basisFun n 𝕜)).reindex e).repr + +/-- The tensor factorisation sends a pure tensor of standard basis vectors to the standard basis +vector at the combined index. -/ +@[simp] +lemma EuclideanSpace.tensorEquiv_single_tmul (e : (m × n) ≃ p) (i : m) (j : n) : + EuclideanSpace.tensorEquiv (𝕜 := 𝕜) e + (EuclideanSpace.single i (1 : 𝕜) ⊗ₜ[𝕜] EuclideanSpace.single j (1 : 𝕜)) + = EuclideanSpace.single (e (i, j)) (1 : 𝕜) := by + have hb : + (((EuclideanSpace.basisFun m 𝕜).tensorProduct (EuclideanSpace.basisFun n 𝕜)).reindex e) + (e (i, j)) + = EuclideanSpace.single i (1 : 𝕜) ⊗ₜ[𝕜] EuclideanSpace.single j (1 : 𝕜) := by + rw [OrthonormalBasis.reindex_apply, Equiv.symm_apply_apply, + OrthonormalBasis.tensorProduct_apply, EuclideanSpace.basisFun_apply, + EuclideanSpace.basisFun_apply] + change (((EuclideanSpace.basisFun m 𝕜).tensorProduct (EuclideanSpace.basisFun n 𝕜)).reindex e).repr + (EuclideanSpace.single i (1 : 𝕜) ⊗ₜ[𝕜] EuclideanSpace.single j (1 : 𝕜)) = _ + rw [← hb, OrthonormalBasis.repr_self] + +end EuclideanTensor + +section EuclideanTensorCoord + +open WithLp + +variable {𝕜 : Type*} [RCLike 𝕜] {m n p : Type*} + [Fintype m] [Fintype n] [Fintype p] + +/-- Coordinate formula for the tensor factorisation on a pure tensor: the `k`-coordinate of +`tensorEquiv e (w₁ ⊗ w₂)` is the product of the `(e.symm k).1`-coordinate of `w₁` and the +`(e.symm k).2`-coordinate of `w₂`. -/ +lemma EuclideanSpace.ofLp_tensorEquiv_tmul (e : (m × n) ≃ p) (w₁ : EuclideanSpace 𝕜 m) + (w₂ : EuclideanSpace 𝕜 n) (k : p) : + ofLp (EuclideanSpace.tensorEquiv (𝕜 := 𝕜) e (w₁ ⊗ₜ[𝕜] w₂)) k + = ofLp w₁ (e.symm k).1 * ofLp w₂ (e.symm k).2 := by + classical + have hk : EuclideanSpace.single k (1 : 𝕜) + = EuclideanSpace.tensorEquiv (𝕜 := 𝕜) e + (EuclideanSpace.single (e.symm k).1 (1 : 𝕜) ⊗ₜ[𝕜] + EuclideanSpace.single (e.symm k).2 (1 : 𝕜)) := by + rw [EuclideanSpace.tensorEquiv_single_tmul, Prod.mk.eta, Equiv.apply_symm_apply] + have hofLp : ofLp (EuclideanSpace.tensorEquiv (𝕜 := 𝕜) e (w₁ ⊗ₜ[𝕜] w₂)) k + = inner 𝕜 (EuclideanSpace.single k (1 : 𝕜)) + (EuclideanSpace.tensorEquiv (𝕜 := 𝕜) e (w₁ ⊗ₜ[𝕜] w₂)) := by + rw [EuclideanSpace.inner_single_left, map_one, one_mul] + rw [hofLp, hk, LinearIsometryEquiv.inner_map_map, TensorProduct.inner_tmul, + EuclideanSpace.inner_single_left, EuclideanSpace.inner_single_left] + simp + +end EuclideanTensorCoord diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean new file mode 100644 index 0000000..33f27c1 --- /dev/null +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean @@ -0,0 +1,131 @@ +module + +public import Mathlib.LinearAlgebra.Trace + +/-! +# Tensor product of endomorphism algebras and the partial trace + +For finite-dimensional free modules `M`, `N` over a commutative ring `R`, the canonical algebra +homomorphism `Module.endTensorEndAlgHom : End R M ⊗ End R N →ₐ End R (M ⊗ N)` is an isomorphism. +This file packages it as an `AlgEquiv` and uses it to define the **partial trace** over the second +factor `partialTraceRight : End R (M ⊗ N) →ₗ End R M`, characterised on operator tensors by +`Y ⊗ Z ↦ (trace Z) • Y`. + +These are the abstract, basis-free ingredients of the tensor factorisation of operator algebras +on (finite-dimensional) Hilbert spaces. +-/ + +@[expose] public section + +open scoped TensorProduct + +namespace TensorProduct + +variable {R : Type*} [CommRing R] {M N : Type*} + [AddCommGroup M] [Module R M] [Module.Finite R M] [Module.Free R M] + [AddCommGroup N] [Module R N] [Module.Finite R N] [Module.Free R N] + +/-- For finite-dimensional free modules, `Module.endTensorEndAlgHom` is an algebra isomorphism +`End R M ⊗ End R N ≃ₐ End R (M ⊗ N)`. -/ +noncomputable def endTensorEndAlgEquiv : + Module.End R M ⊗[R] Module.End R N ≃ₐ[R] Module.End R (M ⊗[R] N) := + AlgEquiv.ofBijective Module.endTensorEndAlgHom <| by + have h : (Module.endTensorEndAlgHom (R := R) (S := R) (A := R) (M := M) (N := N)).toLinearMap + = (homTensorHomEquiv R M N M N).toLinearMap := by + apply TensorProduct.ext' + intro f g + rw [AlgHom.toLinearMap_apply, Module.endTensorEndAlgHom_apply, + LinearEquiv.coe_coe, homTensorHomEquiv_apply] + apply TensorProduct.ext' + intro m n + rw [TensorProduct.AlgebraTensorModule.map_tmul, TensorProduct.homTensorHomMap_apply, + TensorProduct.map_tmul] + have hcoe : ⇑(Module.endTensorEndAlgHom (R := R) (S := R) (A := R) (M := M) (N := N)) + = ⇑(homTensorHomEquiv R M N M N) := funext fun x => LinearMap.congr_fun h x + rw [hcoe] + exact (homTensorHomEquiv R M N M N).bijective + +@[simp] +lemma endTensorEndAlgEquiv_tmul (f : Module.End R M) (g : Module.End R N) : + (endTensorEndAlgEquiv (R := R) (M := M) (N := N)) (f ⊗ₜ[R] g) = TensorProduct.map f g := by + rw [endTensorEndAlgEquiv, AlgEquiv.coe_ofBijective, Module.endTensorEndAlgHom_apply] + apply TensorProduct.ext' + intro m n + rw [TensorProduct.AlgebraTensorModule.map_tmul, TensorProduct.map_tmul] + +/-- The **partial trace over the second factor** `End R M ⊗ End R N →ₗ End R M`: trace out the +`N`-factor of an operator tensor, characterised by `Y ⊗ Z ↦ (trace Z) • Y`. This is the abstract +partial trace paired with the operator tensor decomposition `endTensorEndAlgEquiv`. -/ +noncomputable def partialTraceRight : + Module.End R M ⊗[R] Module.End R N →ₗ[R] Module.End R M := + (TensorProduct.rid R (Module.End R M)).toLinearMap ∘ₗ + TensorProduct.map LinearMap.id (LinearMap.trace R N) + +omit [Module.Finite R M] [Module.Free R M] [Module.Finite R N] [Module.Free R N] in +@[simp] +lemma partialTraceRight_tmul (Y : Module.End R M) (Z : Module.End R N) : + partialTraceRight (Y ⊗ₜ[R] Z) = (LinearMap.trace R N Z) • Y := by + rw [partialTraceRight, LinearMap.comp_apply, TensorProduct.map_tmul, LinearMap.id_apply, + LinearEquiv.coe_coe, TensorProduct.rid_tmul] + +omit [Module.Finite R M] [Module.Free R M] [Module.Finite R N] [Module.Free R N] in +/-- **Left module property** (pull-out): the partial trace pulls a left factor `Y ⊗ 1` out of the +first tensor factor, `partialTraceRight ((Y ⊗ 1) * S) = Y * partialTraceRight S`. Internal building +block for `LinearMap.partialTrace_ampliate_mul`. -/ +private lemma partialTraceRight_includeLeft_mul (Y : Module.End R M) + (S : Module.End R M ⊗[R] Module.End R N) : + partialTraceRight ((Y ⊗ₜ[R] (1 : Module.End R N)) * S) = Y * partialTraceRight S := by + induction S using TensorProduct.induction_on with + | zero => simp + | tmul Y' Z' => + rw [Algebra.TensorProduct.tmul_mul_tmul, one_mul, partialTraceRight_tmul, + partialTraceRight_tmul, mul_smul_comm] + | add S₁ S₂ h₁ h₂ => rw [mul_add, map_add, map_add, h₁, h₂, mul_add] + +end TensorProduct + +namespace LinearMap + +open scoped TensorProduct + +variable {𝕜 ℋ A B : Type*} [Field 𝕜] + [AddCommGroup ℋ] [Module 𝕜 ℋ] + [AddCommGroup A] [Module 𝕜 A] [Module.Finite 𝕜 A] [Module.Free 𝕜 A] + [AddCommGroup B] [Module 𝕜 B] [Module.Finite 𝕜 B] [Module.Free 𝕜 B] + +/-- **Partial trace along an explicit decomposition** `e : ℋ ≃ₗ A ⊗ B`: trace out the named second +factor `B` and retain `A`. This is the operator analogue of `Matrix.partialTrace (e : X ≃ A × B)` — +the subspace traced out is named by `e`, and the retained subsystem `A` appears in the codomain. -/ +noncomputable def partialTrace (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) : + Module.End 𝕜 ℋ →ₗ[𝕜] Module.End 𝕜 A := + TensorProduct.partialTraceRight ∘ₗ + (TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm.toLinearMap ∘ₗ + (e.conjAlgEquiv 𝕜).toLinearMap + +theorem partialTrace_apply (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (ρ : Module.End 𝕜 ℋ) : + partialTrace e ρ = TensorProduct.partialTraceRight + ((TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm (e.conjAlgEquiv 𝕜 ρ)) := + rfl + +/-- **Ampliation along `e`**: lift an operator `M` on the retained factor `A` to `ℋ`, acting as +`M` on `A` and the identity on the traced-out factor `B` (i.e. `M ⊗ 1` transported by `e`). -/ +noncomputable def ampliate (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Module.End 𝕜 A) : Module.End 𝕜 ℋ := + (e.conjAlgEquiv 𝕜).symm (TensorProduct.map M 1) + +private theorem endTensorEndAlgEquiv_symm_map_one (M : Module.End 𝕜 A) : + (TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm + (TensorProduct.map M 1) = M ⊗ₜ[𝕜] 1 := by + rw [← TensorProduct.endTensorEndAlgEquiv_tmul] + exact (TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm_apply_apply _ + +/-- **`Tr_B((M⊗1)·ρ) = M·Tr_B(ρ)`**: the partial trace along `e` is a left module map over the +ampliation, with `B` (the traced-out subspace) named explicitly by `e`. -/ +theorem partialTrace_ampliate_mul (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Module.End 𝕜 A) + (ρ : Module.End 𝕜 ℋ) : + partialTrace e (ampliate e M * ρ) = M * partialTrace e ρ := by + rw [partialTrace_apply, partialTrace_apply, ampliate, map_mul (e.conjAlgEquiv 𝕜), + AlgEquiv.apply_symm_apply, + map_mul (TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm, + endTensorEndAlgEquiv_symm_map_one, TensorProduct.partialTraceRight_includeLeft_mul] + +end LinearMap From f29a1f24c35fdd360d32dcd565701767d378ba58 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 10:07:11 +0000 Subject: [PATCH 004/113] refactor(LocalNet): drop unused region-index factorisation equivalences Remove the empty/insert/univ recursive split, the left-associated triple factorisation, the complement-decomposition suite, and the singleton helper from LocalNet/Basic.lean. Only regionIdxCongr, regionIdxPairEquiv and regionIdxTripleEquiv are actually consumed by the net properties; the rest was speculative scaffolding with no call sites. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem/Algebra/LocalNet/Basic.lean | 253 +--------------------- 1 file changed, 5 insertions(+), 248 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/Basic.lean b/QuantumSystem/Algebra/LocalNet/Basic.lean index f37eb48..84db3a8 100644 --- a/QuantumSystem/Algebra/LocalNet/Basic.lean +++ b/QuantumSystem/Algebra/LocalNet/Basic.lean @@ -18,8 +18,8 @@ systems this specialises to: This file provides the carrier structure, the derived region-index types, the index-combiner equivalence `combineIdx` realising `regionIdx Λ_total ≃ regionIdx Λ × regionIdx (Λ_total \ Λ)`, -the cardinality factorisation, the transport `regionIdxCongr`, and the `n`-partite region -factorisation equivalences (`regionIdxPairEquiv`, `regionIdxTripleEquiv`, `regionIdxCompl*`). +the cardinality factorisation, the transport `regionIdxCongr`, and the bipartite and tripartite +region factorisation equivalences (`regionIdxPairEquiv`, `regionIdxTripleEquiv`). The net **properties** built on this data live in sibling modules: `LocalNet.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `LocalNet.Locality` @@ -145,74 +145,12 @@ def regionIdxCongr {Λ Λ' : Finset L.sites} (h : Λ = Λ') : /-! ### Region equivalences -Generic equivalences over arbitrary site types — used both directly (for any finite region) -and as building blocks for the bipartite (`regionIdxPairEquiv`) and tripartite -(`regionIdxTripleEquiv`, `regionIdxTripleEquiv'`) factorisations below. -/ +Bipartite and tripartite factorisations of a region's index type over arbitrary site types: +`regionIdx {a, b} ≃ localIdx a × localIdx b` and the right-associated three-element analogue. +Both are direct definitions with concrete `toFun`, so every projection evaluates by `rfl`. -/ variable (L : LocalNet) -/-- Singleton region: `regionIdx {s} ≃ localIdx s`. -/ -def singletonRegionIdxEquiv (s : L.sites) : - L.regionIdx ({s} : Finset L.sites) ≃ L.localIdx s where - toFun f := f ⟨s, Finset.mem_singleton.mpr rfl⟩ - invFun x := fun ⟨v, hv⟩ => - (Finset.mem_singleton.mp hv).symm ▸ x - left_inv f := by - funext ⟨v, hv⟩ - have hvs : v = s := Finset.mem_singleton.mp hv - subst hvs - rfl - right_inv x := rfl - -@[simp] private lemma singletonRegionIdxEquiv_apply (s : L.sites) - (f : L.regionIdx ({s} : Finset L.sites)) : - L.singletonRegionIdxEquiv s f = f ⟨s, Finset.mem_singleton.mpr rfl⟩ := rfl - -/-! ### Generic n-partite primitives - -Building blocks for any finite region: `regionIdx ∅ ≃ PUnit`, an `insert`-based recursive -split, and (for finite site types) the universal product form -`regionIdx Finset.univ ≃ Π s, localIdx s`. Two- and three-element factor equivs are derived -from the recursive split — adding more partite counts (4, 5, ...) is now a one-liner with no -new boilerplate. -/ - -/-- The empty region: `regionIdx ∅ ≃ PUnit`. The dependent product over the empty - subtype has a unique element. -/ -def regionIdxEmptyEquiv : L.regionIdx (∅ : Finset L.sites) ≃ PUnit where - toFun _ := PUnit.unit - invFun _ := fun s => absurd s.property (Finset.notMem_empty _) - left_inv f := by - funext s - exact absurd s.property (Finset.notMem_empty _) - right_inv _ := rfl - -/-- **Recursive split (region composition rule)**: for `s ∉ Λ`, - `regionIdx (insert s Λ) ≃ localIdx s × regionIdx Λ`. - - This is the core composition primitive — repeated application gives factorisation - of any finitely-enumerated region into per-site factors. Built from `combineIdx` - applied to the singleton `{s} ⊆ insert s Λ`, with the complementary region - `insert s Λ \ {s}` reducing to `Λ`. -/ -def regionIdxInsertEquiv {s : L.sites} {Λ : Finset L.sites} (hs : s ∉ Λ) : - L.regionIdx (insert s Λ) ≃ L.localIdx s × L.regionIdx Λ := - have h_sub : ({s} : Finset L.sites) ⊆ insert s Λ := - Finset.singleton_subset_iff.mpr (Finset.mem_insert_self s Λ) - have h_compl_eq : insert s Λ \ {s} = Λ := by - rw [Finset.insert_sdiff_of_mem _ (Finset.mem_singleton_self s), - Finset.sdiff_eq_self_iff_disjoint.mpr (Finset.disjoint_singleton_right.mpr hs)] - (L.combineIdx h_sub).symm.trans - (Equiv.prodCongr (L.singletonRegionIdxEquiv s) (L.regionIdxCongr h_compl_eq)) - -/-- The universal region: `regionIdx Finset.univ ≃ Π s : sites, localIdx s`. - Collapses the `Finset.univ`-subtype back to the underlying type. Requires `Fintype sites` - (the only place a finite site set is needed; the rest of the API runs on infinite lattices). -/ -def regionIdxUnivEquiv [Fintype L.sites] : L.regionIdx (Finset.univ : Finset L.sites) ≃ - ∀ s : L.sites, L.localIdx s where - toFun f s := f ⟨s, Finset.mem_univ s⟩ - invFun g := fun ⟨s, _⟩ => g s - left_inv f := by funext ⟨s, _⟩; rfl - right_inv _ := rfl - /-- **2-element factorisation**: `regionIdx {a, b} ≃ localIdx a × localIdx b` when `a ≠ b`. Direct definition with concrete `toFun` so both projections evaluate by `rfl`. -/ def regionIdxPairEquiv {a b : L.sites} (hab : a ≠ b) : @@ -330,185 +268,4 @@ def regionIdxTripleEquiv {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac f ⟨c, Finset.mem_insert_of_mem (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl))⟩ := rfl -/-- **3-element factorisation (left-associated)**: the alternate - `regionIdx {a, b, c} ≃ (localIdx a × localIdx b) × localIdx c` view, used when the - bipartite split sees the pair `(a, b)` together against `c`. -/ -def regionIdxTripleEquiv' {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) : - L.regionIdx ({a, b, c} : Finset L.sites) ≃ - (L.localIdx a × L.localIdx b) × L.localIdx c := - (L.regionIdxTripleEquiv hab hbc hac).trans (Equiv.prodAssoc _ _ _).symm - -/-- **Pair-complement on the left site**: for the two-element region `{a, b}` with - `a ≠ b`, the index type of the complement of `{a}` reduces to `localIdx b`. - Direct realisation of "evaluate at the unique remaining site `b`". -/ -def regionIdxComplLeftSite {a b : L.sites} (hab : a ≠ b) : - L.regionIdx (({a, b} : Finset L.sites) \ {a}) ≃ L.localIdx b where - toFun f := f ⟨b, Finset.mem_sdiff.mpr - ⟨Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl), - Finset.notMem_singleton.mpr (fun h => hab h.symm)⟩⟩ - invFun y := fun ⟨s, hs⟩ => - have hsb : s = b := by - simp only [Finset.mem_sdiff, Finset.mem_insert, Finset.mem_singleton] at hs - rcases hs.1 with h | h - · exact absurd h hs.2 - · exact h - hsb ▸ y - left_inv f := by - funext ⟨s, hs⟩ - have hsb : s = b := by - simp only [Finset.mem_sdiff, Finset.mem_insert, Finset.mem_singleton] at hs - rcases hs.1 with h | h - · exact absurd h hs.2 - · exact h - subst hsb - rfl - right_inv y := rfl - -/-- **Pair-complement on the right site**: dual of `regionIdxComplLeftSite` — the - complement of `{b}` in `{a, b}` reduces to `localIdx a`. -/ -def regionIdxComplRightSite {a b : L.sites} (hab : a ≠ b) : - L.regionIdx (({a, b} : Finset L.sites) \ {b}) ≃ L.localIdx a where - toFun f := f ⟨a, Finset.mem_sdiff.mpr - ⟨Finset.mem_insert_self a {b}, Finset.notMem_singleton.mpr hab⟩⟩ - invFun y := fun ⟨s, hs⟩ => - have hsa : s = a := by - simp only [Finset.mem_sdiff, Finset.mem_insert, Finset.mem_singleton] at hs - rcases hs.1 with h | h - · exact h - · exact absurd h hs.2 - hsa ▸ y - left_inv f := by - funext ⟨s, hs⟩ - have hsa : s = a := by - simp only [Finset.mem_sdiff, Finset.mem_insert, Finset.mem_singleton] at hs - rcases hs.1 with h | h - · exact h - · exact absurd h hs.2 - subst hsa - rfl - right_inv y := rfl - -/-- **Triple-complement, first site**: for pairwise-distinct `a, b, c : L.sites`, - `regionIdx ({a, b, c} \ {a}) ≃ localIdx b × localIdx c`. Direct construction - (no `regionIdxCongr` transport) so pointwise evaluation reduces by computation, - enabling the marginal-compatibility helpers used by SSA-style proofs. -/ -noncomputable def regionIdxComplFirst {a b c : L.sites} - (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) : - L.regionIdx (({a, b, c} : Finset L.sites) \ ({a} : Finset _)) ≃ - L.localIdx b × L.localIdx c where - toFun f := - (f ⟨b, Finset.mem_sdiff.mpr ⟨ - Finset.mem_insert_of_mem (Finset.mem_insert_self _ _), - Finset.notMem_singleton.mpr hab.symm⟩⟩, - f ⟨c, Finset.mem_sdiff.mpr ⟨ - Finset.mem_insert_of_mem (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)), - Finset.notMem_singleton.mpr hac.symm⟩⟩) - invFun xbc := fun ⟨v, hv⟩ => - if h : v = b then h ▸ xbc.1 - else - have hvc : v = c := by - rw [Finset.mem_sdiff] at hv - rcases Finset.mem_insert.mp hv.1 with rfl | h2 - · exact absurd (Finset.mem_singleton_self _) hv.2 - · rcases Finset.mem_insert.mp h2 with rfl | h3 - · exact absurd rfl h - · exact Finset.mem_singleton.mp h3 - hvc ▸ xbc.2 - left_inv f := by - funext ⟨v, hv⟩ - rw [Finset.mem_sdiff] at hv - by_cases hvb : v = b - · subst hvb; simp - · have hvc : v = c := by - rcases Finset.mem_insert.mp hv.1 with rfl | h2 - · exact absurd (Finset.mem_singleton_self _) hv.2 - · rcases Finset.mem_insert.mp h2 with rfl | h3 - · exact absurd rfl hvb - · exact Finset.mem_singleton.mp h3 - subst hvc; simp [hvb] - right_inv := by - rintro ⟨xb, xc⟩ - have hcb : c ≠ b := hbc.symm - ext1 <;> simp [hcb] - -/-- **Triple-complement, first two sites**: for pairwise-distinct - `a, b, c : L.sites`, `regionIdx ({a, b, c} \ {a, b}) ≃ localIdx c`. Direct - construction (no `regionIdxCongr` transport) so pointwise evaluation reduces - by computation. -/ -noncomputable def regionIdxComplPairFirstTwo {a b c : L.sites} - (hac : a ≠ c) (hbc : b ≠ c) : - L.regionIdx (({a, b, c} : Finset L.sites) \ ({a, b} : Finset _)) ≃ L.localIdx c where - toFun f := f ⟨c, Finset.mem_sdiff.mpr ⟨ - Finset.mem_insert_of_mem (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)), - by simp only [Finset.mem_insert, Finset.mem_singleton, not_or] - exact ⟨hac.symm, hbc.symm⟩⟩⟩ - invFun xc := fun ⟨v, hv⟩ => - have hvc : v = c := by - rw [Finset.mem_sdiff] at hv - rcases Finset.mem_insert.mp hv.1 with rfl | h2 - · exact absurd (Finset.mem_insert_self _ _) hv.2 - · rcases Finset.mem_insert.mp h2 with rfl | h3 - · exact absurd - (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)) hv.2 - · exact Finset.mem_singleton.mp h3 - hvc ▸ xc - left_inv f := by - funext ⟨v, hv⟩ - rw [Finset.mem_sdiff] at hv - have hvc : v = c := by - rcases Finset.mem_insert.mp hv.1 with rfl | h2 - · exact absurd (Finset.mem_insert_self _ _) hv.2 - · rcases Finset.mem_insert.mp h2 with rfl | h3 - · exact absurd - (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)) hv.2 - · exact Finset.mem_singleton.mp h3 - subst hvc; rfl - right_inv := by intro xc; rfl - -/-- **Triple-complement, last two sites**: for pairwise-distinct - `a, b, c : L.sites`, `regionIdx ({a, b, c} \ {b, c}) ≃ localIdx a`. Direct - construction (no `regionIdxCongr` transport) so pointwise evaluation reduces - by computation. -/ -noncomputable def regionIdxComplPairLastTwo {a b c : L.sites} - (hab : a ≠ b) (hac : a ≠ c) : - L.regionIdx (({a, b, c} : Finset L.sites) \ ({b, c} : Finset _)) ≃ L.localIdx a where - toFun f := f ⟨a, Finset.mem_sdiff.mpr ⟨ - Finset.mem_insert_self _ _, - by simp only [Finset.mem_insert, Finset.mem_singleton, not_or] - exact ⟨hab, hac⟩⟩⟩ - invFun xa := fun ⟨v, hv⟩ => - have hva : v = a := by - rw [Finset.mem_sdiff] at hv - rcases Finset.mem_insert.mp hv.1 with rfl | h2 - · rfl - · rcases Finset.mem_insert.mp h2 with rfl | h3 - · exact absurd (Finset.mem_insert_self _ _) hv.2 - · have hvc : v = c := Finset.mem_singleton.mp h3 - subst hvc - exact absurd - (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)) hv.2 - hva ▸ xa - left_inv f := by - funext ⟨v, hv⟩ - rw [Finset.mem_sdiff] at hv - have hva : v = a := by - rcases Finset.mem_insert.mp hv.1 with rfl | h2 - · rfl - · rcases Finset.mem_insert.mp h2 with rfl | h3 - · exact absurd (Finset.mem_insert_self _ _) hv.2 - · have hvc : v = c := Finset.mem_singleton.mp h3 - subst hvc - exact absurd - (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)) hv.2 - subst hva; rfl - right_inv := by intro xa; rfl - -/-- `{b} ⊆ {a, b, c}` for any sites `a, b, c`. Pure Finset membership; the - arguments `a` and `c` are kept positional so call sites can pass them - explicitly when convenient. -/ -lemma singleton_b_subset_triple (a b c : L.sites) : - ({b} : Finset L.sites) ⊆ ({a, b, c} : Finset L.sites) := - Finset.singleton_subset_iff.mpr - (Finset.mem_insert_of_mem (Finset.mem_insert_self b _)) - end LocalNet From 03501722f2f9d941d22510566450b0b8e411c2d7 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 10:07:29 +0000 Subject: [PATCH 005/113] refactor(Matrix): remove unused rpow CFC-transport chain from Effros The leftMulMatrix_rpow / rightMulMatrix_rpow lemmas and the entire star-algebra homomorphism + continuity + cfc apparatus built to prove them were unused. Removing the rpow lemmas orphaned the whole chain (leftMulStarAlgHom, rightMulConjTransposeStarAlgHom, *_cfc, rightMulMatrix_posSemidef) plus several leaf helpers (leftMul_apply, *_pow, *_conjTranspose, signMatrix_*, kronecker_npow, leftRightMatrixPerspective and its Hermiticity lemma). All removals verified dead by build. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem/Analysis/Matrix/Effros.lean | 344 ---------------------- 1 file changed, 344 deletions(-) diff --git a/QuantumSystem/Analysis/Matrix/Effros.lean b/QuantumSystem/Analysis/Matrix/Effros.lean index d7738b4..297aea7 100644 --- a/QuantumSystem/Analysis/Matrix/Effros.lean +++ b/QuantumSystem/Analysis/Matrix/Effros.lean @@ -44,16 +44,6 @@ noncomputable def rightMul {m : Type*} [Fintype m] (B : Matrix m m ℂ) : Matrix m m ℂ →ₗ[ℂ] Matrix m m ℂ := mulRightLinearMap m ℂ B -/-- `leftMul A` applied to a matrix `X` yields `A * X`. -/ -@[simp] lemma leftMul_apply {m : Type*} [Fintype m] - (A X : Matrix m m ℂ) : leftMul A X = A * X := by - simp [leftMul] - -/-- `rightMul B` applied to a matrix `X` yields `X * B`. -/ -@[simp] lemma rightMul_apply {m : Type*} [Fintype m] - (B X : Matrix m m ℂ) : rightMul B X = X * B := by - simp [rightMul] - /-- Left and right multiplication operators commute as linear maps. -/ lemma leftMul_rightMul_commute {m : Type*} [Fintype m] (A B : Matrix m m ℂ) : @@ -166,23 +156,6 @@ theorem rightMulMatrix_smul_real {m : Type*} [Fintype m] [DecidableEq m] ext i j simp [Complex.real_smul] -/-- leftMulMatrix is multiplicative: leftMulMatrix (A * B) = leftMulMatrix A * leftMulMatrix B -/ -lemma leftMulMatrix_mul {m : Type*} [Fintype m] [DecidableEq m] - (A B : Matrix m m ℂ) : - 𝐋 (A * B) = 𝐋 A * 𝐋 B := by - simp only [leftMulMatrix] - have h : leftMul (A * B) = (leftMul A).comp (leftMul B) := by - ext X; simp [leftMul] - rw [h, LinearMap.toMatrix_comp (matrixBasis m) (matrixBasis m) (matrixBasis m)] - -/-- leftMulMatrix maps identity to identity -/ -lemma leftMulMatrix_one {m : Type*} [Fintype m] [DecidableEq m] : - 𝐋 (1 : Matrix m m ℂ) = (1 : Matrix (m × m) (m × m) ℂ) := by - simp only [leftMulMatrix] - have h : leftMul (1 : Matrix m m ℂ) = LinearMap.id := by - ext X; simp [leftMul] - rw [h, LinearMap.toMatrix_id (matrixBasis m)] - /-- rightMulMatrix is anti-multiplicative: rightMulMatrix (A * B) = rightMulMatrix B * rightMulMatrix A -/ lemma rightMulMatrix_mul {m : Type*} [Fintype m] [DecidableEq m] @@ -201,26 +174,6 @@ lemma rightMulMatrix_one {m : Type*} [Fintype m] [DecidableEq m] : ext X; simp [rightMul] rw [h, LinearMap.toMatrix_id (matrixBasis m)] - -/-- rightMulMatrix preserves powers: rightMulMatrix (B ^ n) = (rightMulMatrix B) ^ n -/ -lemma rightMulMatrix_pow {m : Type*} [Fintype m] [DecidableEq m] - (B : Matrix m m ℂ) (n : ℕ) : - 𝐑 (B ^ n) = (𝐑 B) ^ n := by - induction n with - | zero => simp [rightMulMatrix_one] - | succ n ih => - rw [pow_succ, rightMulMatrix_mul, ih, ← pow_succ'] - -/-- leftMulMatrix preserves powers: leftMulMatrix (A ^ n) = (leftMulMatrix A) ^ n -/ -lemma leftMulMatrix_pow {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (n : ℕ) : - 𝐋 (A ^ n) = (𝐋 A) ^ n := by - induction n with - | zero => simp [leftMulMatrix_one] - | succ n ih => - rw [pow_succ, leftMulMatrix_mul, ih] - rw [pow_succ] - /-- The standard basis element at index `(i, j)` is the matrix with `1` at `(i, j)` and `0` elsewhere. -/ lemma matrixBasis_apply_eq_single {m : Type*} [Fintype m] [DecidableEq m] (ij : m × m) : matrixBasis m ij = Matrix.single ij.1 ij.2 (1 : ℂ) := by @@ -301,13 +254,6 @@ theorem rightMulMatrix_apply {m : Type*} [Fintype m] [DecidableEq m] simp · simp [hik] -/-- Action of `leftMulMatrix A` on the vectorized form of `Kᴴ` yields `(A * Kᴴ) i j`. -/ -lemma leftMulMatrix_mulVec_vecConjTranspose {m : Type*} [Fintype m] [DecidableEq m] - (A K : Matrix m m ℂ) (i j : m) : - (𝐋 A *ᵥ (fun x : m × m => Kᴴ x.1 x.2)) (i, j) = (A * Kᴴ) i j := by - classical - simp [Matrix.mulVec, dotProduct, leftMulMatrix_apply, Matrix.mul_apply, Fintype.sum_prod_type] - /-- Action of `rightMulMatrix B` on the vectorized form of `Kᴴ` yields `(Kᴴ * B) i j`. -/ lemma rightMulMatrix_mulVec_vecConjTranspose {m : Type*} [Fintype m] [DecidableEq m] (B K : Matrix m m ℂ) (i j : m) : @@ -368,30 +314,6 @@ lemma rightMulMatrix_eq_one_kronecker_transpose {m : Type*} [Fintype m] [Decidab simp [rightMulMatrix_apply, Matrix.kroneckerMap_apply, Matrix.transpose_apply] · simp [rightMulMatrix_apply, Matrix.kroneckerMap_apply, Matrix.transpose_apply, hik] -/-- `leftMulMatrix` commutes with conjugate transpose: `leftMulMatrix (Aᴴ) = (leftMulMatrix A)ᴴ`. -/ -lemma leftMulMatrix_conjTranspose {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) : - 𝐋 (Aᴴ) = (𝐋 A)ᴴ := by - classical - ext ⟨i, j⟩ ⟨k, l⟩ - simp only [leftMulMatrix_apply, Matrix.conjTranspose_apply] - by_cases hjl : j = l - · subst hjl; simp - · have hlj : ¬ l = j := Ne.symm hjl - simp [hjl, hlj] - -/-- `rightMulMatrix` commutes with conjugate transpose: `rightMulMatrix (Bᴴ) = (rightMulMatrix B)ᴴ`. -/ -lemma rightMulMatrix_conjTranspose {m : Type*} [Fintype m] [DecidableEq m] - (B : Matrix m m ℂ) : - 𝐑 (Bᴴ) = (𝐑 B)ᴴ := by - classical - ext ⟨i, j⟩ ⟨k, l⟩ - simp only [rightMulMatrix_apply, Matrix.conjTranspose_apply] - by_cases hik : i = k - · subst hik; simp - · have hki : ¬ k = i := Ne.symm hik - simp [hik, hki] - /-- `leftMulMatrix` preserves positive semidefiniteness. -/ theorem leftMulMatrix_posSemidef {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosSemidef) : @@ -400,15 +322,6 @@ theorem leftMulMatrix_posSemidef {m : Type*} [Fintype m] [DecidableEq m] simpa [leftMulMatrix_eq_kronecker_one] using (Matrix.PosSemidef.kronecker (m := m) (x := A) (y := (1 : Matrix m m ℂ)) hA posSemidef_one) -/-- `rightMulMatrix` preserves positive semidefiniteness. -/ -lemma rightMulMatrix_posSemidef {m : Type*} [Fintype m] [DecidableEq m] - {B : Matrix m m ℂ} (hB : B.PosSemidef) : - (𝐑 B).PosSemidef := by - classical - have hB' : Bᵀ.PosSemidef := hB.transpose - simpa [rightMulMatrix_eq_one_kronecker_transpose] using - (Matrix.PosSemidef.kronecker (m := m) (x := (1 : Matrix m m ℂ)) (y := Bᵀ) posSemidef_one hB') - /-- `rightMulMatrix` preserves positive definiteness. -/ theorem rightMulMatrix_posDef {m : Type*} [Fintype m] [DecidableEq m] {B : Matrix m m ℂ} (hB : B.PosDef) : @@ -418,190 +331,6 @@ theorem rightMulMatrix_posDef {m : Type*} [Fintype m] [DecidableEq m] simpa [rightMulMatrix_eq_one_kronecker_transpose] using (Matrix.PosDef.kronecker (m := m) (x := (1 : Matrix m m ℂ)) (y := Bᵀ) posDef_one hB') -/-- leftMulMatrix as a star algebra homomorphism over ℝ. - This allows using the CFC infrastructure to relate - leftMulMatrix (f(A)) = f(leftMulMatrix(A)) for continuous f. -/ -noncomputable def leftMulStarAlgHom {m : Type*} [Fintype m] [DecidableEq m] : - Matrix m m ℂ →⋆ₐ[ℝ] Matrix (m × m) (m × m) ℂ where - toFun := leftMulMatrix - map_one' := leftMulMatrix_one - map_mul' := leftMulMatrix_mul - map_zero' := by - change 𝐋 0 = 0 - have h : leftMul (0 : Matrix m m ℂ) = 0 := by ext X; simp [leftMul] - simp only [leftMulMatrix, h, map_zero] - map_add' := leftMulMatrix_add - commutes' r := by - simp only [Algebra.algebraMap_eq_smul_one] - rw [leftMulMatrix_smul_real, leftMulMatrix_one] - map_star' a := by - simp only [star_eq_conjTranspose] - exact leftMulMatrix_conjTranspose a - -/-- The leftMulMatrix homomorphism is continuous (finite dimensional). -/ -lemma leftMulStarAlgHom_continuous {m : Type*} [Fintype m] [DecidableEq m] : - Continuous (leftMulStarAlgHom : Matrix m m ℂ →⋆ₐ[ℝ] Matrix (m × m) (m × m) ℂ) := by - -- leftMulMatrix is a linear map between finite-dimensional normed spaces, hence continuous - letI : SeminormedAddCommGroup (Matrix m m ℂ) := Matrix.linftyOpSeminormedAddCommGroup - letI : NormedSpace ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedSpace - letI : IsBoundedSMul ℝ (Matrix m m ℂ) := Matrix.linftyOpIsBoundedSMul - letI : SeminormedAddCommGroup (Matrix (m × m) (m × m) ℂ) := - Matrix.linftyOpSeminormedAddCommGroup - letI : NormedSpace ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedSpace - letI : IsBoundedSMul ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpIsBoundedSMul - haveI : FiniteDimensional ℝ (Matrix m m ℂ) := inferInstance - let f : Matrix m m ℂ →ₗ[ℝ] Matrix (m × m) (m × m) ℂ := - (leftMulStarAlgHom : Matrix m m ℂ →⋆ₐ[ℝ] _).toAlgHom.toLinearMap - change Continuous (f : Matrix m m ℂ → _) - exact f.continuous_of_finiteDimensional - -/-- CFC commutes with leftMulMatrix: for self-adjoint A and continuous f, - leftMulMatrix (cfc f A) = cfc f (leftMulMatrix A). -/ -lemma leftMulMatrix_cfc {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : IsSelfAdjoint A) (f : ℝ → ℝ) - (hf : ContinuousOn f (spectrum ℝ A) := by cfc_cont_tac) : - 𝐋 (cfc f A) = cfc f (𝐋 A) := by - letI : NormedRing (Matrix m m ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix m m ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m) (A := ℂ) - letI : NormedRing (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix (m × m) (m × m) ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m × m) (A := ℂ) - exact StarAlgHom.map_cfc leftMulStarAlgHom f A hf - leftMulStarAlgHom_continuous hA - -/-- leftMulMatrix preserves rpow: leftMulMatrix (A ^ s) = (leftMulMatrix A) ^ s - for positive semidefinite A and real s. -/ -lemma leftMulMatrix_rpow {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.PosSemidef) {s : ℝ} (hs : 0 ≤ s) : - 𝐋 (A ^ s) = (𝐋 A) ^ s := by - letI : NormedRing (Matrix m m ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix m m ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m) (A := ℂ) - letI : NormedRing (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix (m × m) (m × m) ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m × m) (A := ℂ) - have hA0 : (0 : Matrix m m ℂ) ≤ A := by simpa [Matrix.le_iff] using hA - have hLA0 : (0 : Matrix (m × m) (m × m) ℂ) ≤ 𝐋 A := by - simpa [Matrix.le_iff] using leftMulMatrix_posSemidef hA - have hcont_rpow : ContinuousOn (fun x : ℝ => x ^ s) (spectrum ℝ A) := - (Real.continuous_rpow_const hs).continuousOn - rw [CFC.rpow_eq_cfc_real (a := A) (ha := hA0), - CFC.rpow_eq_cfc_real (a := 𝐋 A) (ha := hLA0)] - exact leftMulMatrix_cfc A hA.1.isSelfAdjoint (· ^ s) hcont_rpow - -/-- B ↦ rightMulMatrix(Bᴴ) as a star algebra homomorphism over ℝ. -This composes the anti-homomorphism `rightMulMatrix` with the anti-involution -conjTranspose, yielding a genuine homomorphism. -/ -noncomputable def rightMulConjTransposeStarAlgHom {m : Type*} [Fintype m] [DecidableEq m] : - Matrix m m ℂ →⋆ₐ[ℝ] Matrix (m × m) (m × m) ℂ where - toFun B := 𝐑 (Bᴴ) - map_one' := by simp [conjTranspose_one, rightMulMatrix_one] - map_mul' A B := by - change 𝐑 ((A * B)ᴴ) = 𝐑 (Aᴴ) * 𝐑 (Bᴴ) - rw [conjTranspose_mul, rightMulMatrix_mul] - map_zero' := by - change 𝐑 (0ᴴ) = 0 - rw [conjTranspose_zero] - have h : rightMul (0 : Matrix m m ℂ) = 0 := by ext X; simp [rightMul] - simp only [rightMulMatrix, h, map_zero] - map_add' A B := by - change 𝐑 ((A + B)ᴴ) = 𝐑 (Aᴴ) + 𝐑 (Bᴴ) - rw [conjTranspose_add, rightMulMatrix_add] - commutes' r := by - change 𝐑 ((algebraMap ℝ (Matrix m m ℂ) r)ᴴ) = algebraMap ℝ _ r - simp only [Algebra.algebraMap_eq_smul_one] - rw [conjTranspose_smul, conjTranspose_one, star_trivial, - rightMulMatrix_smul_real, rightMulMatrix_one] - map_star' A := by - simp only [star_eq_conjTranspose, conjTranspose_conjTranspose, - rightMulMatrix_conjTranspose] - -/-- The `rightMulConjTransposeStarAlgHom` is continuous (finite dimensional). -/ -lemma rightMulConjTransposeStarAlgHom_continuous {m : Type*} [Fintype m] [DecidableEq m] : - Continuous (rightMulConjTransposeStarAlgHom : - Matrix m m ℂ →⋆ₐ[ℝ] Matrix (m × m) (m × m) ℂ) := by - letI : SeminormedAddCommGroup (Matrix m m ℂ) := Matrix.linftyOpSeminormedAddCommGroup - letI : NormedSpace ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedSpace - letI : IsBoundedSMul ℝ (Matrix m m ℂ) := Matrix.linftyOpIsBoundedSMul - letI : SeminormedAddCommGroup (Matrix (m × m) (m × m) ℂ) := - Matrix.linftyOpSeminormedAddCommGroup - letI : NormedSpace ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedSpace - letI : IsBoundedSMul ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpIsBoundedSMul - haveI : FiniteDimensional ℝ (Matrix m m ℂ) := inferInstance - let f : Matrix m m ℂ →ₗ[ℝ] Matrix (m × m) (m × m) ℂ := - (rightMulConjTransposeStarAlgHom : Matrix m m ℂ →⋆ₐ[ℝ] _).toAlgHom.toLinearMap - change Continuous (f : Matrix m m ℂ → _) - exact f.continuous_of_finiteDimensional - -/-- CFC commutes with rightMulMatrix for self-adjoint (Hermitian) matrices. -Uses the `rightMulConjTransposeStarAlgHom` to transport CFC via `StarAlgHom.map_cfc`. -Key insight: For Hermitian B, `Bᴴ = B`, so `Ψ(B) = rightMulMatrix(B)`, -and for self-adjoint `cfc f B`, `Ψ(cfc f B) = rightMulMatrix(cfc f B)`. -/ -lemma rightMulMatrix_cfc {m : Type*} [Fintype m] [DecidableEq m] - (B : Matrix m m ℂ) (hB : IsSelfAdjoint B) (f : ℝ → ℝ) - (hf : ContinuousOn f (spectrum ℝ B) := by cfc_cont_tac) : - 𝐑 (cfc f B) = cfc f (𝐑 B) := by - letI : NormedRing (Matrix m m ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix m m ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m) (A := ℂ) - letI : NormedRing (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix (m × m) (m × m) ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m × m) (A := ℂ) - -- Ψ = rightMulConjTransposeStarAlgHom: B ↦ rightMulMatrix(Bᴴ) - -- StarAlgHom.map_cfc gives: Ψ(cfc f B) = cfc f (Ψ B) - have h_map := StarAlgHom.map_cfc rightMulConjTransposeStarAlgHom f B hf - rightMulConjTransposeStarAlgHom_continuous hB - -- Ψ(B) = rightMulMatrix(Bᴴ) = rightMulMatrix(B) since B is Hermitian - have h_psi_B : (rightMulConjTransposeStarAlgHom : Matrix m m ℂ →⋆ₐ[ℝ] _) B = - 𝐑 B := by - dsimp [rightMulConjTransposeStarAlgHom] - rw [← star_eq_conjTranspose, hB.star_eq] - -- Ψ(cfc f B) = rightMulMatrix((cfc f B)ᴴ) = rightMulMatrix(cfc f B) - -- since cfc f B is self-adjoint - have h_psi_cfc : (rightMulConjTransposeStarAlgHom : Matrix m m ℂ →⋆ₐ[ℝ] _) (cfc f B) = - 𝐑 (cfc f B) := by - dsimp [rightMulConjTransposeStarAlgHom] - rw [← star_eq_conjTranspose, (cfc_predicate f B : IsSelfAdjoint (cfc f B)).star_eq] - rw [h_psi_B, h_psi_cfc] at h_map - exact h_map - -/-- `rightMulMatrix` preserves rpow: `rightMulMatrix (B ^ s) = (rightMulMatrix B) ^ s` -for positive semidefinite `B` and real `s`. -/ -lemma rightMulMatrix_rpow {m : Type*} [Fintype m] [DecidableEq m] - {B : Matrix m m ℂ} (hB : B.PosSemidef) {s : ℝ} (hs : 0 ≤ s) : - 𝐑 (B ^ s) = (𝐑 B) ^ s := by - letI : NormedRing (Matrix m m ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix m m ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m) (A := ℂ) - letI : NormedRing (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedRing - letI : NormedAlgebra ℝ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : NormedAlgebra ℂ (Matrix (m × m) (m × m) ℂ) := Matrix.linftyOpNormedAlgebra - letI : CStarAlgebra (Matrix (m × m) (m × m) ℂ) := by - simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := m × m) (A := ℂ) - have hB0 : (0 : Matrix m m ℂ) ≤ B := by simpa [Matrix.le_iff] using hB - have hRB0 : (0 : Matrix (m × m) (m × m) ℂ) ≤ 𝐑 B := by - simpa [Matrix.le_iff] using rightMulMatrix_posSemidef hB - have hcont_rpow : ContinuousOn (fun x : ℝ => x ^ s) (spectrum ℝ B) := - (Real.continuous_rpow_const hs).continuousOn - rw [CFC.rpow_eq_cfc_real (a := B) (ha := hB0), - CFC.rpow_eq_cfc_real (a := 𝐑 B) (ha := hRB0)] - exact rightMulMatrix_cfc B hB.1.isSelfAdjoint (· ^ s) hcont_rpow - /-- Matrix perspective of a function `f` using the Kubo-Ando style formula. Defined for PSD `L` and PD `R`. -/ noncomputable def matrixPerspective {m : Type*} [Fintype m] [DecidableEq m] @@ -614,25 +343,6 @@ noncomputable def matrixPerspective {m : Type*} [Fintype m] [DecidableEq m] let Rhalf := matrixSqrt R hR.posSemidef Rhalf * fInner * Rhalf -/-- The matrix perspective of a function preserves Hermiticity. -/ -lemma matrixPerspective_isHermitian {m : Type*} [Fintype m] [DecidableEq m] - (f : ℝ → ℝ) (L R : Matrix m m ℂ) (hL : L.PosSemidef) (hR : R.PosDef) : - (matrixPerspective f L R hL hR).IsHermitian := by - classical - unfold matrixPerspective - dsimp - set Rinv := matrixInvSqrt R hR - set inner := Rinvᴴ * L * Rinv - have hinner : inner.IsHermitian := - isHermitian_conjTranspose_mul_mul (B := Rinv) (A := L) hL.1 - set fInner := matrixFunction (fun x => (f x : ℂ)) inner hinner - set Rhalf := matrixSqrt R hR.posSemidef - have hRhalf : Rhalf.IsHermitian := matrixSqrt_isHermitian hR.posSemidef - have hfin : fInner.IsHermitian := - matrixFunction_isHermitian hinner (fun x => f x) - simpa [hRhalf.eq] using - (isHermitian_mul_mul_conjTranspose (B := Rhalf) (A := fInner) hfin) - /-- Congruence lemma for matrixPerspective: equal matrices give equal results regardless of the proof terms. -/ theorem matrixPerspective_congr {m : Type*} [Fintype m] [DecidableEq m] @@ -642,21 +352,6 @@ theorem matrixPerspective_congr {m : Type*} [Fintype m] [DecidableEq m] matrixPerspective f L₁ R₁ hL₁ hR₁ = matrixPerspective f L₂ R₂ hL₂ hR₂ := by cases hL; cases hR; rfl -/-- Perspective for left/right multiplication matrices. -/ -noncomputable def leftRightMatrixPerspective {m : Type*} [Fintype m] [DecidableEq m] - (f : ℝ → ℝ) (A B : Matrix m m ℂ) - (hA : (𝐋 A).PosSemidef) (hB : (𝐑 B).PosDef) : - Matrix (m × m) (m × m) ℂ := - matrixPerspective f (𝐋 A) (𝐑 B) hA hB - -/-- The left-right matrix perspective preserves Hermiticity. -/ -lemma leftRightMatrixPerspective_isHermitian {m : Type*} [Fintype m] [DecidableEq m] - (f : ℝ → ℝ) (A B : Matrix m m ℂ) - (hA : (𝐋 A).PosSemidef) (hB : (𝐑 B).PosDef) : - (leftRightMatrixPerspective f A B hA hB).IsHermitian := by - simpa [leftRightMatrixPerspective] using - (matrixPerspective_isHermitian (m := m × m) f (𝐋 A) (𝐑 B) hA hB) - /-- Cancellation for (c · (S · P))† (c · (S · P)) = c² · (P · R · P) when S² = R. -/ lemma perspective_AA_cancel {n : Type*} [Fintype n] (c w : ℝ) (P S R : Matrix n n ℂ) @@ -860,47 +555,8 @@ theorem matrixPerspective_joint_convex.{v} {m : Type v} [Fintype m] [DecidableEq exact hpsd' simpa [L, R] using hfinal -/-- The sign matrix Σ = I ⊕ (-I) on m ⊕ m is unitary. -/ -lemma signMatrix_mem_unitary {m : Type*} [Fintype m] [DecidableEq m] : - fromBlocks (1 : Matrix m m ℂ) 0 0 (-1 : Matrix m m ℂ) ∈ - unitary (Matrix (m ⊕ m) (m ⊕ m) ℂ) := by - rw [Unitary.mem_iff] - constructor <;> (simp [star_eq_conjTranspose, fromBlocks_conjTranspose, - fromBlocks_multiply, fromBlocks_one]) - -/-- The sign matrix is self-adjoint: Σ* = Σ. -/ -lemma signMatrix_star_eq {m : Type*} [DecidableEq m] : - star (fromBlocks (1 : Matrix m m ℂ) 0 0 (-1 : Matrix m m ℂ)) = - fromBlocks (1 : Matrix m m ℂ) 0 0 (-1 : Matrix m m ℂ) := by - simp [star_eq_conjTranspose, fromBlocks_conjTranspose] - /-! ### Kronecker Product Powers and Perspective Identity -/ -/-- Kronecker product of natural number powers: `(A ⊗ₖ M)^n = A^n ⊗ₖ M^n`. -/ -lemma kronecker_npow {m : Type*} [Fintype m] [DecidableEq m] - (A M : Matrix m m ℂ) (n : ℕ) : - (A ⊗ₖ M) ^ n = (A ^ n) ⊗ₖ (M ^ n) := by - induction n with - | zero => simp - | succ n ih => - -- Work with the explicit Kronecker product type - set K : Matrix (m × m) (m × m) ℂ := A ⊗ₖ M with hK - change K ^ (n + 1) = _ - rw [pow_succ, ih, hK, ← mul_kronecker_mul, ← pow_succ, ← pow_succ] - -/-- The matrixFunction `x ↦ x^(p:ℂ)` equals rpow for PosSemidef matrices with non-negative - eigenvalues and real exponent p. -/ -lemma matrixFunction_cpow_eq_rpow {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.PosSemidef) (p : ℝ) : - matrixFunction (fun x => x ^ (p : ℂ)) A hA.1 = - matrixFunction (fun x => ((x ^ p : ℝ) : ℂ)) A hA.1 := by - unfold matrixFunction - have h_diag : (fun i => (hA.1.eigenvalues i : ℂ) ^ (p : ℂ)) = - (fun i => ((hA.1.eigenvalues i ^ p : ℝ) : ℂ)) := by - funext i - exact (Complex.ofReal_cpow (hA.eigenvalues_nonneg i) p).symm - simp_rw [h_diag] - /-- For commuting PSD L and PD R, the perspective inner matrix simplifies: Rinv† * L * Rinv = L * R^{-1}. Since matrixInvSqrt is Hermitian (self-adjoint), Rinv† = Rinv, From ae10354ce48bd9cbe9a788c257d46012f80032eb Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 10:07:30 +0000 Subject: [PATCH 006/113] refactor(Matrix): remove unused matrixExp and helper lemmas matrixExp and its only consumer matrixExp_trace were unused, as were matrixLog_trace, matrixLog_isHermitian, matrixFunction_neg_id, matrixFunction_sub_const and matrixSqrt_conjTranspose_mul_self_posSemidef. matrixLog itself is kept (consumed by the entropy modules). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Matrix/HermitianFunctionalCalculus.lean | 77 +------------------ 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean b/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean index 50f7dad..4b69049 100644 --- a/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean +++ b/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean @@ -24,7 +24,7 @@ matrices, positive semidefiniteness, block-matrix identities, and the Löwner or `matrixFunction_smul`, `matrixFunction_const`, `matrixFunction_add_const`, etc. - Complex power instances: `matrixFunction_cpow_zero`, `matrixFunction_cpow_one`. - Compatibility with Mathlib's CFC: `matrixFunction_eq_cfc`. -- Special functions: `matrixExp`, `matrixLog`, `matrixSqrt` (via `matrixFunction`). +- Special functions: `matrixLog`, `matrixSqrt` (via `matrixFunction`). ### Hermitian and PSD Structure - `matrixFunction_isHermitian`: f(A) is Hermitian when f maps ℝ to ℝ. @@ -168,13 +168,6 @@ lemma matrixFunction_const {m : Type*} [Fintype m] [DecidableEq m] simpa [star_eq_conjTranspose] using Unitary.coe_mul_star_self hA.eigenvectorUnitary simp [hU] -/-- matrixFunction of negation is negation of A. -/ -lemma matrixFunction_neg_id {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) : - matrixFunction (fun x => -(x : ℂ)) A hA = -A := by - have h : (fun x : ℝ => -(x : ℂ)) = (fun x => -((fun y : ℝ => (y : ℂ)) x)) := rfl - rw [h, matrixFunction_neg, matrixFunction_id] - /-- matrixFunction depends only on the matrix value, not on the specific proof term. If two matrices are equal, their matrixFunctions are equal. -/ lemma matrixFunction_congr {m : Type*} [Fintype m] [DecidableEq m] @@ -366,35 +359,6 @@ lemma matrixFunction_posSemidef {m : Type*} [Fintype m] [DecidableEq m] simp only [conjTranspose_conjTranspose] at key exact key -/-- matrixFunction (f - c) = matrixFunction f - c • I -/ -lemma matrixFunction_sub_const {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℝ) (c : ℝ) : - matrixFunction (fun x => (f x - c : ℂ)) A hA = matrixFunction (fun x => (f x : ℂ)) A hA - (c : ℂ) • 1 := by - classical - let U : Matrix m m ℂ := hA.eigenvectorUnitary - have hU : U * Uᴴ = 1 := by - simpa [U, star_eq_conjTranspose] using Unitary.coe_mul_star_self hA.eigenvectorUnitary - have hdiag : - diagonal (fun i => (f (hA.eigenvalues i) - c : ℂ)) = - diagonal (fun i => (f (hA.eigenvalues i) : ℂ)) - diagonal (fun _ => (c : ℂ)) := by - ext i j - by_cases h : i = j - · subst h - simp - · simp [h] - have hdiagc : diagonal (fun _ => (c : ℂ)) = (c : ℂ) • (1 : Matrix m m ℂ) := by - ext i j - by_cases h : i = j - · subst h - simp - · simp [h] - unfold matrixFunction - rw [hdiag] - simp only [Matrix.mul_sub, Matrix.sub_mul] - rw [hdiagc] - simp only [Matrix.mul_smul, Matrix.smul_mul, Matrix.mul_one] - rw [hU] - /-- Product of two matrixFunctions is the matrixFunction of the pointwise product. Since both share the eigenbasis U, f(A) g(A) = U diag(f(λ) · g(λ)) U*. -/ lemma matrixFunction_mul {m : Type*} [Fintype m] [DecidableEq m] @@ -460,11 +424,6 @@ lemma IsHermitian.trace_ofReal_re {m : Type*} [Fintype m] rw [← trace_conjTranspose, hA.eq] exact (RCLike.conj_eq_iff_re (K := ℂ)).mp h -/-- Matrix exponential for Hermitian matrices via spectral decomposition. -/ -noncomputable def matrixExp {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : Matrix m m ℂ := - matrixFunction (fun x => Real.exp x) A hA - /-- Matrix logarithm for positive definite matrices via spectral decomposition. -/ noncomputable def matrixLog {m : Type*} [Fintype m] [DecidableEq m] (A : Matrix m m ℂ) (hA : A.IsHermitian) : Matrix m m ℂ := @@ -481,30 +440,6 @@ lemma matrixLog_spectral_eq {m : Type*} [Fintype m] [DecidableEq m] unfold matrixLog matrixFunction rfl -/-- Trace of matrix exponential equals sum of exp of eigenvalues. -/ -lemma matrixExp_trace {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : - (matrixExp A hA).trace = ∑ i, (Real.exp (hA.eigenvalues i) : ℂ) := by - unfold matrixExp - rw [matrixFunction_trace] - -/-- Trace of matrix logarithm equals sum of log of eigenvalues. -/ -lemma matrixLog_trace {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : - (matrixLog A hA).trace = ∑ i, (Real.log (hA.eigenvalues i) : ℂ) := by - unfold matrixLog - rw [matrixFunction_trace] - -/-- Matrix logarithm of a Hermitian matrix is Hermitian. -/ -lemma matrixLog_isHermitian {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : - (matrixLog A hA).IsHermitian := by - unfold matrixLog matrixFunction IsHermitian - simp only [conjTranspose_mul, conjTranspose_conjTranspose] - have hDiag := IsHermitian.diagonal_real (fun i => Real.log (hA.eigenvalues i)) - rw [IsHermitian] at hDiag - rw [hDiag, Matrix.mul_assoc] - /-- The matrix logarithm commutes with any `*-`algebra equivalence between complex matrix algebras on PosDef matrices. Continuity is automatic in finite dimensions. -/ theorem matrixLog_map_starAlgEquiv {m n : Type*} [Fintype m] [DecidableEq m] @@ -732,16 +667,6 @@ lemma matrixInvSqrt_commute_of_commute {n : Type*} [Fintype n] [DecidableEq n] have hcommute : Commute R L := hcomm.symm exact Commute.cfc_real hcommute _ -/-- For a PSD matrix `A`, `(A^{1/2})ᴴ * A^{1/2} = A` (since the square root is Hermitian). -/ -lemma matrixSqrt_conjTranspose_mul_self_posSemidef {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.PosSemidef) : - (matrixSqrt A hA)ᴴ * matrixSqrt A hA = A := by - have hherm : (matrixSqrt A hA).IsHermitian := matrixSqrt_isHermitian hA - calc - (matrixSqrt A hA)ᴴ * matrixSqrt A hA = matrixSqrt A hA * matrixSqrt A hA := by - simp [hherm.eq] - _ = A := matrixSqrt_mul_self_posSemidef hA - /-- At p = 0: `matrixFunction (fun x => x ^ 0) A = I`. -/ lemma matrixFunction_cpow_zero {m : Type*} [Fintype m] [DecidableEq m] (A : Matrix m m ℂ) (hA : A.IsHermitian) : From 8684e112c42eabc4c8a7004be20681dc1a24d019 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 10:07:31 +0000 Subject: [PATCH 007/113] refactor(CStarAlgebra): remove unused State helper lemmas Drop star_mul_self_eq_normSq, kernel_degenerate_right, real_eval_nonneg_of_nonneg, real_eval_le_of_le, star_mul_self_ne_zero_of_ne_zero and norm_star_mul_self_eq_sq, none of which had call sites. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem/Algebra/CStarAlgebra/State.lean | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/State.lean b/QuantumSystem/Algebra/CStarAlgebra/State.lean index 791b3e0..559baa5 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/State.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/State.lean @@ -97,9 +97,6 @@ variable (z c : ℂ) /-- The star of a complex number equals its conjugate. -/ lemma star_as_conj : star z = conj z := rfl -/-- The product of a complex number with its conjugate equals the squared norm. -/ -lemma star_mul_self_eq_normSq : star z * z = ‖z‖^2 := Complex.conj_mul' z - /-- Quadratic expansion of `ω(star (z • x + y) * (z • x + y))`. -/ lemma quadratic_expansion : ω (star (z • x + y) * (z • x + y)) = ‖z‖^2 * ω (star x * x) + conj z * ω (star x * y) + z * ω (star y * x) + ω (star y * y) := by @@ -213,11 +210,6 @@ lemma kernel_degenerate_left (a : A) (hx : ω (star x * x) = 0) : ω (star a * x rw [hx, zero_mul] at this exact norm_eq_zero.mp (sq_eq_zero_iff.mp (le_antisymm (by exact_mod_cast this) (sq_nonneg _))) -/-- If `ω(star x * x) = 0`, then `ω(star x * a) = 0` for any `a`. -/ -lemma kernel_degenerate_right (a : A) (hx : ω (star x * x) = 0) : ω (star x * a) = 0 := by - rw [conj_sym (ω := ω) (x := a) (y := x), kernel_degenerate_left (ω := ω) (x := x) (a := a) hx] - simp - /-- If `ω(star x * x) = 0` and `ω(star y * y) = 0`, then `ω(star (x + y) * (x + y)) = 0`. -/ lemma kernel_closed_under_add (hx : ω (star x * x) = 0) (hy : ω (star y * y) = 0) : ω (star (x + y) * (x + y)) = 0 := by calc ω (star (x + y) * (x + y)) @@ -320,23 +312,6 @@ lemma star_mul_bound (a b : A) : _ = ω (‖a‖ ^ 2 • (star b * b)) := by norm_cast _ = ω (star b * star a * a * b) + RCLike.ofReal (r : ℝ) := hr -/-- Real parts of a state are nonnegative on positive elements. -/ -lemma real_eval_nonneg_of_nonneg {a : A} (ha : 0 ≤ a) : 0 ≤ (ω a).re := by - obtain ⟨r, hr⟩ := nonneg_of_nonneg (ω := ω) ha - have hr_nonneg : 0 ≤ (r : ℝ) := by exact_mod_cast r.property - have hr_rewrite : (ω a).re = (r : ℝ) := by rw [hr]; simp - exact hr_rewrite ▸ hr_nonneg - -/-- States are monotone on real parts: `a ≤ b` implies `(ω a).re ≤ (ω b).re`. -/ -lemma real_eval_le_of_le {a b : A} (hab : a ≤ b) : (ω a).re ≤ (ω b).re := by - obtain ⟨r, hr⟩ := monotone (ω := ω) hab - have h_re : (ω b).re = (ω a).re + (r : ℝ) := by - have := congrArg Complex.re hr - simpa [Complex.add_re, RCLike.ofReal_re] using this - have hr_nonneg : 0 ≤ (r : ℝ) := by exact_mod_cast r.property - have h_le : (ω a).re ≤ (ω a).re + (r : ℝ) := le_add_of_nonneg_right hr_nonneg - exact h_re ▸ h_le - /-- If `ω(star x * x) = 0`, then `ω(x) = 0`. This uses the approximate unit. -/ lemma kernel_vanish_on_elem (hx : ω (star x * x) = 0) : ω x = 0 := by -- Prove by showing ‖ω(x)‖ < ε for all ε > 0 @@ -413,19 +388,4 @@ lemma approx_unit_cauchy_schwarz_bound (a e : A) (he_star : star e = e) (he_norm · simpa [h_ee_real, RCLike.ofReal_re] using h_ee_bound _ = (ω (star a * a)).re := mul_one _ - -/-- For nonzero `a`, the element `star a * a` is also nonzero. -/ -lemma star_mul_self_ne_zero_of_ne_zero {a : A} (ha : a ≠ 0) : star a * a ≠ 0 := by - rw [← norm_ne_zero_iff] at ha ⊢ - rw [CStarRing.norm_star_mul_self] - intro h - have : ‖a‖ = 0 := by nlinarith [sq_nonneg ‖a‖] - exact ha this - - -/-- The norm of `star a * a` equals the square of the norm of `a`. -/ -lemma norm_star_mul_self_eq_sq (a : A) : ‖star a * a‖ = ‖a‖ ^ 2 := by - rw [pow_two] - exact CStarRing.norm_star_mul_self - end State From a40c3492b64d0f13a2fd204b0d3c8cdf2ddaa76f Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 10:07:48 +0000 Subject: [PATCH 008/113] refactor(ForMathlib): remove modules unused by the project Adjoint, l2Space, ContinuousFunctionalCalculus.Abs (operator absolute value), ContinuousFunctionalCalculus.PartialIsometry and SpecialFunctions.Pow.Real are imported only by the aggregate root and consumed by no module. The polar- decomposition pair (Abs + PartialIsometry) in particular was unwired scaffolding. Drop the files and their aggregate imports (~802 lines). Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 5 - .../Analysis/InnerProductSpace/Adjoint.lean | 30 -- .../Analysis/InnerProductSpace/l2Space.lean | 67 ---- .../ContinuousFunctionalCalculus/Abs.lean | 212 ----------- .../PartialIsometry.lean | 341 ------------------ .../Analysis/SpecialFunctions/Pow/Real.lean | 152 -------- 6 files changed, 807 deletions(-) delete mode 100644 QuantumSystem/ForMathlib/Analysis/InnerProductSpace/Adjoint.lean delete mode 100644 QuantumSystem/ForMathlib/Analysis/InnerProductSpace/l2Space.lean delete mode 100644 QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Abs.lean delete mode 100644 QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PartialIsometry.lean delete mode 100644 QuantumSystem/ForMathlib/Analysis/SpecialFunctions/Pow/Real.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 78272c2..ef19c20 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -42,19 +42,14 @@ public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Ideal public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.NonUnital public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Unital public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.WeakDual -public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.Adjoint public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.DiagonalAmplification public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.InvariantSubspace -public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.l2Space public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.StrongOperatorTopology public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.WeakOperatorTopology public import QuantumSystem.ForMathlib.Analysis.Matrix.Basic public import QuantumSystem.ForMathlib.Analysis.Matrix.Hermitian public import QuantumSystem.ForMathlib.Analysis.Matrix.Order -public import QuantumSystem.ForMathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.Abs -public import QuantumSystem.ForMathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.PartialIsometry -public import QuantumSystem.ForMathlib.Analysis.SpecialFunctions.Pow.Real public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.StarAlgEquiv public import QuantumSystem.ForMathlib.LinearAlgebra.Span.Def diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/Adjoint.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/Adjoint.lean deleted file mode 100644 index b8fe2f5..0000000 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/Adjoint.lean +++ /dev/null @@ -1,30 +0,0 @@ -module - -public import Mathlib.Analysis.InnerProductSpace.Adjoint - -/-! -# Self-adjoint operators on inner product spaces - -This file contains results about self-adjoint operators on inner product spaces. --/ - -@[expose] public section - -open scoped InnerProductSpace - -variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℂ E] [CompleteSpace E] - -namespace ContinuousLinearMap - -/-- For a self-adjoint operator T, if ⟪Tx, x⟫ = 0 for all x, then T = 0. -This is a corollary of the polarization identity `LinearMap.IsSymmetric.inner_map_self_eq_zero`. -/ -theorem IsSelfAdjoint.eq_zero_of_inner_map_self_eq_zero {T : E →L[ℂ] E} - (hsa : IsSelfAdjoint T) (h : ∀ x, ⟪T x, x⟫_ℂ = 0) : T = 0 := by - have hT_sym : (T : E →ₗ[ℂ] E).IsSymmetric := hsa.isSymmetric - have h' : (T : E →ₗ[ℂ] E) = 0 := hT_sym.inner_map_self_eq_zero.mp h - ext x - have := congrFun (congrArg DFunLike.coe h') x - simp only [LinearMap.zero_apply, ContinuousLinearMap.coe_coe] at this - exact this - -end ContinuousLinearMap diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/l2Space.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/l2Space.lean deleted file mode 100644 index ec4feaa..0000000 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/l2Space.lean +++ /dev/null @@ -1,67 +0,0 @@ -module - -public import Mathlib.Analysis.InnerProductSpace.l2Space - -/-! -# Helper lemmas for Hilbert bases and Parseval identity - -This file provides additional lemmas for Hilbert bases that extend Mathlib's `l2Space`. - -## Main results - -* `inner_mul_inner_eq_norm_sq`: For a Hilbert basis, `⟪x, bᵢ⟫ * ⟪bᵢ, x⟫ = ‖⟪bᵢ, x⟫‖²` -* `HilbertBasis.norm_sq_eq_tsum_norm_sq_inner'`: Parseval identity `‖x‖² = ∑ᵢ ‖⟪bᵢ, x⟫‖²` -* `HilbertBasis.summable_norm_sq_inner'`: The sequence `‖⟪bᵢ, x⟫‖²` is summable --/ - -@[expose] public section - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] -variable {ι : Type*} - -/-- For a Hilbert basis, `⟪x, bᵢ⟫ * ⟪bᵢ, x⟫ = ‖⟪bᵢ, x⟫‖²` as complex numbers. -/ -theorem inner_mul_inner_eq_norm_sq (b : HilbertBasis ι ℂ H) (x : H) (i : ι) : - inner (𝕜 := ℂ) x (b i) * inner (𝕜 := ℂ) (b i) x = (‖inner (𝕜 := ℂ) (b i) x‖^2 : ℂ) := by - rw [← inner_conj_symm (𝕜 := ℂ)] - have h : ↑(Complex.normSq (inner ℂ (b i) x)) = (starRingEnd ℂ) (inner ℂ (b i) x) * inner ℂ (b i) x := - Complex.normSq_eq_conj_mul_self - rw [← h] - norm_cast - exact Complex.normSq_eq_norm_sq _ - -/-- Helper: real part of a real power. -/ -private lemma ofReal_pow_re (r : ℝ) (n : ℕ) : ((r : ℂ)^n).re = r^n := by - induction n with - | zero => simp - | succ n ih => - rw [pow_succ, pow_succ] - rw [Complex.mul_re, Complex.ofReal_re, Complex.ofReal_im, ih] - ring - -/-- Parseval identity for Hilbert bases: `‖x‖² = ∑ᵢ ‖⟪bᵢ, x⟫‖²`. -/ -theorem HilbertBasis.norm_sq_eq_tsum_norm_sq_inner' (b : HilbertBasis ι ℂ H) (x : H) : - ‖x‖^2 = ∑' i, ‖inner (𝕜 := ℂ) (b i) x‖^2 := by - have h := b.tsum_inner_mul_inner x x - simp_rw [inner_mul_inner_eq_norm_sq b x] at h - have h2 : (inner (𝕜 := ℂ) x x).re = ‖x‖^2 := by - rw [inner_self_eq_norm_sq_to_K] - exact ofReal_pow_re _ 2 - have h3 : (∑' i, (‖inner (𝕜 := ℂ) (b i) x‖^2 : ℂ)).re = ∑' i, ‖inner (𝕜 := ℂ) (b i) x‖^2 := by - rw [Complex.re_tsum] - · congr 1 - ext i - exact ofReal_pow_re _ 2 - · have := b.summable_inner_mul_inner x x - simp_rw [inner_mul_inner_eq_norm_sq b x] at this - exact this - rw [← h2, ← h, h3] - -/-- The sequence `‖⟪bᵢ, x⟫‖²` is summable for any Hilbert basis. -/ -theorem HilbertBasis.summable_norm_sq_inner' (b : HilbertBasis ι ℂ H) (x : H) : - Summable (fun i => ‖inner (𝕜 := ℂ) (b i) x‖^2) := by - have hsummable := b.summable_inner_mul_inner x x - simp_rw [inner_mul_inner_eq_norm_sq b x] at hsummable - obtain ⟨s, hs⟩ := hsummable - have hs_re := Complex.hasSum_re hs - simp_rw [ofReal_pow_re] at hs_re - exact hs_re.summable diff --git a/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Abs.lean b/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Abs.lean deleted file mode 100644 index 95f98ae..0000000 --- a/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Abs.lean +++ /dev/null @@ -1,212 +0,0 @@ -module - -public import Mathlib.Analysis.InnerProductSpace.StarOrder -public import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.Abs - -open scoped InnerProductSpace -open ContinuousLinearMap - -@[expose] public section - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-! ### Absolute value of an operator -/ - -section AbsoluteValue - -/-- `T†T` is always a non-negative operator (in the Loewner order). -/ -lemma adjoint_mul_self_nonneg (T : H →L[ℂ] H) : 0 ≤ T.adjoint * T := by - rw [nonneg_iff_isPositive] - exact isPositive_adjoint_comp_self T - -/-- The absolute value of a bounded linear operator `T`, defined as `√(T†T)`. -This uses the continuous functional calculus for positive operators. -This equals `CFC.abs T` since `star T = T.adjoint` for ContinuousLinearMap. -/ -noncomputable def absoluteValue (T : H →L[ℂ] H) : H →L[ℂ] H := - CFC.sqrt (T.adjoint * T) - -lemma absoluteValue_eq_cfc_abs (T : H →L[ℂ] H) : absoluteValue T = CFC.abs T := by - simp only [absoluteValue, CFC.abs, ContinuousLinearMap.star_eq_adjoint] - -/-- The absolute value of an operator is non-negative. -/ -lemma absoluteValue_nonneg (T : H →L[ℂ] H) : 0 ≤ absoluteValue T := by - rw [absoluteValue_eq_cfc_abs] - exact CFC.abs_nonneg T - -/-- The absolute value of an operator is self-adjoint. -/ -lemma absoluteValue_isSelfAdjoint (T : H →L[ℂ] H) : IsSelfAdjoint (absoluteValue T) := by - have h := absoluteValue_nonneg T - rw [nonneg_iff_isPositive] at h - exact h.isSelfAdjoint - -/-- The absolute value of an operator is positive (in the sense of IsPositive). -/ -lemma absoluteValue_isPositive (T : H →L[ℂ] H) : (absoluteValue T).IsPositive := by - rw [← nonneg_iff_isPositive] - exact absoluteValue_nonneg T - -/-- `|T|² = T†T` -/ -lemma absoluteValue_sq (T : H →L[ℂ] H) : absoluteValue T * absoluteValue T = T.adjoint * T := by - unfold absoluteValue - exact CFC.sqrt_mul_sqrt_self _ (adjoint_mul_self_nonneg T) - -/-- The absolute value of the zero operator is zero. -/ -lemma absoluteValue_zero : absoluteValue (0 : H →L[ℂ] H) = 0 := by - unfold absoluteValue - have h : (0 : H →L[ℂ] H).adjoint = 0 := by ext; simp - simp only [h, zero_mul] - exact CFC.sqrt_zero - -/-- For a positive operator T, the absolute value equals T itself. -/ -lemma absoluteValue_of_nonneg {T : H →L[ℂ] H} (hT : 0 ≤ T) : absoluteValue T = T := by - unfold absoluteValue - have hpos : T.IsPositive := by rwa [← nonneg_iff_isPositive] - have hsa : T.adjoint = T := hpos.isSelfAdjoint.adjoint_eq - rw [hsa, ← sq] - exact CFC.sqrt_sq T hT - -lemma absoluteValue_smul (c : ℂ) (T : H →L[ℂ] H) : - absoluteValue (c • T) = ‖c‖ • absoluteValue T := by - letI : IsScalarTower ℝ ℂ H := ⟨fun r z x => by - rw [show (r • z : ℂ) = (r : ℂ) * z from rfl, mul_smul] - rfl⟩ - letI : IsScalarTower ℝ ℂ (H →L[ℂ] H) := ⟨fun r z S => by - apply ContinuousLinearMap.ext - intro x - change (r • z) • S x = r • z • S x - exact smul_assoc r z (S x)⟩ - rw [absoluteValue_eq_cfc_abs, absoluteValue_eq_cfc_abs] - exact CFC.abs_smul c T - -lemma norm_absoluteValue_eq_norm (T : H →L[ℂ] H) (x : H) : ‖absoluteValue T x‖ = ‖T x‖ := by - have hP := absoluteValue_isSelfAdjoint T - let P := absoluteValue T - have h_inner : ‖P x‖^2 = ‖T x‖^2 := by - simp only [← inner_self_eq_norm_sq (𝕜 := ℂ) _] - change (⟪P x, P x⟫_ℂ).re = (⟪T x, T x⟫_ℂ).re - calc (⟪P x, P x⟫_ℂ).re - = (⟪P.adjoint (P x), x⟫_ℂ).re := by rw [adjoint_inner_left] - _ = (⟪P (P x), x⟫_ℂ).re := by rw [hP.adjoint_eq] - _ = (⟪(P * P) x, x⟫_ℂ).re := rfl - _ = (⟪(T.adjoint * T) x, x⟫_ℂ).re := by rw [absoluteValue_sq] - _ = (⟪T.adjoint (T x), x⟫_ℂ).re := rfl - _ = (⟪T x, T x⟫_ℂ).re := by rw [adjoint_inner_left] - exact (sq_eq_sq₀ (norm_nonneg _) (norm_nonneg _)).mp h_inner - -lemma absoluteValue_ker_eq_ker (T : H →L[ℂ] H) : - LinearMap.ker (absoluteValue T).toLinearMap = LinearMap.ker T.toLinearMap := by - ext x - simp only [LinearMap.mem_ker, ContinuousLinearMap.coe_coe] - constructor - · intro h - rw [← norm_eq_zero, ← norm_absoluteValue_eq_norm, h, norm_zero] - · intro h - rw [← norm_eq_zero, norm_absoluteValue_eq_norm, h, norm_zero] - -lemma absoluteValue_adjoint_sq (T : H →L[ℂ] H) : - absoluteValue T.adjoint * absoluteValue T.adjoint = T * T.adjoint := by - simpa [adjoint_adjoint] using (absoluteValue_sq (T := T.adjoint)) - -/-! ### Polar decomposition identities -/ - -/-- (U|T|U†)² = T·T† when T = U|T| and U†U|T| = |T| -/ -lemma conjugate_abs_sq_eq {T U : H →L[ℂ] H} - (hT_polar : T = U * absoluteValue T) - (hU_adj_U_abs : U.adjoint * U * absoluteValue T = absoluteValue T) : - (U * absoluteValue T * U.adjoint) * (U * absoluteValue T * U.adjoint) = T * T.adjoint := by - have h2 : T.adjoint = absoluteValue T * U.adjoint := by - have h_adj : (U * absoluteValue T).adjoint = (absoluteValue T).adjoint * U.adjoint := by - change star (U * absoluteValue T) = star (absoluteValue T) * star U - rw [star_mul] - conv_lhs => rw [hT_polar] - rw [h_adj, (absoluteValue_isSelfAdjoint T).adjoint_eq] - set absT := absoluteValue T with h_absT_def - -- (U|T|U†)² = U|T|(U†U)|T|U† = U|T|²U† - have lhs_eq : (U * absT * U.adjoint) * (U * absT * U.adjoint) - = U * absT * absT * U.adjoint := by - have hU_adj_U_absT : U.adjoint * U * absT = absT := hU_adj_U_abs - calc (U * absT * U.adjoint) * (U * absT * U.adjoint) - = U * absT * (U.adjoint * U * absT) * U.adjoint := by simp only [mul_assoc] - _ = U * absT * absT * U.adjoint := by rw [hU_adj_U_absT] - -- T·T† = (U|T|)(|T|U†) = U|T|²U† - have h2' : T.adjoint = absT * U.adjoint := h2 - have rhs_eq : T * T.adjoint = U * absT * absT * U.adjoint := by - calc T * T.adjoint - = T * (absT * U.adjoint) := by rw [h2'] - _ = (U * absT) * (absT * U.adjoint) := by rw [hT_polar] - _ = U * absT * absT * U.adjoint := by simp only [mul_assoc] - rw [lhs_eq, rhs_eq] - -/-- U|T|U† is a positive operator when |T| is the absolute value -/ -lemma conjugate_abs_nonneg {T U : H →L[ℂ] H} : - 0 ≤ U * absoluteValue T * U.adjoint := by - set absT := absoluteValue T with h_absT_def - rw [ContinuousLinearMap.le_def] - constructor - · -- Symmetry: (U|T|U†)† = U|T|†U†† = U|T|U† - simp only [sub_zero] - change ((U * absT * U.adjoint) : H →L[ℂ] H).toLinearMap.IsSymmetric - have h_self_adj : IsSelfAdjoint (U * absT * U.adjoint) := by - rw [isSelfAdjoint_iff'] - -- Need: (U * absT * U†)† = U * absT * U† - have step1 : (U * absT * U.adjoint).adjoint = U.adjoint.adjoint * (U * absT).adjoint := by - change star _ = star (adjoint U) * star (U * absT) - rw [star_mul] - have step2 : (U * absT).adjoint = absT.adjoint * U.adjoint := by - change star _ = star absT * star U - rw [star_mul] - rw [step1, step2, ContinuousLinearMap.adjoint_adjoint] - rw [h_absT_def, (absoluteValue_isSelfAdjoint T).adjoint_eq, ← h_absT_def] - simp only [mul_assoc] - exact h_self_adj.isSymmetric - · intro x - simp only [ContinuousLinearMap.reApplyInnerSelf, sub_zero, mul_apply] - -- Goal: 0 ≤ re⟨U(|T|(U†x)), x⟩ = re⟨|T|(U†x), U†x⟩ - have eq : ⟪U (absT (U.adjoint x)), x⟫_ℂ = ⟪absT (U.adjoint x), U.adjoint x⟫_ℂ := by - rw [← adjoint_inner_left U.adjoint, ContinuousLinearMap.adjoint_adjoint] - rw [eq, h_absT_def] - have h_abs_pos := absoluteValue_isPositive T - rw [ContinuousLinearMap.isPositive_def] at h_abs_pos - have h := h_abs_pos.2 (U.adjoint x) - simp only [ContinuousLinearMap.reApplyInnerSelf_apply] at h - exact h - -/-- For polar decomposition T = U|T| with U partial isometry, |T†| = U|T|U† -/ -lemma absoluteValue_adjoint_eq_conjugate_by_partial_isometry {T U : H →L[ℂ] H} - (hT_polar : T = U * absoluteValue T) - (hU_adj_U_abs : U.adjoint * U * absoluteValue T = absoluteValue T) : - absoluteValue T.adjoint = U * absoluteValue T * U.adjoint := by - set absT := absoluteValue T with h_absT_def - have h_sq : (U * absT * U.adjoint) * (U * absT * U.adjoint) = T * T.adjoint := - conjugate_abs_sq_eq hT_polar hU_adj_U_abs - have h_pos : 0 ≤ U * absT * U.adjoint := conjugate_abs_nonneg - have h_absT_adj_sq : absoluteValue T.adjoint * absoluteValue T.adjoint = T * T.adjoint := - absoluteValue_adjoint_sq T - have h_both_positive : 0 ≤ absoluteValue T.adjoint := absoluteValue_nonneg T.adjoint - -- Both U|T|U† and |T†| are positive with same square, so equal by sqrt uniqueness - calc absoluteValue T.adjoint - = CFC.sqrt (absoluteValue T.adjoint * absoluteValue T.adjoint) := - (CFC.sqrt_sq (absoluteValue T.adjoint) h_both_positive).symm - _ = CFC.sqrt (T * T.adjoint) := by rw [h_absT_adj_sq] - _ = CFC.sqrt (U * absT * U.adjoint * (U * absT * U.adjoint)) := by - rw [← h_sq] - _ = U * absT * U.adjoint := - CFC.sqrt_sq (U * absT * U.adjoint) h_pos - -/-- S x = 0 when x ∈ ker |T| and S = √|T| -/ -lemma cfc_sqrt_absoluteValue_ker {T : H →L[ℂ] H} - (x : H) (hx : absoluteValue T x = 0) : - CFC.sqrt (absoluteValue T) x = 0 := by - let S := CFC.sqrt (absoluteValue T) - have hS_sq : S * S = absoluteValue T := CFC.sqrt_mul_sqrt_self _ (absoluteValue_nonneg T) - have hS_sa : IsSelfAdjoint S := (CFC.sqrt_nonneg _).isSelfAdjoint - have h_norm_sq : ‖S x‖^2 = (⟪absoluteValue T x, x⟫_ℂ).re := by - have h1 : ‖S x‖^2 = Complex.re ⟪S x, S x⟫_ℂ := by - rw [(inner_self_eq_norm_sq (𝕜 := ℂ) (S x)).symm]; simp - calc ‖S x‖^2 = Complex.re ⟪S x, S x⟫_ℂ := h1 - _ = Complex.re ⟪S (S x), x⟫_ℂ := by rw [← adjoint_inner_left, hS_sa.adjoint_eq] - _ = Complex.re ⟪(S * S) x, x⟫_ℂ := by rfl - _ = Complex.re ⟪absoluteValue T x, x⟫_ℂ := by rw [hS_sq] - rw [hx, inner_zero_left, Complex.zero_re] at h_norm_sq - exact norm_eq_zero.mp (eq_zero_of_pow_eq_zero h_norm_sq) - -end AbsoluteValue diff --git a/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PartialIsometry.lean b/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PartialIsometry.lean deleted file mode 100644 index e4d4ef7..0000000 --- a/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PartialIsometry.lean +++ /dev/null @@ -1,341 +0,0 @@ -module - -public import Mathlib.Analysis.InnerProductSpace.Adjoint - -@[expose] public section - -open ContinuousLinearMap InnerProductSpace - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- A continuous linear map `U` is a partial isometry if `U†U` is a projection. -/ -def IsPartialIsometry (U : H →L[ℂ] H) : Prop := - U.adjoint * U * (U.adjoint * U) = U.adjoint * U - -/-- Alternative characterization: U is a partial isometry iff UU†U = U. -/ -lemma isPartialIsometry_iff (U : H →L[ℂ] H) : - IsPartialIsometry U ↔ U * U.adjoint * U = U := by - constructor - · intro h - -- U†U is a projection P. - -- We want to show U P = U. - -- Is equivalent to U (1 - P) = 0. - -- || U (1 - P) x ||² = ⟨ (1-P)x, U† U (1-P) x ⟩ = ⟨ (1-P)x, P (1-P) x ⟩ = 0 - let P := U.adjoint * U - have hP : P * P = P := h - have h_orth : U * (1 - P) = 0 := by - ext x - refine norm_eq_zero.mp ?_ - have h0 : ‖(U * (1 - P)) x‖ ^ 2 = 0 := by - rw [← inner_self_eq_norm_sq (𝕜 := ℂ) (x := (U * (1 - P)) x)] - change Complex.re ⟪U ((1 - P) x), U ((1 - P) x)⟫_ℂ = 0 - rw [← adjoint_inner_right] - -- rewrite `U† (U ((1 - P) x))` as `P ((1 - P) x)` - simp only [P] - -- U† U (x - P x) = P (x - P x) = P x - P² x = P x - P x = 0 - have hPP : P (P x) = P x := by - simpa [P, ContinuousLinearMap.mul_apply, mul_assoc] using - congrArg (fun T => T x) hP - have h1 : (1 - P) x = x - P x := by - simp [sub_eq_add_neg] - have h2 : P ((1 - P) x) = P x - P (P x) := by - rw [h1, map_sub] - have h3 : U.adjoint (U (x - P x)) = P (x - P x) := by rfl - rw [h1, h3, map_sub, hPP, sub_self, inner_zero_right, Complex.zero_re] - exact (sq_eq_zero_iff.mp h0) - have h_orth' : U * (P - 1) = 0 := by - calc - U * (P - 1) = U * (-(1 - P)) := by - simp [sub_eq_add_neg, add_comm] - _ = - (U * (1 - P)) := by - simp [sub_eq_add_neg, mul_add, mul_one, add_comm] - _ = 0 := by simp [h_orth] - -- `U * (P - 1) = 0` rewrites to `U * U† * U - U = 0` - have h_orth'' : U * U.adjoint * U - U = 0 := by - simpa [P, mul_sub, mul_assoc, mul_one] using h_orth' - have h_eq : U * U.adjoint * U = U := by - calc - U * U.adjoint * U = (U * U.adjoint * U - U) + U := by abel - _ = 0 + U := by simp [h_orth''] - _ = U := by simp - exact h_eq - · intro h - -- We want IsPartialIsometry U, i.e., U† U U† U = U† U - have h_adj : U.adjoint * U * U.adjoint = U.adjoint := by - -- take adjoint of `U * U† * U = U` - simpa [mul_def, adjoint_comp, adjoint_adjoint, mul_assoc] using - congrArg ContinuousLinearMap.adjoint h - calc - U.adjoint * U * (U.adjoint * U) - = (U.adjoint * U * U.adjoint) * U := by simp [mul_assoc] - _ = U.adjoint * U := by simp [h_adj] - -/-- The adjoint of a partial isometry is a partial isometry. -/ -lemma IsPartialIsometry.adjoint {U : H →L[ℂ] H} (hU : IsPartialIsometry U) : - IsPartialIsometry U.adjoint := by - rw [isPartialIsometry_iff] at hU ⊢ - -- We want U† U†† U† = U†. - -- i.e., U† U U† = U†. - rw [adjoint_adjoint] - -- We know U U† U = U. Taking adjoint gives U† U U† = U†. - -- take adjoint of `U * U† * U = U` - simpa [mul_def, adjoint_comp, adjoint_adjoint, mul_assoc] using - congrArg ContinuousLinearMap.adjoint hU - -/-- A partial isometry is an isometry on the orthogonal complement of its kernel. - Note: (ker U)ᗮ = range U†. -/ -lemma IsPartialIsometry.norm_of_mem_initialSpace {U : H →L[ℂ] H} - (hU : IsPartialIsometry U) (x : H) (hx : x ∈ (LinearMap.ker U.toLinearMap)ᗮ) : - ‖U x‖ = ‖x‖ := by - -- ‖U x‖² = ⟨x, U† U x⟩. - -- If x ∈ (ker U)ᗮ, then x ∈ range U† (since range U† is closed? In finite dim yes. - -- In general, (ker U)ᗮ = closure (range U†). - -- Wait, U† U is a projection onto range U†. - -- Let P = U† U. If hU, P is a projection. - -- range P = range U† (standard fact for P = T* T? No, range P ⊆ range U†. Also range U† U ⊆ range U†. - -- Actually range U† = range (U† U) because range U† U ⊆ range U†. - -- And if y = U† z, U† U y = U† U U† z = U† z = y using U U† U = U. - -- So range U† ⊆ range P. Thus range P = range U†. - -- P is an orthogonal projection onto range U†. - -- So for x ∈ range U†, P x = x. - -- ‖U x‖² = ⟨x, P x⟩ = ⟨x, x⟩ = ‖x‖². - - -- But argument x is in (ker U)ᗮ. - -- We need to know P is the projection onto (ker U)ᗮ. - -- ker P = ker (U† U) = ker U. - -- So range P = (ker P)ᗮ = (ker U)ᗮ. - -- So x ∈ range P. - let P := U.adjoint * U - have hP_proj : P * P = P := hU - -- We want to show ⟨x, P x⟩ = ⟨x, x⟩ - have h_P_mem : P x = x := by - -- P is orthogonal projection onto range P. - -- range P = (ker P)ᗮ = (ker U)ᗮ. - -- Wait, P is self-adjoint idempotent, so it is orthogonal projection onto range P. - -- range P = (ker P)ᗮ because P is self-adjoint. - -- ker P = ker U? - -- ker U ⊆ ker P: U x = 0 → U† U x = 0. - -- ker P ⊆ ker U: U† U x = 0 → ⟨x, U† U x⟩ = 0 → ‖U x‖² = 0 → U x = 0. - -- So ker P = ker U. - -- Therefore range P = (ker U)ᗮ. - -- Since x ∈ (ker U)ᗮ, x ∈ range P. - -- So P x = x. - - -- Let's prove ker P = ker U formally. - have h_ker : LinearMap.ker P.toLinearMap = LinearMap.ker U.toLinearMap := by - ext y - simp only [LinearMap.mem_ker] -- `P.toLinearMap y` is definitionaly `P y` - constructor - · intro hy - -- U† U y = 0 ⇒ U y = 0 - have h0 : ‖U y‖ ^ 2 = 0 := by - rw [← inner_self_eq_norm_sq (𝕜 := ℂ) (x := U y)] - rw [← adjoint_inner_right] - -- `U† (U y) = P y = 0` - have hy' : U.adjoint (U y) = 0 := by - simpa [P, ContinuousLinearMap.mul_apply] using hy - simp [hy', inner_zero_right] - have h1 : ‖U y‖ = 0 := (sq_eq_zero_iff.mp h0) - exact (norm_eq_zero.mp h1) - · intro hy - dsimp [P] - calc - (U.adjoint) (U y) = U.adjoint 0 := by - have hy' : U y = 0 := by simpa using hy - simp [hy'] - _ = 0 := by simp - -- P is self-adjoint - have h_sa : IsSelfAdjoint P := by - -- `(U†U)† = U†U` - simpa [P, star_eq_adjoint] using (IsSelfAdjoint.star_mul_self U) - -- range P is closed? - -- range P = ker(1-P). Since P is continuous, ker(1-P) is closed. - -- So range P is closed. - -- For orthogonal projection P, range P = (ker P)ᗮ. - -- We need this fact from Mathlib. `LinearMap.isProj_iff_idempotent_and_...`? - -- Actually `OrthogonalProjection` exists. - -- But we defined IsPartialIsometry manually. - - -- Let's rely on P x = x iff x ∈ (ker P)ᗮ. - -- Mathlib has `orthogonalProjection_eq_self_iff`. - -- We can construct the `orthogonalProjection` structure from P. - - -- Or just prove manually: - -- If x ∈ (ker P)ᗮ, then P x - x ∈ ? - -- P(P x - x) = P x - P x = 0. So P x - x ∈ ker P. - -- Also P x - x ∈ range P + x? No. - -- P x ∈ range P = (ker P)ᗮ. - -- So P x - x ∈ (ker P)ᗮ. - -- The only vector in intersection of ker P and (ker P)ᗮ is 0. - -- So P x = x. - - -- Use the idempotent+symmetry characterization to identify the range. - have hP_idem : IsIdempotentElem P := hP_proj - have hP_symm : (P : H →ₗ[ℂ] H).IsSymmetric := - (ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric).1 h_sa - have h_orth : (LinearMap.range P.toLinearMap)ᗮ = LinearMap.ker P.toLinearMap := - (LinearMap.IsIdempotentElem.isSymmetric_iff_orthogonal_range hP_idem.toLinearMap).1 hP_symm - have h_range_closed : IsClosed (LinearMap.range P.toLinearMap : Set H) := - (IsIdempotentElem.isClosed_range (p := P) hP_idem) - -- Hence (ker P)ᗮ = range P - have h_eq_range : (LinearMap.ker P.toLinearMap)ᗮ = LinearMap.range P.toLinearMap := by - calc - (LinearMap.ker P.toLinearMap)ᗮ = (LinearMap.range P.toLinearMap)ᗮᗮ := by - simp [h_orth] - _ = (LinearMap.range P.toLinearMap).topologicalClosure := by - simpa using (Submodule.orthogonal_orthogonal_eq_closure - (K := LinearMap.range P.toLinearMap)) - _ = LinearMap.range P.toLinearMap := - (IsClosed.submodule_topologicalClosure_eq h_range_closed) - -- rewrite `hx` into membership in range P - have hx' : x ∈ (LinearMap.ker P.toLinearMap)ᗮ := by - simpa [h_ker] using hx - have hx_range : x ∈ LinearMap.range P.toLinearMap := by - simpa [h_eq_range] using hx' - rcases hx_range with ⟨y, rfl⟩ - -- `P (P y) = P y` - simpa [P, mul_assoc, ContinuousLinearMap.mul_apply] using - congrArg (fun T => T y) hP_proj - -- Now compute squared norms using `P x = x`. - have hsq : ‖U x‖ ^ 2 = ‖x‖ ^ 2 := by - rw [← inner_self_eq_norm_sq (𝕜 := ℂ) (x := U x)] - change Complex.re ⟪U x, U x⟫_ℂ = ‖x‖ ^ 2 - rw [← adjoint_inner_right] - have hPx : U.adjoint (U x) = P x := by rfl - rw [hPx, h_P_mem] - simpa using (inner_self_eq_norm_sq (𝕜 := ℂ) (x := x)) - have hnonneg1 : 0 ≤ ‖U x‖ := norm_nonneg _ - have hnonneg2 : 0 ≤ ‖x‖ := norm_nonneg _ - have hsq' : ‖U x‖ = ‖x‖ := by - have h' := sq_eq_sq_iff_eq_or_eq_neg.mp (by simpa [pow_two] using hsq) - cases h' with - | inl h => exact h - | inr h => nlinarith - exact hsq' - -/-- For a partial isometry U, U†U = id on (ker U)ᗮ -/ -lemma IsPartialIsometry.adjoint_mul_self_apply_of_mem_ker_orthogonal {U : H →L[ℂ] H} - (hU : IsPartialIsometry U) - (x : H) (hx : x ∈ (LinearMap.ker U.toLinearMap)ᗮ) : - U.adjoint (U x) = x := by - let P := U.adjoint * U - have hP_proj : P * P = P := hU - have h_sa : IsSelfAdjoint P := IsSelfAdjoint.star_mul_self U - have h_ker_P : LinearMap.ker P.toLinearMap = LinearMap.ker U.toLinearMap := by - ext y - simp only [LinearMap.mem_ker, ContinuousLinearMap.coe_coe] - constructor - · intro hy - have h0 : ‖U y‖ ^ 2 = 0 := by - rw [← inner_self_eq_norm_sq (𝕜 := ℂ), ← adjoint_inner_right] - have : U.adjoint (U y) = P y := rfl - rw [this, hy, inner_zero_right] - rfl - exact norm_eq_zero.mp (sq_eq_zero_iff.mp h0) - · intro hy - change P y = 0 - calc P y = (U.adjoint * U) y := rfl - _ = U.adjoint (U y) := rfl - _ = U.adjoint 0 := by rw [hy] - _ = 0 := map_zero _ - have hP_idem : IsIdempotentElem P := hP_proj - have hP_symm : (P : H →ₗ[ℂ] H).IsSymmetric := - ContinuousLinearMap.isSelfAdjoint_iff_isSymmetric.1 h_sa - have h_orth : (LinearMap.range P.toLinearMap)ᗮ = LinearMap.ker P.toLinearMap := - (LinearMap.IsIdempotentElem.isSymmetric_iff_orthogonal_range hP_idem.toLinearMap).1 hP_symm - have h_range_closed : IsClosed (LinearMap.range P.toLinearMap : Set H) := - IsIdempotentElem.isClosed_range hP_idem - have h_eq_range : (LinearMap.ker P.toLinearMap)ᗮ = LinearMap.range P.toLinearMap := by - calc (LinearMap.ker P.toLinearMap)ᗮ = (LinearMap.range P.toLinearMap)ᗮᗮ := by simp [h_orth] - _ = (LinearMap.range P.toLinearMap).topologicalClosure := by - simpa using Submodule.orthogonal_orthogonal_eq_closure (K := LinearMap.range P.toLinearMap) - _ = LinearMap.range P.toLinearMap := IsClosed.submodule_topologicalClosure_eq h_range_closed - have hx' : x ∈ (LinearMap.ker P.toLinearMap)ᗮ := by rw [h_ker_P]; exact hx - have hx_range : x ∈ LinearMap.range P.toLinearMap := by rw [h_eq_range] at hx'; exact hx' - rcases hx_range with ⟨y, hy⟩ - calc U.adjoint (U x) = P x := rfl - _ = P (P y) := by - congr 1 - exact hy.symm - _ = P y := by - have := congrArg (· y) hP_proj - simp only [mul_apply] at this - exact this - _ = x := hy - -/-- A partial isometry has operator norm at most 1. - This follows from ‖U x‖ = ‖x‖ on (ker U)ᗮ and ‖U x‖ = 0 on ker U. -/ -lemma IsPartialIsometry.norm_le_one {U : H →L[ℂ] H} (hU : IsPartialIsometry U) : - ‖U‖ ≤ 1 := by - apply ContinuousLinearMap.opNorm_le_bound _ zero_le_one - intro x - simp only [one_mul] - -- Use U†U is a self-adjoint idempotent (projection) - let P := U.adjoint * U - have hP_idem : P * P = P := hU - have hP_sa : IsSelfAdjoint P := IsSelfAdjoint.star_mul_self U - -- ‖U x‖² = ⟨x, U†U x⟩ = ⟨x, P x⟩ - have h_norm_sq : ‖U x‖ ^ 2 = (⟪x, P x⟫_ℂ).re := by - rw [← inner_self_eq_norm_sq (𝕜 := ℂ)] - change Complex.re ⟪U x, U x⟫_ℂ = (⟪x, P x⟫_ℂ).re - rw [← adjoint_inner_right] - rfl - -- For self-adjoint idempotent P: 0 ≤ ⟨x, P x⟩ ≤ ⟨x, x⟩ - -- ⟨x, Px⟩ = ⟨Px, Px⟩ since P² = P and P = P† - have h_Px_eq : (⟪x, P x⟫_ℂ).re = ‖P x‖ ^ 2 := by - have hPsa : P.adjoint = P := hP_sa.adjoint_eq - have hPPx : P (P x) = P x := by - have := congrArg (fun T => T x) hP_idem - simp only [mul_apply] at this - exact this - -- ⟨x, Px⟩ = ⟨x, PPx⟩ = ⟨P†x, Px⟩ = ⟨Px, Px⟩ - calc (⟪x, P x⟫_ℂ).re - _ = (⟪x, P (P x)⟫_ℂ).re := by rw [hPPx] - _ = (⟪P.adjoint x, P x⟫_ℂ).re := by rw [adjoint_inner_left] - _ = (⟪P x, P x⟫_ℂ).re := by rw [hPsa] - _ = ‖P x‖ ^ 2 := by rw [inner_self_eq_norm_sq_to_K]; norm_cast - -- Similarly for 1 - P - have h_1mP : (⟪x, (1 - P) x⟫_ℂ).re = ‖(1 - P) x‖ ^ 2 := by - let Q := 1 - P - have hQ_idem : Q * Q = Q := by - ext y - simp only [Q, mul_apply, sub_apply, one_apply] - have hPPy : P (P y) = P y := by - have := congrArg (fun T => T y) hP_idem - simp only [mul_apply] at this - exact this - simp [hPPy] - have hQ_sa : IsSelfAdjoint Q := by - simp only [Q, IsSelfAdjoint, star_sub, star_one] - rw [hP_sa.star_eq] - have hQsa : Q.adjoint = Q := hQ_sa.adjoint_eq - have hQQx : Q (Q x) = Q x := by - have := congrArg (fun T => T x) hQ_idem - simp only [mul_apply] at this - exact this - calc (⟪x, Q x⟫_ℂ).re - _ = (⟪x, Q (Q x)⟫_ℂ).re := by rw [hQQx] - _ = (⟪Q.adjoint x, Q x⟫_ℂ).re := by rw [adjoint_inner_left] - _ = (⟪Q x, Q x⟫_ℂ).re := by rw [hQsa] - _ = ‖Q x‖ ^ 2 := by rw [inner_self_eq_norm_sq_to_K]; norm_cast - -- ⟨x, x⟩ = ⟨x, P x⟩ + ⟨x, (1-P) x⟩ - have h_decomp : (⟪x, x⟫_ℂ).re = (⟪x, P x⟫_ℂ).re + (⟪x, (1 - P) x⟫_ℂ).re := by - have h1 : ⟪x, x⟫_ℂ = ⟪x, P x⟫_ℂ + ⟪x, (1 - P) x⟫_ℂ := by - rw [← inner_add_right] - congr 1 - simp [sub_apply] - rw [h1, Complex.add_re] - have h_Px_le : (⟪x, P x⟫_ℂ).re ≤ (⟪x, x⟫_ℂ).re := by - rw [h_decomp, h_1mP] - linarith [sq_nonneg ‖(1 - P) x‖] - have h_inner_xx : (⟪x, x⟫_ℂ).re = ‖x‖ ^ 2 := by - rw [inner_self_eq_norm_sq_to_K]; norm_cast - -- ‖U x‖² ≤ ‖x‖² - have h_sq_le : ‖U x‖ ^ 2 ≤ ‖x‖ ^ 2 := by - rw [h_norm_sq] - calc (⟪x, P x⟫_ℂ).re ≤ (⟪x, x⟫_ℂ).re := h_Px_le - _ = ‖x‖ ^ 2 := h_inner_xx - -- ‖U x‖ ≤ ‖x‖ - have h_nonneg_Ux : 0 ≤ ‖U x‖ := norm_nonneg _ - have h_nonneg_x : 0 ≤ ‖x‖ := norm_nonneg _ - nlinarith [sq_nonneg (‖U x‖ - ‖x‖), sq_nonneg (‖U x‖ + ‖x‖)] diff --git a/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/Pow/Real.lean b/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/Pow/Real.lean deleted file mode 100644 index 3eb8918..0000000 --- a/QuantumSystem/ForMathlib/Analysis/SpecialFunctions/Pow/Real.lean +++ /dev/null @@ -1,152 +0,0 @@ -module - -public import Mathlib.Analysis.MeanInequalities - -/-! -# Inequalities for Real Power Functions - -This file proves scalar inequalities about `Real.rpow` used in the proof of -Lieb's joint concavity theorem. - -## Main results - -- `Real.convexCombo_rpow_mul_rpow_le`: joint concavity of (x, y) ↦ xᵖ y¹⁻ᵖ - for 0 < p < 1. --/ - -@[expose] public section - -namespace Real - -/-- Joint concavity of (x, y) ↦ xᵖ · y¹⁻ᵖ for 0 < p < 1: -the convex combination of values is at most the value at the convex combination. -/ -lemma convexCombo_rpow_mul_rpow_le {p t x₁ x₂ y₁ y₂ : ℝ} - (hp0 : 0 < p) (hp1 : p < 1) - (ht0 : 0 ≤ t) (ht1 : t ≤ 1) - (hx₁ : 0 ≤ x₁) (hx₂ : 0 ≤ x₂) (hy₁ : 0 ≤ y₁) (hy₂ : 0 ≤ y₂) : - t * (x₁ ^ p * y₁ ^ (1 - p)) + (1 - t) * (x₂ ^ p * y₂ ^ (1 - p)) ≤ - (t * x₁ + (1 - t) * x₂) ^ p * (t * y₁ + (1 - t) * y₂) ^ (1 - p) := by - have h1p : 0 < 1 - p := by linarith - have hconj : p + (1 - p) = 1 := by ring - -- Handle boundary cases for t - rcases eq_or_lt_of_le ht0 with rfl | ht0' - · simp - rcases eq_or_lt_of_le ht1 with rfl | ht1' - · simp - have h1t : 0 < 1 - t := by linarith - have htne : t ≠ 0 := ne_of_gt ht0' - have h1tne : 1 - t ≠ 0 := ne_of_gt h1t - -- Handle zero cases - by_cases hsum_x_zero : t * x₁ + (1 - t) * x₂ = 0 - · -- If the x-sum is zero, both t*x₁ and (1-t)*x₂ must be zero - have htx₁ : t * x₁ = 0 := by - have h1 := mul_nonneg (le_of_lt ht0') hx₁ - have h2 := mul_nonneg (le_of_lt h1t) hx₂ - linarith - have hx₁_zero : x₁ = 0 := (mul_eq_zero.mp htx₁).resolve_left htne - have htx₂ : (1 - t) * x₂ = 0 := by linarith - have hx₂_zero : x₂ = 0 := (mul_eq_zero.mp htx₂).resolve_left h1tne - -- LHS = 0 + 0 = 0, RHS = 0^p * (...)^(1-p) ≥ 0 - simp only [hx₁_zero, hx₂_zero, Real.zero_rpow (ne_of_gt hp0), mul_zero, zero_mul, add_zero] - exact le_refl 0 - by_cases hsum_y_zero : t * y₁ + (1 - t) * y₂ = 0 - · -- If the y-sum is zero, both t*y₁ and (1-t)*y₂ must be zero - have hty₁ : t * y₁ = 0 := by - have h1 := mul_nonneg (le_of_lt ht0') hy₁ - have h2 := mul_nonneg (le_of_lt h1t) hy₂ - linarith - have hy₁_zero : y₁ = 0 := (mul_eq_zero.mp hty₁).resolve_left htne - have hty₂ : (1 - t) * y₂ = 0 := by linarith - have hy₂_zero : y₂ = 0 := (mul_eq_zero.mp hty₂).resolve_left h1tne - -- LHS = 0 + 0 = 0, RHS = (...)^p * 0^(1-p) ≥ 0 - simp only [hy₁_zero, hy₂_zero, Real.zero_rpow (ne_of_gt h1p), mul_zero, add_zero] - exact le_refl 0 - -- Main case: both sums are positive - have hsum_x_pos : 0 < t * x₁ + (1 - t) * x₂ := by - have := add_nonneg (mul_nonneg (le_of_lt ht0') hx₁) (mul_nonneg (le_of_lt h1t) hx₂) - exact lt_of_le_of_ne this (Ne.symm hsum_x_zero) - have hsum_y_pos : 0 < t * y₁ + (1 - t) * y₂ := by - have := add_nonneg (mul_nonneg (le_of_lt ht0') hy₁) (mul_nonneg (le_of_lt h1t) hy₂) - exact lt_of_le_of_ne this (Ne.symm hsum_y_zero) - -- Define normalized weights - set X := t * x₁ + (1 - t) * x₂ with hX_def - set Y := t * y₁ + (1 - t) * y₂ with hY_def - set α := (t * x₁) / X with hα_def - set β := (t * y₁) / Y with hβ_def - have hX_ne : X ≠ 0 := ne_of_gt hsum_x_pos - have hY_ne : Y ≠ 0 := ne_of_gt hsum_y_pos - have hα_nonneg : 0 ≤ α := div_nonneg (mul_nonneg (le_of_lt ht0') hx₁) (le_of_lt hsum_x_pos) - have hα_le_one : α ≤ 1 := by - rw [div_le_one (by positivity)] - exact le_add_of_nonneg_right (mul_nonneg (le_of_lt h1t) hx₂) - have hβ_nonneg : 0 ≤ β := div_nonneg (mul_nonneg (le_of_lt ht0') hy₁) (le_of_lt hsum_y_pos) - have hβ_le_one : β ≤ 1 := by - rw [div_le_one (by positivity)] - exact le_add_of_nonneg_right (mul_nonneg (le_of_lt h1t) hy₂) - have h1α_nonneg : 0 ≤ 1 - α := by linarith - have h1β_nonneg : 0 ≤ 1 - β := by linarith - -- Key identities - have htx₁_eq : t * x₁ = α * X := by - rw [hα_def] - exact (div_mul_cancel₀ (t * x₁) hX_ne).symm - have htx₂_eq : (1 - t) * x₂ = (1 - α) * X := by - have h : (1 - t) * x₂ = X - t * x₁ := by rw [hX_def]; ring - rw [h, htx₁_eq]; ring - have hty₁_eq : t * y₁ = β * Y := by - rw [hβ_def] - exact (div_mul_cancel₀ (t * y₁) hY_ne).symm - have hty₂_eq : (1 - t) * y₂ = (1 - β) * Y := by - have h : (1 - t) * y₂ = Y - t * y₁ := by rw [hY_def]; ring - rw [h, hty₁_eq]; ring - -- Use weighted AM-GM to bound the sum of geometric means - have hAMGM1 := geom_mean_le_arith_mean2_weighted (le_of_lt hp0) (le_of_lt h1p) hα_nonneg hβ_nonneg hconj - have hAMGM2 := geom_mean_le_arith_mean2_weighted (le_of_lt hp0) (le_of_lt h1p) h1α_nonneg h1β_nonneg hconj - have hbound : α ^ p * β ^ (1 - p) + (1 - α) ^ p * (1 - β) ^ (1 - p) ≤ 1 := by - calc α ^ p * β ^ (1 - p) + (1 - α) ^ p * (1 - β) ^ (1 - p) - ≤ (p * α + (1 - p) * β) + (p * (1 - α) + (1 - p) * (1 - β)) := add_le_add hAMGM1 hAMGM2 - _ = p * (α + (1 - α)) + (1 - p) * (β + (1 - β)) := by ring - _ = p * 1 + (1 - p) * 1 := by simp - _ = 1 := by ring - -- Key calculation: Express products in terms of α, β - have hprod1 : (t * x₁) ^ p * (t * y₁) ^ (1 - p) = α ^ p * β ^ (1 - p) * X ^ p * Y ^ (1 - p) := by - rw [htx₁_eq, hty₁_eq] - rw [Real.mul_rpow hα_nonneg (le_of_lt hsum_x_pos)] - rw [Real.mul_rpow hβ_nonneg (le_of_lt hsum_y_pos)] - ring - have hprod2 : ((1 - t) * x₂) ^ p * ((1 - t) * y₂) ^ (1 - p) = - (1 - α) ^ p * (1 - β) ^ (1 - p) * X ^ p * Y ^ (1 - p) := by - rw [htx₂_eq, hty₂_eq] - rw [Real.mul_rpow h1α_nonneg (le_of_lt hsum_x_pos)] - rw [Real.mul_rpow h1β_nonneg (le_of_lt hsum_y_pos)] - ring - -- Show t * (x₁ ^ p * y₁ ^ (1 - p)) = (t * x₁) ^ p * (t * y₁) ^ (1 - p) - have ht_rpow : t ^ p * t ^ (1 - p) = t := by - rw [← Real.rpow_add ht0', hconj, Real.rpow_one] - have h1t_rpow : (1 - t) ^ p * (1 - t) ^ (1 - p) = 1 - t := by - rw [← Real.rpow_add h1t, hconj, Real.rpow_one] - have hfinal1 : t * (x₁ ^ p * y₁ ^ (1 - p)) = (t * x₁) ^ p * (t * y₁) ^ (1 - p) := by - rw [Real.mul_rpow (le_of_lt ht0') hx₁, Real.mul_rpow (le_of_lt ht0') hy₁] - have h : t ^ p * x₁ ^ p * (t ^ (1 - p) * y₁ ^ (1 - p)) = - t ^ p * t ^ (1 - p) * x₁ ^ p * y₁ ^ (1 - p) := by ring - rw [h, ht_rpow, mul_assoc] - have hfinal2 : (1 - t) * (x₂ ^ p * y₂ ^ (1 - p)) = ((1 - t) * x₂) ^ p * ((1 - t) * y₂) ^ (1 - p) := by - rw [Real.mul_rpow (le_of_lt h1t) hx₂, Real.mul_rpow (le_of_lt h1t) hy₂] - have h : (1 - t) ^ p * x₂ ^ p * ((1 - t) ^ (1 - p) * y₂ ^ (1 - p)) = - (1 - t) ^ p * (1 - t) ^ (1 - p) * x₂ ^ p * y₂ ^ (1 - p) := by ring - rw [h, h1t_rpow, mul_assoc] - -- Combine everything - calc t * (x₁ ^ p * y₁ ^ (1 - p)) + (1 - t) * (x₂ ^ p * y₂ ^ (1 - p)) - = (t * x₁) ^ p * (t * y₁) ^ (1 - p) + ((1 - t) * x₂) ^ p * ((1 - t) * y₂) ^ (1 - p) := by - rw [hfinal1, hfinal2] - _ = α ^ p * β ^ (1 - p) * X ^ p * Y ^ (1 - p) + - (1 - α) ^ p * (1 - β) ^ (1 - p) * X ^ p * Y ^ (1 - p) := by - rw [hprod1, hprod2] - _ = X ^ p * Y ^ (1 - p) * (α ^ p * β ^ (1 - p) + (1 - α) ^ p * (1 - β) ^ (1 - p)) := by ring - _ ≤ X ^ p * Y ^ (1 - p) * 1 := by - apply mul_le_mul_of_nonneg_left hbound - apply mul_nonneg - · exact Real.rpow_nonneg (le_of_lt hsum_x_pos) _ - · exact Real.rpow_nonneg (le_of_lt hsum_y_pos) _ - _ = X ^ p * Y ^ (1 - p) := mul_one _ - -end Real From ef252c051a87834372b72efa5aeb1554e35d1a90 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 15 Jun 2026 18:51:59 +0000 Subject: [PATCH 009/113] feat(cstar): add bundled *-representation layer Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 7 + .../Algebra/CStarAlgebra/Representation.lean | 83 ++++ .../Representation/Conjugation.lean | 150 ++++++++ .../Representation/DirectSum.lean | 363 ++++++++++++++++++ .../CStarAlgebra/Representation/Family.lean | 82 ++++ .../CStarAlgebra/Representation/Hom.lean | 118 ++++++ .../Representation/Irreducible.lean | 112 ++++++ .../Representation/UnitaryEquiv.lean | 188 +++++++++ .../Analysis/CStarAlgebra/HilbertSpace.lean | 24 ++ 9 files changed, 1127 insertions(+) create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation.lean create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation/Family.lean create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean create mode 100644 QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index ef19c20..2d3241a 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -7,6 +7,13 @@ public import QuantumSystem.Algebra.CStarAlgebra.GNS.PureState public import QuantumSystem.Algebra.CStarAlgebra.GNS.Representation public import QuantumSystem.Algebra.CStarAlgebra.PureState public import QuantumSystem.Algebra.CStarAlgebra.QuasiState +public import QuantumSystem.Algebra.CStarAlgebra.Representation +public import QuantumSystem.Algebra.CStarAlgebra.Representation.Conjugation +public import QuantumSystem.Algebra.CStarAlgebra.Representation.DirectSum +public import QuantumSystem.Algebra.CStarAlgebra.Representation.Family +public import QuantumSystem.Algebra.CStarAlgebra.Representation.Hom +public import QuantumSystem.Algebra.CStarAlgebra.Representation.Irreducible +public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv public import QuantumSystem.Algebra.CStarAlgebra.State public import QuantumSystem.Algebra.CStarAlgebra.State.Continuity public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation.lean new file mode 100644 index 0000000..1b23730 --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation.lean @@ -0,0 +1,83 @@ +module + +public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.HilbertSpace + +/-! +# Bundled `*`-representations of a C\*-algebra on a complex Hilbert space + +This file introduces the type `CStarRep A` of (non-unital) `*`-representations +of a non-unital C\*-algebra `A` on a complex Hilbert space, packaged as the +pair `(H, π)` of a carrier and a non-unital star-algebra homomorphism into +the C\*-algebra of bounded linear operators `𝓑(H)`. + +`CStarRep A` is a foundational, sector-agnostic notion: it is the generic +data of a C\*-algebra representation, with no choice of cyclic vector or +attachment to a state. Both the GNS construction and the abstract +representation-theoretic layer are built on top of it: + +* `CStarAlgebra/GNS/Representation.lean` adds a cyclic vector and a state to + obtain a GNS triplet (`GNS.Representation` extends `CStarRep`); +* `CStarAlgebra/Representation/UnitaryEquiv.lean` defines unitary equivalence + between two `CStarRep`s as the existence of an intertwining unitary map (no + cyclic vector compatibility, contrary to `GNS.Representation.UnitaryEquiv` + which is the same-state GNS uniqueness statement); +* `CStarAlgebra/Representation/Irreducible.lean` lifts the irreducibility + predicate to the general `CStarRep` setting; +* `CStarAlgebra/Representation/Family.lean` packages indexed families of + representatives, on which the superselection sector theory of + `QuantumSystem/Algebra/Sector/*` imposes its DHR / topological / KMS criteria. + +## Relation to Mathlib + +Mathlib's `Mathlib.RepresentationTheory.Basic.Representation` is the +group/monoid representation type `G →* (V →ₗ[k] V)` and does not match +the C\*-algebra / Hilbert-space setting. The GNS construction in +`Mathlib.Analysis.CStarAlgebra.GelfandNaimarkSegal` exposes the Hilbert +space (`f.GNS`) and the homomorphism (`f.gnsStarAlgHom`) as separate +artifacts; there is no bundled `(H, π)` structure. This file introduces +the bundle for the first time. + +## Relation to `GNS.Representation` + +`GNS.Representation ω` (defined in +`QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean`) is the GNS +triplet `(H, π, ξ)` for a specific state `ω : State ℂ A`, adding a +cyclic unit vector `ξ` and the GNS identity +`ω a = ⟪ξ, π a ξ⟫` on top of the data of a `CStarRep A`. +The forgetful projection sending a GNS triplet to its underlying +`CStarRep` is the canonical bridge between the two layers. + +## Main definitions + +* `CStarRep A` — a bundled non-unital `*`-representation + `π : A →⋆ₙₐ[ℂ] 𝓑(H)` together with the carrier `H` and its + `ComplexHilbertSpace` instance. +-/ + +@[expose] public section + +universe u v + +variable {A : Type u} [NonUnitalCStarAlgebra A] + +/-- A bundled non-unital `*`-representation of a non-unital C\*-algebra +`A` on a complex Hilbert space. + +Fields: + +* `H` — the underlying type of the Hilbert space. +* `[hilbert]` — evidence that `H` is a complex Hilbert space. +* `π` — a non-unital `*`-representation `A →⋆ₙₐ[ℂ] 𝓑(H)`. + +This is the underlying data of a representation without any choice of a +cyclic vector or attachment to a particular state. For a GNS triplet +attached to a fixed state, see `GNS.Representation`. -/ +structure CStarRep (A : Type u) [NonUnitalCStarAlgebra A] where + /-- The Hilbert space on which the representation acts. -/ + H : Type v + /-- The complex Hilbert space structure on `H`. -/ + [hilbert : ComplexHilbertSpace H] + /-- The non-unital `*`-representation `A →⋆ₙₐ[ℂ] 𝓑(H)`. -/ + π : A →⋆ₙₐ[ℂ] 𝓑(H) + +attribute [instance] CStarRep.hilbert diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean new file mode 100644 index 0000000..34c61e1 --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean @@ -0,0 +1,150 @@ +module + +public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv + +/-! +# Conjugation of a `CStarRep` by a unitary + +Given a representation `R : CStarRep A` and a unitary +`U : UnitaryMap R.H K` between Hilbert spaces, the **conjugated +representation** is the `CStarRep A` on `K` whose action sends +`a : A` to the bounded operator + +``` +U ∘L R.π a ∘L U⋆ : K →L[ℂ] K. +``` + +The unitary `U` itself intertwines `R` with `R.conjBy U`, so the two +representations are canonically unitarily equivalent. + +This is the operator-algebraic building block of the DHR structure +theorem: given a DHR-intertwined `R` with witness unitary +`U : R.H → globalHilbert L Ω`, the conjugated representation +`R.conjBy U` lives on the same Hilbert space as the vacuum +representation, and the intertwining condition forces it to agree +with the vacuum action on operators localised outside the +DHR-localisation region. + +## Main definitions + +* `CStarRep.conjBy R U` — the conjugated representation. +* `CStarRep.conjByUnitaryEquiv R U` — the canonical unitary + equivalence `R ≃ R.conjBy U`. + +## Main results + +* `CStarRep.conjBy_π_apply` — `(R.conjBy U).π a = U R.π a U⋆`. +* `CStarRep.conjBy_π_eq_of_intertwined` — if the intertwining identity + `U ∘L R.π a = T ∘L U` holds at a particular operator `T`, then + `(R.conjBy U).π a = T`. This is the bridge to the DHR structure + theorem: the conjugated DHR representation acts as the vacuum + representation on operators localised outside the DHR region. + +## References + +* Naaijkens, *Anyons in Infinite Quantum Systems*, 2012, §3.2. +* Bratteli, Robinson, *Operator Algebras and Quantum Statistical + Mechanics II*, §5.3. +-/ + +@[expose] public section + +namespace CStarRep + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +/-- The **conjugated representation** of `R : CStarRep A` by a unitary +`U : UnitaryMap R.H K`: the carrier is `K` and the action is +`a ↦ U ∘L R.π a ∘L U⋆`. + +Internally the underlying non-unital star-algebra homomorphism is the +composition of `R.π` with the conjugation-by-`U` star-algebra +equivalence `(R.H →L[ℂ] R.H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)` provided by +`LinearIsometryEquiv.conjStarAlgEquiv`. -/ +noncomputable def conjBy (R : CStarRep A) {K : Type*} [ComplexHilbertSpace K] + (U : UnitaryMap R.H K) : CStarRep A where + H := K + π := + (((U.toLinearIsometryEquiv.conjStarAlgEquiv : + (R.H →L[ℂ] R.H) →⋆ₙₐ[ℂ] (K →L[ℂ] K))).comp R.π) + +@[simp] lemma conjBy_H (R : CStarRep A) {K : Type*} [ComplexHilbertSpace K] + (U : UnitaryMap R.H K) : (R.conjBy U).H = K := rfl + +/-- The action of the conjugated representation: `(R.conjBy U).π a` is +the operator `U ∘L R.π a ∘L U⋆` on `K`. -/ +@[simp] lemma conjBy_π_apply (R : CStarRep A) {K : Type*} + [ComplexHilbertSpace K] (U : UnitaryMap R.H K) (a : A) : + (R.conjBy U).π a = + U.toContinuousLinearMap ∘L R.π a ∘L U.toContinuousLinearMap.adjoint := by + -- `conjStarAlgEquiv` is defined so that `e.conjStarAlgEquiv x = e ∘L x ∘L e.symm` + -- and `UnitaryMap.toLinearIsometryEquiv` is built with `toFun = U.toCLM` and + -- `invFun = U.toCLM.adjoint`, so both sides reduce to the same CLM. + apply ContinuousLinearMap.ext + intro y + rfl + +/-- The **canonical unitary equivalence** `R ≃ R.conjBy U`: the +intertwining unitary is `U` itself, and the intertwining identity is +`U ∘L R.π a = (U R.π a U⋆) ∘L U`, which follows from `U⋆ U = id`. -/ +noncomputable def conjByUnitaryEquiv (R : CStarRep A) {K : Type*} + [ComplexHilbertSpace K] (U : UnitaryMap R.H K) : + CStarRep.UnitaryEquiv R (R.conjBy U) where + unitary_map := U + intertwines a := by + -- LHS: `U ∘L R.π a`. + -- RHS: `(R.conjBy U).π a ∘L U = U ∘L R.π a ∘L U⋆ ∘L U = U ∘L R.π a` + -- using `U⋆ U = id` from `U.adjoint_comp`. + rw [conjBy_π_apply] + apply ContinuousLinearMap.ext + intro x + have h : U.toContinuousLinearMap.adjoint + (U.toContinuousLinearMap x) = x := by + have := congrArg + (fun (f : R.H →L[ℂ] R.H) => f x) U.adjoint_comp + simpa using this + -- Goal: `U (R.π a x) = U (R.π a (U⋆ (U x)))`. Unfold nested + -- `.comp` applications and then rewrite with `h`. + change U.toContinuousLinearMap ((R.π a) x) = + U.toContinuousLinearMap ((R.π a) (U.toContinuousLinearMap.adjoint + (U.toContinuousLinearMap x))) + rw [h] + +/-- **Intertwining-from-the-left transports to operator equality** for +the conjugated representation. + +If a unitary `U : UnitaryMap R.H K` satisfies `U ∘L R.π a = T ∘L U` +for some `T : K →L[ℂ] K` at a particular `a : A`, then the conjugated +action `(R.conjBy U).π a` equals `T`. + +This is the bridge to the DHR structure theorem: when `U` is the +witness of a DHR intertwining condition and `T = incl a` is the action +of a reference inclusion (for instance the vacuum representation +`Subtype.val`), the conjugated representation agrees with that +inclusion on every operator where the intertwining condition holds — +i.e. on operators localised outside the DHR region. -/ +lemma conjBy_π_eq_of_intertwined {R : CStarRep A} + {K : Type*} [ComplexHilbertSpace K] + (U : UnitaryMap R.H K) + {a : A} {T : K →L[ℂ] K} + (hUa : U.toContinuousLinearMap ∘L R.π a = T ∘L U.toContinuousLinearMap) : + (R.conjBy U).π a = T := by + -- From `U ∘L R.π a = T ∘L U`, post-compose with `U⋆`: + -- `U ∘L R.π a ∘L U⋆ = T ∘L U ∘L U⋆ = T` using `U U⋆ = id`. + rw [conjBy_π_apply] + apply ContinuousLinearMap.ext + intro y + -- Apply `hUa` at the point `U⋆ y`. + have hy := congrArg + (fun (f : R.H →L[ℂ] K) => f (U.toContinuousLinearMap.adjoint y)) hUa + simp only [ContinuousLinearMap.coe_comp', Function.comp_apply] at hy ⊢ + rw [hy] + -- Remaining: `T (U (U⋆ y)) = T y`. + have hUU : U.toContinuousLinearMap + (U.toContinuousLinearMap.adjoint y) = y := by + have := congrArg + (fun (f : K →L[ℂ] K) => f y) U.comp_adjoint + simpa using this + rw [hUU] + +end CStarRep diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean new file mode 100644 index 0000000..adc15ac --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean @@ -0,0 +1,363 @@ +module + +public import Mathlib.Analysis.CStarAlgebra.Spectrum +public import Mathlib.Analysis.InnerProductSpace.l2Space +public import Mathlib.Data.Real.StarOrdered +public import QuantumSystem.Algebra.CStarAlgebra.Representation.Family + +/-! +# Direct sum of a sector family + +For a sector family `F : SectorFamily A` on a non-unital C\*-algebra +`A`, this file constructs: + +* `F.directSumHilbert` — the `ℓ²`-direct sum Hilbert space + `⨁_{α : F.Index} (F.rep α).H`. +* `F.directSumRep` — the block-diagonal universal representation + `A →⋆ₙₐ[ℂ] 𝓑(F.directSumHilbert)`. +* `F.directSumRep_norm_le` — the operator-norm bound + `‖F.directSumRep a‖ ≤ ‖a‖`. + +The construction is criterion-agnostic: it depends only on the +indexed family of representations, not on any selection predicate +`P : CStarRep A → Prop`. Faithfulness of `directSumRep` requires that +the family separates points (`F.SeparatesPoints`); see the +`directSumRep_injective_of` theorem. + +## Comparison with `GNS.DirectSum` + +`QuantumSystem.Algebra.CStarAlgebra.GNS.DirectSum.Hilbert A` is the +analogous `ℓ²`-direct sum indexed by *all* `PureState A`, with each +state contributing its GNS Hilbert space. Two pure states whose GNS +representations are unitarily equivalent contribute the "same sector" +twice (once per state), so this "fat" direct sum is not a true sector +decomposition. The skeleton version +(`PureState.sectorFamily` filtered to a skeleton in +`Sector/PureState/Family.lean`) avoids the over-counting. + +## Main definitions + +* `SectorFamily.directSumHilbert` — the direct-sum Hilbert space. +* `SectorFamily.sectorComponent` / `.sectorEmbed` — coordinate + projection / embedding. +* `SectorFamily.directSumRep` — the block-diagonal universal + `*`-representation. +-/ + +@[expose] public section + +open ENNReal + +namespace SectorFamily + +universe u v w + +variable {A : Type u} [NonUnitalCStarAlgebra A] + +/-- The `ℓ²` direct-sum Hilbert space of the family. -/ +noncomputable abbrev directSumHilbert (F : SectorFamily.{u, v, w} A) := + ↥(lp (fun α : F.Index => (F.rep α).H) 2) + +noncomputable instance (F : SectorFamily.{u, v, w} A) : + ComplexHilbertSpace F.directSumHilbert where + toNormedAddCommGroup := inferInstance + toInnerProductSpace := inferInstance + toCompleteSpace := inferInstance + +/-! ### Coordinate API + +For each `α : F.Index`, the `α`-th coordinate of the direct-sum +Hilbert space is `(F.rep α).H`. We provide: + +* `sectorComponent F α` — coordinate projection + `F.directSumHilbert →L[ℂ] (F.rep α).H`. +* `sectorEmbed F α` — coordinate embedding + `(F.rep α).H →ₗᵢ[ℂ] F.directSumHilbert` (Mathlib `lp.single` + packaged as a `LinearIsometry`). +-/ + +/-- The coordinate projection onto the `α`-th sector component, as a +continuous linear map. -/ +noncomputable def sectorComponent (F : SectorFamily.{u, v, w} A) + (α : F.Index) : F.directSumHilbert →L[ℂ] (F.rep α).H := + lp.evalCLM (𝕜 := ℂ) (fun α' : F.Index => (F.rep α').H) 2 α + +/-- The coordinate embedding of `(F.rep α).H` into the direct-sum +Hilbert space at the `α`-th component, as a linear isometry. -/ +noncomputable def sectorEmbed (F : SectorFamily.{u, v, w} A) + (α : F.Index) : (F.rep α).H →ₗᵢ[ℂ] F.directSumHilbert := + letI : DecidableEq F.Index := Classical.decEq _ + { toLinearMap := + (lp.singleContinuousLinearMap (𝕜 := ℂ) + (E := fun α' : F.Index => (F.rep α').H) 2 α).toLinearMap + norm_map' := fun x => + lp.norm_single (E := fun α' : F.Index => (F.rep α').H) + (by norm_num : (0 : ℝ≥0∞) < 2) α x } + +@[simp] lemma sectorEmbed_apply_coord (F : SectorFamily.{u, v, w} A) + (α : F.Index) (v : (F.rep α).H) : + (sectorEmbed F α v).val α = v := by + letI : DecidableEq F.Index := Classical.decEq _ + change (lp.single (E := fun α' : F.Index => (F.rep α').H) 2 α v) α = v + exact lp.single_apply_self + (E := fun α' : F.Index => (F.rep α').H) 2 α v + +lemma sectorEmbed_apply_coord_ne (F : SectorFamily.{u, v, w} A) + (α : F.Index) (v : (F.rep α).H) + {α' : F.Index} (h : α' ≠ α) : + (sectorEmbed F α v).val α' = 0 := by + letI : DecidableEq F.Index := Classical.decEq _ + change (lp.single (E := fun α'' : F.Index => (F.rep α'').H) 2 α v) α' = 0 + exact lp.single_apply_ne + (E := fun α'' : F.Index => (F.rep α'').H) 2 α v h + +@[simp] theorem sectorComponent_sectorEmbed (F : SectorFamily.{u, v, w} A) + (α : F.Index) (v : (F.rep α).H) : + sectorComponent F α (sectorEmbed F α v) = v := by + change (sectorEmbed F α v).val α = v + exact sectorEmbed_apply_coord F α v + +/-- Generic helper: from a `LinearIsometryEquiv` between a Hilbert space +`H` and the `α`-th fiber of the family, produce a `LinearIsometry` +embedding of `H` into the direct-sum Hilbert space. + +Defined generically (the family `F` stays a variable so that the +costly `directSumHilbert`-family typeclass synthesis only fires here, +not at downstream specialized call sites). -/ +noncomputable def sectorEmbedOfEquiv (F : SectorFamily.{u, v, w} A) + (α : F.Index) {H : Type v} [ComplexHilbertSpace H] + (eq : H ≃ₗᵢ[ℂ] (F.rep α).H) : + H →ₗᵢ[ℂ] F.directSumHilbert := + (sectorEmbed F α).comp eq.toLinearIsometry + +/-- The component-wise action of `a : A` on a fiber. -/ +noncomputable def componentWiseMap (F : SectorFamily.{u, v, w} A) (a : A) : + ∀ α : F.Index, 𝓑((F.rep α).H) := + fun α => (F.rep α).π a + +/-- Norm bound on the component-wise action: each fibre is bounded by `‖a‖`. -/ +lemma componentWiseMap_norm_le (F : SectorFamily.{u, v, w} A) + (a : A) (α : F.Index) (v : (F.rep α).H) : + ‖componentWiseMap F a α v‖ ≤ ‖a‖ * ‖v‖ := by + -- `‖π_α(a) v‖ ≤ ‖π_α(a)‖ * ‖v‖ ≤ ‖a‖ * ‖v‖` since `‖π_α(a)‖ ≤ ‖a‖` + -- for any C\*-algebra `*`-homomorphism into `𝓑(H)`. + calc ‖componentWiseMap F a α v‖ + _ ≤ ‖componentWiseMap F a α‖ * ‖v‖ := + ContinuousLinearMap.le_opNorm _ _ + _ ≤ ‖a‖ * ‖v‖ := + mul_le_mul_of_nonneg_right + (NonUnitalStarAlgHom.norm_apply_le (φ := (F.rep α).π) a) + (norm_nonneg _) + +/-- The component-wise image of an `ℓ²` family stays in `ℓ²`. -/ +lemma componentWiseMap_memℓp (F : SectorFamily.{u, v, w} A) (a : A) + (x : F.directSumHilbert) : + Memℓp (fun α => componentWiseMap F a α (x.val α)) 2 := by + have hx : Memℓp x.val 2 := x.property + rw [memℓp_gen_iff zero_lt_two] at hx ⊢ + have h2 : (2 : ℝ≥0∞).toReal = 2 := by norm_num + simp only [h2] at hx ⊢ + refine Summable.of_nonneg_of_le (fun α => by positivity) (fun α => ?_) + (Summable.mul_left (‖a‖ ^ 2) hx) + have h := componentWiseMap_norm_le F a α (x.val α) + change ‖componentWiseMap F a α (x.val α)‖ ^ (2 : ℝ) ≤ ‖a‖ ^ 2 * ‖x.val α‖ ^ 2 + trans (‖a‖ * ‖x.val α‖) ^ (2 : ℝ) + · gcongr + · rw [Real.mul_rpow (norm_nonneg _) (norm_nonneg _)] + norm_cast + +/-- The component-wise operator norm bound, summed in `ℓ²`. -/ +lemma componentWiseMap_norm_bound (F : SectorFamily.{u, v, w} A) (a : A) + (x : F.directSumHilbert) : + ‖(⟨fun α => componentWiseMap F a α (x.val α), + componentWiseMap_memℓp F a x⟩ : F.directSumHilbert)‖ ≤ ‖a‖ * ‖x‖ := by + have h2pos : (0 : ℝ) < (2 : ℝ≥0∞).toReal := by norm_num + have h2 : (2 : ℝ≥0∞).toReal = 2 := by norm_num + rw [lp.norm_eq_tsum_rpow h2pos, lp.norm_eq_tsum_rpow h2pos] + simp only [h2] + have hsum1 : Summable fun α => ‖componentWiseMap F a α (x.val α)‖ ^ (2 : ℝ) := by + have := componentWiseMap_memℓp F a x + rw [memℓp_gen_iff zero_lt_two] at this + simp only [h2] at this + exact this + have hsum2 : Summable fun α => ‖x.val α‖ ^ (2 : ℝ) := by + have : Memℓp x.val 2 := x.property + rw [memℓp_gen_iff zero_lt_two] at this + simp only [h2] at this + exact this + have sum_ineq : + ∑' α, ‖componentWiseMap F a α (x.val α)‖ ^ (2 : ℝ) ≤ + ‖a‖ ^ 2 * ∑' α, ‖x.val α‖ ^ (2 : ℝ) := by + rw [← tsum_mul_left] + apply tsum_le_of_sum_le' (by positivity) + intro s + calc ∑ α ∈ s, ‖componentWiseMap F a α (x.val α)‖ ^ (2 : ℝ) + _ ≤ ∑ α ∈ s, ‖a‖ ^ 2 * ‖x.val α‖ ^ (2 : ℝ) := by + gcongr with α _ + have h := componentWiseMap_norm_le F a α (x.val α) + trans (‖a‖ * ‖x.val α‖) ^ (2 : ℝ) + · gcongr + · rw [Real.mul_rpow (norm_nonneg _) (norm_nonneg _)] + norm_cast + _ ≤ ∑' α, ‖a‖ ^ 2 * ‖x.val α‖ ^ (2 : ℝ) := by + refine sum_le_hasSum _ (fun α _ => by positivity) + (Summable.hasSum (Summable.mul_left _ hsum2)) + trans ((‖a‖ ^ 2 * ∑' α, ‖x.val α‖ ^ (2 : ℝ)) ^ ((1 : ℝ) / 2)) + · gcongr + rw [Real.mul_rpow (sq_nonneg _) (tsum_nonneg fun α => by positivity)] + gcongr + rw [← Real.rpow_natCast ‖a‖ 2, ← Real.rpow_mul (norm_nonneg _)] + norm_num + +/-- The linear-map version of the block-diagonal action of `a` on the +direct-sum Hilbert space. -/ +noncomputable def directSumLinearMap (F : SectorFamily.{u, v, w} A) (a : A) : + F.directSumHilbert →ₗ[ℂ] F.directSumHilbert where + toFun x := ⟨fun α => componentWiseMap F a α (x.val α), + componentWiseMap_memℓp F a x⟩ + map_add' x y := by + apply Subtype.ext + funext α + simp only [lp.coeFn_add, Pi.add_apply, map_add] + map_smul' c x := by + apply Subtype.ext + funext α + simp only [lp.coeFn_smul, Pi.smul_apply, map_smul, RingHom.id_apply] + +/-- The bounded-operator version of the block-diagonal action of `a`. -/ +noncomputable def directSumCLM (F : SectorFamily.{u, v, w} A) (a : A) : + 𝓑(F.directSumHilbert) := + LinearMap.mkContinuous (F.directSumLinearMap a) ‖a‖ + (componentWiseMap_norm_bound F a) + +/-- Block-diagonality is compatible with the `*`-structure. -/ +lemma directSumCLM_adjoint (F : SectorFamily.{u, v, w} A) (a : A) : + ContinuousLinearMap.adjoint (F.directSumCLM a) = F.directSumCLM (star a) := by + refine ContinuousLinearMap.ext fun x => ?_ + apply ext_inner_right ℂ + intro y + rw [ContinuousLinearMap.adjoint_inner_left] + rw [lp.inner_eq_tsum, lp.inner_eq_tsum] + congr with α + simp only [directSumCLM, LinearMap.mkContinuous_apply, directSumLinearMap, + LinearMap.coe_mk, AddHom.coe_mk, componentWiseMap] + rw [← ContinuousLinearMap.adjoint_inner_left] + rw [map_star] + rw [ContinuousLinearMap.star_eq_adjoint] + +/-- The block-diagonal universal `*`-representation associated with a +sector family. -/ +noncomputable def directSumRep (F : SectorFamily.{u, v, w} A) : + A →⋆ₙₐ[ℂ] 𝓑(F.directSumHilbert) where + toFun a := F.directSumCLM a + map_mul' a b := by + ext x : 1 + apply Subtype.ext + funext α + simp only [directSumCLM, LinearMap.mkContinuous_apply, directSumLinearMap, + LinearMap.coe_mk, AddHom.coe_mk, ContinuousLinearMap.mul_apply] + rw [componentWiseMap, componentWiseMap, componentWiseMap] + conv_lhs => rw [map_mul] + rfl + map_zero' := by + ext x : 1 + apply Subtype.ext + funext α + simp only [directSumCLM, LinearMap.mkContinuous_apply, directSumLinearMap, + LinearMap.coe_mk, AddHom.coe_mk, ContinuousLinearMap.zero_apply] + rw [componentWiseMap] + rw [map_zero] + rfl + map_add' a b := by + ext x : 1 + apply Subtype.ext + funext α + simp only [directSumCLM, LinearMap.mkContinuous_apply, directSumLinearMap, + LinearMap.coe_mk, AddHom.coe_mk, ContinuousLinearMap.add_apply, + lp.coeFn_add, Pi.add_apply] + rw [componentWiseMap, componentWiseMap, componentWiseMap] + conv_lhs => rw [map_add] + rfl + map_smul' c a := by + ext x : 1 + apply Subtype.ext + funext α + simp only [directSumCLM, LinearMap.mkContinuous_apply, directSumLinearMap, + LinearMap.coe_mk, AddHom.coe_mk, ContinuousLinearMap.smul_apply, + lp.coeFn_smul, Pi.smul_apply] + rw [componentWiseMap, componentWiseMap] + conv_lhs => rw [map_smul] + rfl + map_star' a := by + rw [← directSumCLM_adjoint] + rfl + +/-- The operator-norm bound `‖F.directSumRep a‖ ≤ ‖a‖`. -/ +theorem directSumRep_norm_le (F : SectorFamily.{u, v, w} A) (a : A) : + ‖F.directSumRep a‖ ≤ ‖a‖ := by + change ‖F.directSumCLM a‖ ≤ ‖a‖ + exact LinearMap.mkContinuous_norm_le _ (norm_nonneg _) _ + +/-- A sector family *separates points* if the family of representations +separates `A`: whenever every member annihilates `a`, we have `a = 0`. -/ +def SeparatesPoints (F : SectorFamily.{u, v, w} A) : Prop := + ∀ a : A, (∀ α : F.Index, (F.rep α).π a = 0) → a = 0 + +/-- **Faithfulness of the direct-sum representation** under a +points-separation condition on the family: if the family separates `A`, +then `F.directSumRep` is injective. -/ +theorem directSumRep_injective_of (F : SectorFamily.{u, v, w} A) + (h_sep : F.SeparatesPoints) : + Function.Injective F.directSumRep := by + intro a b hab + -- It suffices to show `a - b = 0`. + rw [← sub_eq_zero] + -- `F.directSumRep (a - b) = 0` from `hab` by linearity. + have h_diff_zero : F.directSumRep (a - b) = 0 := by + rw [map_sub, hab, sub_self] + -- `F.directSumCLM (a - b) = 0` (the underlying bounded operator). + have h_clm_zero : F.directSumCLM (a - b) = 0 := h_diff_zero + -- Apply separation: every family member annihilates `a - b`. + apply h_sep + intro α + ext v + -- Goal: `(F.rep α).π (a - b) v = 0`. + classical + -- Construct the `δ_α`-vector in `directSumHilbert` carrying `v` in the + -- `α`-th component and `0` elsewhere. + let f : ∀ α' : F.Index, (F.rep α').H := + fun α' => if h : α' = α then h ▸ v else 0 + have hf_mem : Memℓp f 2 := by + rw [memℓp_gen_iff zero_lt_two] + have h2 : (2 : ℝ≥0∞).toReal = 2 := by norm_num + simp only [h2] + have h_eq : (fun α' => ‖f α'‖ ^ (2 : ℝ)) = + fun α' => if α' = α then ‖v‖ ^ 2 else 0 := by + ext α' + simp only [f] + by_cases h : α' = α + · subst h; simp + · simp only [dif_neg h, if_neg h]; simp + rw [h_eq] + apply summable_of_hasFiniteSupport + have : + Function.support (fun α' => if α' = α then ‖v‖ ^ 2 else 0) ⊆ {α} := by + intro α' hα' + simp only [Function.mem_support, ne_eq, ite_eq_right_iff, + Set.mem_singleton_iff] at hα' ⊢ + by_contra h + simp [h] at hα' + exact Set.Finite.subset (Set.finite_singleton α) this + let x : F.directSumHilbert := ⟨f, hf_mem⟩ + have hx_α : x.val α = v := by + simp only [x, f]; simp + -- Apply `h_clm_zero` to `x`. + have h0 : F.directSumCLM (a - b) x = 0 := by simp [h_clm_zero] + have hα0 : (F.directSumCLM (a - b) x).val α = 0 := by + simpa using congrArg (fun y : F.directSumHilbert => y.val α) h0 + -- Unfold the `α`-coordinate. + have hcomp : componentWiseMap F (a - b) α (x.val α) = 0 := by + simpa [directSumCLM, directSumLinearMap] using hα0 + simpa [componentWiseMap, hx_α] using hcomp + +end SectorFamily diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Family.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Family.lean new file mode 100644 index 0000000..d41cfa9 --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Family.lean @@ -0,0 +1,82 @@ +module + +public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv + +/-! +# Sector families + +A *sector family* `F : SectorFamily A` for a non-unital C\*-algebra `A` +is an indexed family of `CStarRep`s. In sector theory the typical +intent is that `F` enumerates a *complete system of representatives* +for the unitary-equivalence classes of representations satisfying some +physical selection condition `P` (DHR, KMS, cone-localised, ...): for +every physical representation `R` there is some index `α` with +`R ≃ F.rep α`, and indices give pairwise inequivalent representations. + +The selection condition `P` and the completeness/skeleton conditions are +*separate* structures (`SectorFamily.IsComplete`, `IsSkeleton`), so the +basic `SectorFamily` data carries no condition — it is just an indexed +family of representations. The direct sum +`SectorFamily.directSumHilbert` (in `CStarAlgebra/Representation/DirectSum.lean`) and its +universal `*`-representation `directSumRep` need only the family data. + +## Design rationale + +Compared to a quotient-first API such as +`Sector 𝒞 := Quotient 𝒞.equiv`, the family-first API avoids +`Classical.choice` / `Quotient.out` at the representative-selection level. +Sector representatives are explicit values of `F.rep α`, not output of +`Quotient.out`. This is the natural form used in the +Doplicher–Haag–Roberts and Naaijkens literature, where DHR sectors are +first constructed from localized endomorphisms and only *afterwards* +identified up to unitary equivalence. + +## Main definitions + +* `SectorFamily A` — an indexed family of `CStarRep`s. +* `SectorFamily.IsPhysical` — every member satisfies `P`. +* `SectorFamily.IsComplete` — every `P`-representation is unitarily + equivalent to some `F.rep α`. +* `SectorFamily.IsSkeleton` — `IsComplete` and pairwise non-equivalent. +-/ + +@[expose] public section + +universe u v w + +/-- An indexed family of `CStarRep`s of a non-unital C\*-algebra `A`, +parametrised by an arbitrary index type. -/ +structure SectorFamily (A : Type u) [NonUnitalCStarAlgebra A] where + /-- The index type. -/ + Index : Type w + /-- The representation at each index. -/ + rep : Index → CStarRep.{u, v} A + +namespace SectorFamily + +variable {A : Type u} [NonUnitalCStarAlgebra A] + +/-- Every member of the family satisfies the predicate `P`. -/ +structure IsPhysical (F : SectorFamily.{u, v, w} A) + (P : CStarRep.{u, v} A → Prop) : Prop where + /-- Each `F.rep α` is physical. -/ + isPhysical : ∀ α, P (F.rep α) + +/-- The family `F` is a *complete system of physical representatives*: +every representation satisfying `P` is unitarily equivalent to some +`F.rep α`. -/ +structure IsComplete (F : SectorFamily.{u, v, w} A) + (P : CStarRep.{u, v} A → Prop) : Prop extends F.IsPhysical P where + /-- Every `P`-representation is unitarily equivalent to some `F.rep α`. -/ + complete : ∀ R : CStarRep.{u, v} A, P R → ∃ α, + Nonempty (CStarRep.UnitaryEquiv R (F.rep α)) + +/-- The family `F` is a *skeleton* for the `P`-representations: it is +complete and any two indices give non-equivalent representations. -/ +structure IsSkeleton (F : SectorFamily.{u, v, w} A) + (P : CStarRep.{u, v} A → Prop) : Prop extends F.IsComplete P where + /-- Distinct indices give non-equivalent representations. -/ + pairwise : ∀ α β, + Nonempty (CStarRep.UnitaryEquiv (F.rep α) (F.rep β)) → α = β + +end SectorFamily diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean new file mode 100644 index 0000000..31f79c0 --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean @@ -0,0 +1,118 @@ +module + +public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv + +/-! +# Intertwiners between `CStarRep`s + +A *morphism* `T : CStarRep.Hom R₁ R₂` in the representation category of a +non-unital C\*-algebra `A` is a bounded linear map +`T : R₁.H →L[ℂ] R₂.H` that intertwines the two `*`-representations: + +``` +T ∘L R₁.π a = R₂.π a ∘L T for every a : A. +``` + +This is the standard notion of intertwiner used throughout sector +theory: subrepresentations, irreducibility, direct sums, Schur's lemma +and ultimately fusion of DHR sectors are all phrased in this language. +Unitary equivalence (`CStarAlgebra/Representation/UnitaryEquiv.lean`) is the subgroupoid of +isomorphisms in this category. + +## Main definitions + +* `CStarRep.Hom R₁ R₂` — bundled intertwiner. +* `CStarRep.Hom.id` — identity intertwiner. +* `CStarRep.Hom.comp` — composition of intertwiners. +* `CStarRep.UnitaryEquiv.toHom` — forget a unitary equivalence to an + intertwiner. +-/ + +@[expose] public section + +namespace CStarRep + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +/-- A morphism between two `CStarRep`s of the same C\*-algebra: a +bounded linear map intertwining the two `*`-representations. -/ +structure Hom (R₁ R₂ : CStarRep A) where + /-- The underlying bounded linear map. -/ + toContinuousLinearMap : R₁.H →L[ℂ] R₂.H + /-- The intertwining property. -/ + intertwines : + ∀ a : A, + toContinuousLinearMap ∘L R₁.π a = R₂.π a ∘L toContinuousLinearMap + +namespace Hom + +variable {R₁ R₂ R₃ : CStarRep A} + +/-- Two intertwiners are equal when their underlying continuous linear +maps agree. -/ +@[ext] lemma ext {T S : Hom R₁ R₂} + (h : T.toContinuousLinearMap = S.toContinuousLinearMap) : T = S := by + cases T; cases S; congr + +/-- The identity intertwiner. -/ +noncomputable def id (R : CStarRep A) : Hom R R where + toContinuousLinearMap := ContinuousLinearMap.id ℂ R.H + intertwines a := by ext x; simp + +/-- Composition of intertwiners. -/ +noncomputable def comp (S : Hom R₂ R₃) (T : Hom R₁ R₂) : Hom R₁ R₃ where + toContinuousLinearMap := + S.toContinuousLinearMap ∘L T.toContinuousLinearMap + intertwines a := by + -- `S ∘L T ∘L π₁ a = S ∘L (π₂ a ∘L T) = (S ∘L π₂ a) ∘L T = (π₃ a ∘L S) ∘L T`. + ext x + have hT := congrArg (fun (f : R₁.H →L[ℂ] R₂.H) => f x) (T.intertwines a) + have hS := congrArg (fun (f : R₂.H →L[ℂ] R₃.H) => f (T.toContinuousLinearMap x)) + (S.intertwines a) + simp only [ContinuousLinearMap.coe_comp', Function.comp_apply] at hT hS ⊢ + rw [← hT] at hS + exact hS + +@[simp] lemma id_toContinuousLinearMap (R : CStarRep A) : + (Hom.id R).toContinuousLinearMap = ContinuousLinearMap.id ℂ R.H := rfl + +@[simp] lemma comp_toContinuousLinearMap (S : Hom R₂ R₃) (T : Hom R₁ R₂) : + (S.comp T).toContinuousLinearMap = + S.toContinuousLinearMap ∘L T.toContinuousLinearMap := rfl + +@[simp] lemma id_comp (T : Hom R₁ R₂) : (Hom.id R₂).comp T = T := by + ext; simp + +@[simp] lemma comp_id (T : Hom R₁ R₂) : T.comp (Hom.id R₁) = T := by + ext; simp + +lemma comp_assoc {R₄ : CStarRep A} + (U : Hom R₃ R₄) (S : Hom R₂ R₃) (T : Hom R₁ R₂) : + (U.comp S).comp T = U.comp (S.comp T) := by + ext; simp [ContinuousLinearMap.comp_assoc] + +end Hom + +namespace UnitaryEquiv + +variable {R₁ R₂ : CStarRep A} + +/-- A unitary equivalence is in particular an intertwiner. -/ +noncomputable def toHom (U : UnitaryEquiv R₁ R₂) : Hom R₁ R₂ where + toContinuousLinearMap := U.unitary_map.toContinuousLinearMap + intertwines := U.intertwines + +@[simp] lemma toHom_toContinuousLinearMap (U : UnitaryEquiv R₁ R₂) : + U.toHom.toContinuousLinearMap = U.unitary_map.toContinuousLinearMap := rfl + +@[simp] lemma symm_toHom (U : UnitaryEquiv R₁ R₂) : + U.symm.toHom.toContinuousLinearMap = + U.unitary_map.toContinuousLinearMap.adjoint := rfl + +@[simp] lemma refl_toHom (R : CStarRep A) : + (UnitaryEquiv.refl R).toHom = Hom.id R := by + ext; rfl + +end UnitaryEquiv + +end CStarRep diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean new file mode 100644 index 0000000..54c622f --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean @@ -0,0 +1,112 @@ +module + +public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv + +/-! +# Irreducibility for `CStarRep` + +A `*`-representation `R : CStarRep A` is *(topologically) irreducible* +when its only closed invariant subspaces are `⊥` and `⊤`. This file +lifts the irreducibility predicate from `GNS.Representation` (where it +is parameterised by a state `ω`) to the more general setting of +`CStarRep A` (no cyclic vector / no state attachment), and proves that +irreducibility is preserved under unitary equivalence — a fact +required by sector well-definedness (a sector is an equivalence class +of irreducible representations, so the irreducibility predicate must +descend to the quotient). + +## Main definitions + +* `CStarRep.IsInvariant R W` — `W` is stable under every `R.π a`. +* `CStarRep.IsIrreducible R` — the only closed `R`-invariant + submodules are `⊥` and `⊤`. + +## Main results + +* `CStarRep.UnitaryEquiv.isIrreducible_iff` — irreducibility transfers + along a unitary equivalence. +-/ + +@[expose] public section + +namespace CStarRep + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +/-- A submodule `W` of the carrier of a representation is *invariant* if +it is stable under the action of every `R.π a`. -/ +def IsInvariant (R : CStarRep A) (W : Submodule ℂ R.H) : Prop := + ∀ a : A, W.map (R.π a).toLinearMap ≤ W + +/-- A representation is (topologically) irreducible if the only closed +invariant submodules are `⊥` and `⊤`. -/ +def IsIrreducible (R : CStarRep A) : Prop := + ∀ W : Submodule ℂ R.H, + IsClosed (W : Set R.H) → R.IsInvariant W → (W = ⊥ ∨ W = ⊤) + +namespace UnitaryEquiv + +/-- The forward direction of `isIrreducible_iff`: a unitary equivalence +transports irreducibility. -/ +private lemma isIrreducible_of {R₁ R₂ : CStarRep A} + (U : UnitaryEquiv R₁ R₂) (h₁ : R₁.IsIrreducible) : R₂.IsIrreducible := by + intro W hW_closed hW_inv + -- Pull `W` back along `U` to obtain a closed invariant submodule `W'` of `R₁.H`. + let f : R₁.H →L[ℂ] R₂.H := U.unitary_map.toContinuousLinearMap + let W' : Submodule ℂ R₁.H := W.comap f.toLinearMap + have hW'_closed : IsClosed (W' : Set R₁.H) := + hW_closed.preimage f.continuous + have hW'_inv : R₁.IsInvariant W' := by + intro a y hy + obtain ⟨x, hx_mem, rfl⟩ := hy + -- `hx_mem : x ∈ W'` means `f x ∈ W`. + -- Goal: `(R₁.π a) x ∈ W'`, i.e. `f ((R₁.π a) x) ∈ W`. + change f ((R₁.π a) x) ∈ W + -- Use the intertwining property `f ∘L R₁.π a = R₂.π a ∘L f`. + have hI := congrArg (fun (g : R₁.H →L[ℂ] R₂.H) => g x) (U.intertwines a) + simp only [ContinuousLinearMap.coe_comp', Function.comp_apply] at hI + rw [show f ((R₁.π a) x) = (R₂.π a) (f x) from hI] + -- `f x ∈ W` and `W` is invariant under `R₂.π a`. + have hfx : f x ∈ W := hx_mem + have := hW_inv a (Submodule.mem_map.mpr ⟨f x, hfx, rfl⟩) + exact this + rcases h₁ W' hW'_closed hW'_inv with hbot | htop + · -- `W' = ⊥`: then every `w ∈ W` has `w = f x` with `x ∈ W' = ⊥`, hence `x = 0`, so `w = 0`. + refine Or.inl ?_ + refine le_antisymm ?_ bot_le + intro w hw + -- Surjectivity of `f`: `w = f (f.adjoint w)` since `f ∘L f.adjoint = 1`. + have hsurj : f (f.adjoint w) = w := by + have := congrArg (fun (g : R₂.H →L[ℂ] R₂.H) => g w) U.unitary_map.comp_adjoint + simpa using this + set x := f.adjoint w with hx_def + have hx_mem : x ∈ W' := by + change f x ∈ W + rw [hx_def]; rw [hsurj] + exact hw + have hx_zero : x = 0 := by + have : x ∈ (⊥ : Submodule ℂ R₁.H) := hbot ▸ hx_mem + simpa using this + have : w = 0 := by rw [← hsurj, hx_zero]; simp + exact this ▸ Submodule.zero_mem _ + · -- `W' = ⊤`: then every `x ∈ R₁.H` has `f x ∈ W`; by surjectivity, every `w ∈ R₂.H` is in `W`. + refine Or.inr ?_ + refine le_antisymm le_top ?_ + intro w _ + have hsurj : f (f.adjoint w) = w := by + have := congrArg (fun (g : R₂.H →L[ℂ] R₂.H) => g w) U.unitary_map.comp_adjoint + simpa using this + have hx_mem : f.adjoint w ∈ W' := + htop ▸ Submodule.mem_top + have hfx : f (f.adjoint w) ∈ W := hx_mem + rw [hsurj] at hfx + exact hfx + +/-- Irreducibility transfers along unitary equivalence. -/ +lemma isIrreducible_iff {R₁ R₂ : CStarRep A} (U : UnitaryEquiv R₁ R₂) : + R₁.IsIrreducible ↔ R₂.IsIrreducible := + ⟨isIrreducible_of U, isIrreducible_of U.symm⟩ + +end UnitaryEquiv + +end CStarRep diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean new file mode 100644 index 0000000..026c6a0 --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean @@ -0,0 +1,188 @@ +module + +public import QuantumSystem.Algebra.CStarAlgebra.Representation + +/-! +# Unitary equivalence of `CStarRep`s + +Two non-unital `*`-representations `R₁ R₂ : CStarRep A` are *unitarily +equivalent* if there exists a unitary map `U : R₁.H → R₂.H` intertwining +the two representations: + +``` +U ∘L R₁.π a = R₂.π a ∘L U for every a : A +``` + +This is the standard notion used in sector theory: representations in +the same unitary-equivalence class are physically indistinguishable. +Compared with `GNS.Representation.UnitaryEquiv` (which additionally +requires the unitary to identify the GNS cyclic vectors of two triplets +for the *same* state `ω`), this notion drops the cyclic-vector +compatibility and applies to two general representations of possibly +unrelated origin. + +## Main definitions + +* `CStarRep.UnitaryEquiv R₁ R₂` — the data of a unitary intertwiner. +* `CStarRep.UnitaryEquiv.refl` / `.symm` / `.trans` — equivalence + closure. +* `CStarRep.unitarySetoid` — the corresponding `Setoid` on `CStarRep A`, + whose underlying relation is `Nonempty ∘ UnitaryEquiv`. +-/ + +@[expose] public section + +namespace CStarRep + +variable {A : Type*} [NonUnitalCStarAlgebra A] + +/-- A unitary equivalence between two `CStarRep`s of the same C\*-algebra +`A`: a unitary map between the underlying Hilbert spaces that intertwines +the two `*`-representations. -/ +structure UnitaryEquiv (R₁ R₂ : CStarRep A) where + /-- The underlying unitary between the Hilbert spaces. -/ + unitary_map : UnitaryMap R₁.H R₂.H + /-- The intertwining property. -/ + intertwines : + ∀ a : A, + unitary_map.toContinuousLinearMap ∘L R₁.π a = + R₂.π a ∘L unitary_map.toContinuousLinearMap + +namespace UnitaryEquiv + +/-- Identity unitary equivalence. -/ +noncomputable def refl (R : CStarRep A) : UnitaryEquiv R R where + unitary_map := + { toContinuousLinearMap := ContinuousLinearMap.id ℂ R.H + adjoint_comp := by + rw [ContinuousLinearMap.adjoint_id] + ext x; simp + comp_adjoint := by + rw [ContinuousLinearMap.adjoint_id] + ext x; simp } + intertwines a := by ext x; simp + +/-- Inverse of a unitary equivalence: take the adjoint of the unitary map. -/ +noncomputable def symm {R₁ R₂ : CStarRep A} (U : UnitaryEquiv R₁ R₂) : + UnitaryEquiv R₂ R₁ where + unitary_map := + { toContinuousLinearMap := U.unitary_map.toContinuousLinearMap.adjoint + adjoint_comp := by + rw [ContinuousLinearMap.adjoint_adjoint] + exact U.unitary_map.comp_adjoint + comp_adjoint := by + rw [ContinuousLinearMap.adjoint_adjoint] + exact U.unitary_map.adjoint_comp } + intertwines a := by + -- From `U ∘L π₁ a = π₂ a ∘L U`, taking adjoints both sides yields + -- `(π₁ a)† ∘L U† = U† ∘L (π₂ a)†`; rewriting (πᵢ a)† = πᵢ (star a) + -- gives `π₁ (star a) ∘L U† = U† ∘L π₂ (star a)`. Substituting + -- `a ↦ star a` (and using `star (star a) = a`) yields the goal. + have h := U.intertwines (star a) + have h' : + (U.unitary_map.toContinuousLinearMap ∘L R₁.π (star a)).adjoint = + (R₂.π (star a) ∘L U.unitary_map.toContinuousLinearMap).adjoint := by + rw [h] + rw [ContinuousLinearMap.adjoint_comp, ContinuousLinearMap.adjoint_comp] at h' + -- Now `(π₁ (star a))† ∘L U†.adjoint.adjoint = U†.adjoint.adjoint ∘L (π₂ (star a))†`. + -- But the LHS is `(π₁ (star a))† ∘L U†` after no rewriting since adjoint sits in + -- the outer position. The relevant simp lemma: `(π a)† = π (star a)`. + have hπ₁ : (R₁.π (star a)).adjoint = R₁.π a := by + have := (R₁.π).map_star' (star a) + rw [ContinuousLinearMap.star_eq_adjoint, star_star] at this + exact this.symm + have hπ₂ : (R₂.π (star a)).adjoint = R₂.π a := by + have := (R₂.π).map_star' (star a) + rw [ContinuousLinearMap.star_eq_adjoint, star_star] at this + exact this.symm + -- After rewriting: + rw [hπ₁, hπ₂] at h' + exact h'.symm + +/-- Composition of unitary equivalences. -/ +noncomputable def trans {R₁ R₂ R₃ : CStarRep A} + (U : UnitaryEquiv R₁ R₂) (V : UnitaryEquiv R₂ R₃) : + UnitaryEquiv R₁ R₃ where + unitary_map := + { toContinuousLinearMap := + V.unitary_map.toContinuousLinearMap ∘L U.unitary_map.toContinuousLinearMap + adjoint_comp := by + ext x + -- ((VU)† ∘L (VU)) x = U†(V†(V(Ux))) = U†(Ux) = x + simp only [ContinuousLinearMap.adjoint_comp, ContinuousLinearMap.coe_comp', + Function.comp_apply, ContinuousLinearMap.one_apply] + have hV : + V.unitary_map.toContinuousLinearMap.adjoint + (V.unitary_map.toContinuousLinearMap (U.unitary_map.toContinuousLinearMap x)) = + U.unitary_map.toContinuousLinearMap x := by + have := congrArg + (fun (f : R₂.H →L[ℂ] R₂.H) => f (U.unitary_map.toContinuousLinearMap x)) + V.unitary_map.adjoint_comp + simpa using this + rw [hV] + have hU : + U.unitary_map.toContinuousLinearMap.adjoint + (U.unitary_map.toContinuousLinearMap x) = x := by + have := congrArg + (fun (f : R₁.H →L[ℂ] R₁.H) => f x) U.unitary_map.adjoint_comp + simpa using this + exact hU + comp_adjoint := by + ext y + simp only [ContinuousLinearMap.adjoint_comp, ContinuousLinearMap.coe_comp', + Function.comp_apply, ContinuousLinearMap.one_apply] + have hU : + U.unitary_map.toContinuousLinearMap + (U.unitary_map.toContinuousLinearMap.adjoint + (V.unitary_map.toContinuousLinearMap.adjoint y)) = + V.unitary_map.toContinuousLinearMap.adjoint y := by + have := congrArg + (fun (f : R₂.H →L[ℂ] R₂.H) => f (V.unitary_map.toContinuousLinearMap.adjoint y)) + U.unitary_map.comp_adjoint + simpa using this + rw [hU] + have hV : + V.unitary_map.toContinuousLinearMap + (V.unitary_map.toContinuousLinearMap.adjoint y) = y := by + have := congrArg + (fun (f : R₃.H →L[ℂ] R₃.H) => f y) V.unitary_map.comp_adjoint + simpa using this + exact hV } + intertwines a := by + -- (VU) ∘L π₁ a = V ∘L (U ∘L π₁ a) = V ∘L (π₂ a ∘L U) = (V ∘L π₂ a) ∘L U + -- = (π₃ a ∘L V) ∘L U = π₃ a ∘L (V ∘L U) + ext x + have hU := congrArg (fun (f : R₁.H →L[ℂ] R₂.H) => f x) (U.intertwines a) + have hV := congrArg (fun (f : R₂.H →L[ℂ] R₃.H) => f (U.unitary_map.toContinuousLinearMap x)) + (V.intertwines a) + simp only [ContinuousLinearMap.coe_comp', Function.comp_apply] at hU hV ⊢ + rw [← hU] at hV + exact hV + +end UnitaryEquiv + +/-- The relation "there exists a unitary equivalence between `R₁` and `R₂`". -/ +def unitarilyEquivalent (R₁ R₂ : CStarRep A) : Prop := + Nonempty (UnitaryEquiv R₁ R₂) + +lemma unitarilyEquivalent.refl (R : CStarRep A) : unitarilyEquivalent R R := + ⟨UnitaryEquiv.refl R⟩ + +lemma unitarilyEquivalent.symm {R₁ R₂ : CStarRep A} + (h : unitarilyEquivalent R₁ R₂) : unitarilyEquivalent R₂ R₁ := + h.elim fun U => ⟨U.symm⟩ + +lemma unitarilyEquivalent.trans {R₁ R₂ R₃ : CStarRep A} + (h₁ : unitarilyEquivalent R₁ R₂) (h₂ : unitarilyEquivalent R₂ R₃) : + unitarilyEquivalent R₁ R₃ := + h₁.elim fun U => h₂.elim fun V => ⟨U.trans V⟩ + +/-- The `Setoid` of `CStarRep`s up to unitary equivalence. -/ +def unitarySetoid : Setoid (CStarRep A) where + r := unitarilyEquivalent + iseqv := + { refl := unitarilyEquivalent.refl + symm := unitarilyEquivalent.symm + trans := unitarilyEquivalent.trans } + +end CStarRep diff --git a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean index 0b950bc..7e96686 100644 --- a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean +++ b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean @@ -57,9 +57,33 @@ noncomputable def asUnitary (U : H ≃ₗᵢ[ℂ] K) : UnitaryMap H K where ext y simp [LinearIsometryEquiv.adjoint_eq_symm] +namespace UnitaryMap + /-- Unitary maps preserve the inner product. -/ lemma inner_map_eq (U : UnitaryMap H K) (x y : H) : inner ℂ (U.toContinuousLinearMap x) (U.toContinuousLinearMap y) = inner ℂ x y := by simp only [← ContinuousLinearMap.adjoint_inner_right, ← ContinuousLinearMap.comp_apply, U.adjoint_comp, ContinuousLinearMap.one_apply] +/-- A unitary map between complex Hilbert spaces, viewed as a linear isometric +equivalence. The forward map is `U.toContinuousLinearMap` and its inverse is the +adjoint `U.toContinuousLinearMap.adjoint`; the relations `U†U = 1` and `UU† = 1` +make these mutually inverse, and `inner_map_eq` makes the map an isometry. -/ +noncomputable def toLinearIsometryEquiv (U : UnitaryMap H K) : H ≃ₗᵢ[ℂ] K := + LinearEquiv.isometryOfInner + { U.toContinuousLinearMap.toLinearMap with + invFun := U.toContinuousLinearMap.adjoint + left_inv := fun x => by + simpa using congrArg (fun f : H →L[ℂ] H => f x) U.adjoint_comp + right_inv := fun y => by + simpa using congrArg (fun f : K →L[ℂ] K => f y) U.comp_adjoint } + U.inner_map_eq + +@[simp] lemma toLinearIsometryEquiv_apply (U : UnitaryMap H K) (x : H) : + U.toLinearIsometryEquiv x = U.toContinuousLinearMap x := rfl + +@[simp] lemma toLinearIsometryEquiv_symm_apply (U : UnitaryMap H K) (y : K) : + U.toLinearIsometryEquiv.symm y = U.toContinuousLinearMap.adjoint y := rfl + +end UnitaryMap + end UnitaryMap From a2f569d09fbc9158d5718f0a18b1135ae0e2fb5d Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 15 Jun 2026 18:52:07 +0000 Subject: [PATCH 010/113] refactor(gns): build GNS representation on CStarRep Co-Authored-By: Claude Opus 4.8 (1M context) --- .../CStarAlgebra/GNS/Representation.lean | 101 ++++++++++-------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean index 264a2a2..1cb4230 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean @@ -4,30 +4,37 @@ public import QuantumSystem.ForMathlib.LinearAlgebra.Span.Def public import QuantumSystem.ForMathlib.Topology.DenseLinear public import QuantumSystem.ForMathlib.Topology.MetricSpace.Completion public import QuantumSystem.Algebra.CStarAlgebra.GNS.Construction +public import QuantumSystem.Algebra.CStarAlgebra.Representation +public import QuantumSystem.Algebra.CStarAlgebra.Representation.Irreducible @[expose] public section +open scoped InnerProductSpace + namespace GNS /-- A (non‑unital) GNS triplet `(π, H, ξ)` for a state `ω : A → ℂ` on a (possibly non‑unital) C*-algebra `A`. -Fields: +This structure extends the bundled C\*-algebra representation `CStarRep A` +(defined in `QuantumSystem.Algebra.CStarAlgebra.Representation`) by the additional data of a +cyclic unit vector `ξ` and the GNS identity, factoring the conceptual +decomposition "general C\*-representation" + "cyclic vector for a specified +state" at the type level. + +Inherited fields (from `CStarRep A`): * `H` : the underlying type of the Hilbert space. * `[hilbert]` : evidence that `H` is a complex Hilbert space. * `π : A →⋆ₙₐ[ℂ] 𝓑(H)` : a non‑unital *-representation of `A` on `H`. + +GNS-specific fields: * `ξ : H` : a cyclic unit vector. * `cyclic` : density of the linear span `Submodule.span ℂ { π a ξ | a : A }` in `H`. * `unit_norm` : normalisation `‖ξ‖ = 1`. * `gns_condition` : the GNS identity `ω a = ⟪ξ, π a ξ⟫` for every `a : A`. -/ -structure Representation {A} [NonUnitalCStarAlgebra A] (ω : State ℂ A) where - /-- The Hilbert space of the GNS representation -/ - H : Type* - /-- The complex Hilbert space structure on H -/ - [hilbert : ComplexHilbertSpace H] - /-- The representation π : A → 𝓑(H) -/ - π : A →⋆ₙₐ[ℂ] 𝓑(H) +structure Representation {A} [NonUnitalCStarAlgebra A] (ω : State ℂ A) + extends CStarRep A where /-- The cyclic vector ξ ∈ H -/ ξ : H /-- The cyclic property: the span of {π(a)ξ : a ∈ A} is dense in H -/ @@ -35,9 +42,7 @@ structure Representation {A} [NonUnitalCStarAlgebra A] (ω : State ℂ A) where /-- The unit norm property: ‖ξ‖ = 1 -/ unit_norm : ‖ξ‖ = 1 /-- The GNS condition: ω(a) = ⟪ξ, π(a)ξ⟫ for all a ∈ A -/ - gns_condition : ∀ a : A, ω a = @inner ℂ H hilbert.toInnerProductSpace.toCore.toInner ξ (π a ξ) - -attribute [instance] Representation.hilbert + gns_condition : ∀ a : A, ω a = ⟪ξ, π a ξ⟫_ℂ namespace Representation @@ -47,50 +52,52 @@ variable {A : Type*} [NonUnitalCStarAlgebra A] variable {ω : State ℂ A} /-- A submodule `W` of the Hilbert space of a GNS representation is invariant if it is -stable under the action of `π(a)` for every `a : A`. -/ +stable under the action of `π(a)` for every `a : A`. + +This is the generic `CStarRep.IsInvariant` of the underlying representation `T.toCStarRep`; +it is provided here as a thin wrapper so that the GNS-specific lemmas read `T.IsInvariant W`, +while the single source of truth for the notion is `CStarRep.IsInvariant`. -/ def IsInvariant (T : Representation ω) (W : Submodule ℂ T.H) : Prop := - ∀ a : A, W.map (T.π a).toLinearMap ≤ W + T.toCStarRep.IsInvariant W /-- A GNS representation is (topologically) irreducible if the only **closed** invariant -submodules are `⊥` and `⊤`. -/ +submodules are `⊥` and `⊤`. + +This is the generic `CStarRep.IsIrreducible` of the underlying representation `T.toCStarRep` +(definitionally, since `T.H`/`T.π` are the inherited fields); the GNS wrapper keeps the +`T.IsIrreducible` spelling while delegating the definition to `CStarRep.IsIrreducible`. -/ def IsIrreducible (T : Representation ω) : Prop := - ∀ W : Submodule ℂ T.H, - IsClosed (W : Set T.H) → - T.IsInvariant W → - (W = ⊥ ∨ W = ⊤) + T.toCStarRep.IsIrreducible @[simp] lemma isInvariant_bot (T : Representation ω) : T.IsInvariant (⊥ : Submodule ℂ T.H) := by - unfold IsInvariant intro a w hw rcases (show w = 0 from by simpa using hw) with rfl simp @[simp] lemma isInvariant_top (T : Representation ω) : T.IsInvariant (⊤ : Submodule ℂ T.H) := by - unfold IsInvariant intro a w hw simp -/-- A unitary equivalence between two GNS representations packages the underlying -unitary between the Hilbert spaces together with the expected compatibility data. -/ -structure UnitaryEquiv (T₁ T₂ : Representation ω) where - /-- The underlying unitary between the Hilbert spaces. -/ - unitary_map : UnitaryMap T₁.H T₂.H +/-- A unitary equivalence between two GNS representations for the **same** state `ω`. + +This **extends** the generic unitary equivalence of the underlying `CStarRep`s +(`CStarRep.UnitaryEquiv`, which supplies the intertwining unitary `unitary_map` and its +`intertwines` property) by the GNS-specific compatibility `map_cyclic_vector`, requiring the +unitary to identify the two cyclic vectors. This is exactly the extra data of the GNS +uniqueness statement, on top of the bare unitary intertwiner shared with sector theory. -/ +structure UnitaryEquiv (T₁ T₂ : Representation ω) extends + CStarRep.UnitaryEquiv T₁.toCStarRep T₂.toCStarRep where /-- The unitary sends the cyclic vector of the first triplet to that of the second. -/ map_cyclic_vector : - (unitary_map.toContinuousLinearMap) T₁.ξ = T₂.ξ - /-- The unitary intertwines the two representations. -/ - intertwines : - ∀ a : A, - (unitary_map.toContinuousLinearMap) ∘L T₁.π a = - T₂.π a ∘L (unitary_map.toContinuousLinearMap) + (toUnitaryEquiv.unitary_map.toContinuousLinearMap) T₁.ξ = T₂.ξ notation:50 T₁ " ≃ᵁ " T₂ => Representation.UnitaryEquiv (ω := _) T₁ T₂ /-- Auxiliary: computes `⟪π a ξ, π b ξ⟫ = ω (star a * b)` for a single GNS triplet. -/ private lemma inner_cyclic_aux (T : Representation ω) (a b : A) : - @inner ℂ T.H _ (T.π a T.ξ) (T.π b T.ξ) = ω (star a * b) := by - have h₁ : @inner ℂ T.H _ (T.π a T.ξ) (T.π b T.ξ) = - @inner ℂ T.H _ T.ξ ((T.π a).adjoint (T.π b T.ξ)) := by + ⟪T.π a T.ξ, T.π b T.ξ⟫_ℂ = ω (star a * b) := by + have h₁ : ⟪T.π a T.ξ, T.π b T.ξ⟫_ℂ = + ⟪T.ξ, (T.π a).adjoint (T.π b T.ξ)⟫_ℂ := by rw [ContinuousLinearMap.adjoint_inner_right] have hstar : (T.π a).adjoint = T.π (star a) := by have : T.π (star a) = star (T.π a) := T.π.map_star' a @@ -102,12 +109,12 @@ private lemma inner_cyclic_aux (T : Representation ω) (a b : A) : /-- Inner products on cyclic vectors agree across triplets: both realise `ω (star a * b)`. -/ private lemma inner_cyclic (T₁ T₂ : Representation ω) (a b : A) : - @inner ℂ T₁.H _ (T₁.π a T₁.ξ) (T₁.π b T₁.ξ) = - @inner ℂ T₂.H _ (T₂.π a T₂.ξ) (T₂.π b T₂.ξ) := by + ⟪T₁.π a T₁.ξ, T₁.π b T₁.ξ⟫_ℂ = + ⟪T₂.π a T₂.ξ, T₂.π b T₂.ξ⟫_ℂ := by calc - @inner ℂ T₁.H _ (T₁.π a T₁.ξ) (T₁.π b T₁.ξ) + ⟪T₁.π a T₁.ξ, T₁.π b T₁.ξ⟫_ℂ = ω (star a * b) := inner_cyclic_aux T₁ a b - _ = @inner ℂ T₂.H _ (T₂.π a T₂.ξ) (T₂.π b T₂.ξ) := (inner_cyclic_aux T₂ a b).symm + _ = ⟪T₂.π a T₂.ξ, T₂.π b T₂.ξ⟫_ℂ := (inner_cyclic_aux T₂ a b).symm /-- Equality of norms of corresponding cyclic orbit vectors between two triplets. -/ private lemma norm_cyclic (T₁ T₂ : Representation ω) (a : A) : @@ -133,7 +140,7 @@ private lemma cyclic_correspondence_well_defined (T₁ T₂ : Representation ω) _ = T₁.π a T₁.ξ - T₁.π b T₁.ξ := by simp [ContinuousLinearMap.sub_apply] _ = 0 := by rw [h]; simp -- Transfer vanishing inner product to T₂ using equality of inner forms on cyclic vectors - have h_inner_zero_T₂ : @inner ℂ T₂.H _ (T₂.π (a - b) T₂.ξ) (T₂.π (a - b) T₂.ξ) = 0 := by + have h_inner_zero_T₂ : ⟪T₂.π (a - b) T₂.ξ, T₂.π (a - b) T₂.ξ⟫_ℂ = 0 := by rw [← inner_cyclic T₁ T₂ (a - b) (a - b), h_map_sub]; simp -- Norm zero implies vector zero in T₂ have h_map_sub_T₂ : T₂.π (a - b) T₂.ξ = 0 := by @@ -209,13 +216,13 @@ private lemma dist_cyclic (T₁ T₂ : Representation ω) (a : A) : rw [← sq_eq_sq₀ (norm_nonneg _) (norm_nonneg _)] rw [@norm_sub_sq ℂ T₁.H, @norm_sub_sq ℂ T₂.H] have h_norm := norm_cyclic T₁ T₂ a - have h_inner₁ : @inner ℂ T₁.H _ (T₁.π a T₁.ξ) T₁.ξ = conj (ω a) := by - calc @inner ℂ T₁.H _ (T₁.π a T₁.ξ) T₁.ξ - = conj (@inner ℂ T₁.H _ T₁.ξ (T₁.π a T₁.ξ)) := by rw [@inner_conj_symm ℂ T₁.H] + have h_inner₁ : ⟪T₁.π a T₁.ξ, T₁.ξ⟫_ℂ = conj (ω a) := by + calc ⟪T₁.π a T₁.ξ, T₁.ξ⟫_ℂ + = conj ⟪T₁.ξ, T₁.π a T₁.ξ⟫_ℂ := by rw [@inner_conj_symm ℂ T₁.H] _ = conj (ω a) := by rw [T₁.gns_condition a] - have h_inner₂ : @inner ℂ T₂.H _ (T₂.π a T₂.ξ) T₂.ξ = conj (ω a) := by - calc @inner ℂ T₂.H _ (T₂.π a T₂.ξ) T₂.ξ - = conj (@inner ℂ T₂.H _ T₂.ξ (T₂.π a T₂.ξ)) := by rw [@inner_conj_symm ℂ T₂.H] + have h_inner₂ : ⟪T₂.π a T₂.ξ, T₂.ξ⟫_ℂ = conj (ω a) := by + calc ⟪T₂.π a T₂.ξ, T₂.ξ⟫_ℂ + = conj ⟪T₂.ξ, T₂.π a T₂.ξ⟫_ℂ := by rw [@inner_conj_symm ℂ T₂.H] _ = conj (ω a) := by rw [T₂.gns_condition a] rw [h_inner₁, h_inner₂, h_norm, T₁.unit_norm, T₂.unit_norm] @@ -244,8 +251,8 @@ private lemma cyclicMap_well_defined (T₁ T₂ : Representation ω) /-- The cyclic map preserves inner products. -/ private lemma cyclicMap_inner (T₁ T₂ : Representation ω) (x y : cyclicSet T₁) : - @inner ℂ T₂.H _ (cyclicMap T₁ T₂ x) (cyclicMap T₁ T₂ y) = - @inner ℂ T₁.H _ x.val y.val := by + ⟪cyclicMap T₁ T₂ x, cyclicMap T₁ T₂ y⟫_ℂ = + ⟪x.val, y.val⟫_ℂ := by obtain ⟨a, ha⟩ := Set.mem_iUnion.mp x.property obtain ⟨b, hb⟩ := Set.mem_iUnion.mp y.property simp only [Set.mem_singleton_iff] at ha hb From bbe27098ab1bd96d22dc5e9cf5f50c7c645f7273 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 12:45:41 +0000 Subject: [PATCH 011/113] =?UTF-8?q?feat:=20add=20=E2=80=A0=20notation=20fo?= =?UTF-8?q?r=20continuous=20linear=20map=20adjoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a lightweight scoped postfix `T†` for `ContinuousLinearMap.adjoint T` in `ForMathlib/Analysis/InnerProductSpace/AdjointNotation.lean`, the standard operator-algebra symbol for the Hilbert-space adjoint. The notation lives in the opt-in `Adjoint` scope and the module imports only Mathlib, keeping it a valid ForMathlib upstream candidate. Regenerate the `QuantumSystem` aggregate. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 1 + .../InnerProductSpace/AdjointNotation.lean | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 QuantumSystem/ForMathlib/Analysis/InnerProductSpace/AdjointNotation.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 2d3241a..273eb60 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -49,6 +49,7 @@ public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Ideal public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.NonUnital public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Unital public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.WeakDual +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.DiagonalAmplification public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.InvariantSubspace public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/AdjointNotation.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/AdjointNotation.lean new file mode 100644 index 0000000..af41e72 --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/AdjointNotation.lean @@ -0,0 +1,35 @@ +module + +public import Mathlib.Analysis.InnerProductSpace.Adjoint + +@[expose] public section + +/-! +# Dagger notation for the adjoint of a continuous linear map + +This module introduces the postfix notation `T†` for `ContinuousLinearMap.adjoint T`, +the Hilbert-space adjoint of a continuous linear map between complex (or `RCLike`) +inner product spaces. + +The dagger `†` is the standard symbol for the adjoint throughout the operator-algebra +and quantum-physics literature (Bratteli–Robinson, Takesaki, Haag), where one writes +`T†` rather than the long-form `ContinuousLinearMap.adjoint T`. Keeping the formal +statements in this notation lets them read like the source texts. + +The notation lives in the dedicated `Adjoint` scope, so it is opt-in: activate it with +`open scoped Adjoint`. + +| Symbol | Expansion | How to activate | +|---|---|---| +| `T†` | `ContinuousLinearMap.adjoint T` | `open scoped Adjoint` | + +`†` binds at maximum precedence, so it attaches to the immediately preceding atom: +write `(f ∘L g)†` and `(R.π a)†` with explicit parentheses, exactly as for `⁻¹`. +-/ + +namespace Adjoint + +/-- `T†` denotes the Hilbert-space adjoint `ContinuousLinearMap.adjoint T`. -/ +scoped postfix:max "†" => ContinuousLinearMap.adjoint + +end Adjoint From 54856dda8d4ff0ca2cb6304b693244f4f9548ba4 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 12:45:52 +0000 Subject: [PATCH 012/113] =?UTF-8?q?refactor:=20use=20=E2=9F=AA=C2=B7,?= =?UTF-8?q?=C2=B7=E2=9F=AB/=E2=88=98L=20notation=20in=20ForMathlib=20inner?= =?UTF-8?q?-product=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spell the Hilbert-space inner product as `⟪·,·⟫_ℂ` and operator composition as `∘L` in `HilbertSpace`, `InvariantSubspace`, and `DiagonalAmplification`, matching Mathlib idiom. `InvariantSubspace` gains a file-local `†` postfix for the adjoint so its proofs read like its existing comments. No imports beyond Mathlib are added, preserving ForMathlib purity. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Analysis/CStarAlgebra/HilbertSpace.lean | 5 ++++- .../DiagonalAmplification.lean | 4 ++-- .../InnerProductSpace/InvariantSubspace.lean | 17 +++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean index 7e96686..9ef9fb6 100644 --- a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean +++ b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean @@ -4,6 +4,8 @@ public import Mathlib.Analysis.CStarAlgebra.ContinuousLinearMap @[expose] public section +open scoped InnerProductSpace + /-- A complex *pre*-Hilbert space: a normed space with a complex inner product. -/ class ComplexPreHilbertSpace (H : Type*) extends NormedAddCommGroup H, InnerProductSpace ℂ H @@ -60,7 +62,8 @@ noncomputable def asUnitary (U : H ≃ₗᵢ[ℂ] K) : UnitaryMap H K where namespace UnitaryMap /-- Unitary maps preserve the inner product. -/ -lemma inner_map_eq (U : UnitaryMap H K) (x y : H) : inner ℂ (U.toContinuousLinearMap x) (U.toContinuousLinearMap y) = inner ℂ x y := by +lemma inner_map_eq (U : UnitaryMap H K) (x y : H) : + ⟪U.toContinuousLinearMap x, U.toContinuousLinearMap y⟫_ℂ = ⟪x, y⟫_ℂ := by simp only [← ContinuousLinearMap.adjoint_inner_right, ← ContinuousLinearMap.comp_apply, U.adjoint_comp, ContinuousLinearMap.one_apply] diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean index cc7ac56..ad61311 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean @@ -89,7 +89,7 @@ lemma single_apply {n : ℕ} (i : Fin n) (v : H) (k : Fin n) : /-- Diagonal action of an operator `T : H →L[ℂ] H` on `H^n`. -/ noncomputable def diagonal {n : ℕ} (T : H →L[ℂ] H) : Hn (H := H) n →L[ℂ] Hn (H := H) n := by classical - exact ∑ i : Fin n, (single (H := H) (n := n) i).comp (T.comp (proj (H := H) (n := n) i)) + exact ∑ i : Fin n, single (H := H) (n := n) i ∘L (T ∘L proj (H := H) (n := n) i) @[simp] lemma diagonal_apply {n : ℕ} (T : H →L[ℂ] H) (x : Hn (H := H) n) (i : Fin n) : @@ -109,7 +109,7 @@ lemma diagonal_apply {n : ℕ} (T : H →L[ℂ] H) (x : Hn (H := H) n) (i : Fin /-- The projection of an operator `S` on `H^n` to its `(i, j)`-th component in `B(H)`. -/ noncomputable def matrixComponent {n : ℕ} (S : Hn (H := H) n →L[ℂ] Hn (H := H) n) (i j : Fin n) : H →L[ℂ] H := - (proj (H := H) (n := n) i).comp (S.comp (single (H := H) (n := n) j)) + proj (H := H) (n := n) i ∘L (S ∘L single (H := H) (n := n) j) @[simp] lemma matrixComponent_apply {n : ℕ} (S : Hn (H := H) n →L[ℂ] Hn (H := H) n) diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean index 31a5205..d168418 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean @@ -33,6 +33,7 @@ This file provides a minimal API for invariant / reducing subspaces for a set of namespace InnerProductSpace local notation "⟪" x ", " y "⟫" => inner ℂ x y +local postfix:max "†" => ContinuousLinearMap.adjoint variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] @@ -137,25 +138,25 @@ variable [CompleteSpace H] /-- A subspace `K` is reducing for a set of operators `S` if it is invariant under every operator in `S` and also invariant under every adjoint operator. -/ def IsReducing (S : Set (H →L[ℂ] H)) (K : Submodule ℂ H) : Prop := - ∀ T ∈ S, IsInvariant T K ∧ IsInvariant (ContinuousLinearMap.adjoint T) K + ∀ T ∈ S, IsInvariant T K ∧ IsInvariant (T†) K /-- If `K` is invariant under `T†`, then `Kᗮ` is invariant under `T`. -/ lemma orthogonalComplement_invariant_of_adjoint_invariant {T : H →L[ℂ] H} {K : Submodule ℂ H} - (hK : IsInvariant (ContinuousLinearMap.adjoint T) K) : IsInvariant T Kᗮ := by + (hK : IsInvariant (T†) K) : IsInvariant T Kᗮ := by -- Unfold to the pointwise characterization. refine (IsInvariant.iff_forall_mem (T := T) (K := Kᗮ)).2 ?_ intro y hy -- Show `T y ∈ Kᗮ` via the inner-product characterization. refine (K.mem_orthogonal (T y)).2 ?_ intro x hx - have hx' : (ContinuousLinearMap.adjoint T) x ∈ K := - (IsInvariant.iff_forall_mem (T := ContinuousLinearMap.adjoint T) (K := K)).1 hK x hx + have hx' : (T†) x ∈ K := + (IsInvariant.iff_forall_mem (T := T†) (K := K)).1 hK x hx -- `y ∈ Kᗮ` implies `⟪(T†) x, y⟫ = 0`, hence also `⟪x, T y⟫ = 0`. - have hy0 : ⟪(ContinuousLinearMap.adjoint T) x, y⟫ = 0 := - (K.mem_orthogonal y).1 hy ((ContinuousLinearMap.adjoint T) x) hx' + have hy0 : ⟪(T†) x, y⟫ = 0 := + (K.mem_orthogonal y).1 hy ((T†) x) hx' -- Use adjointness: `⟪(T†) x, y⟫ = ⟪x, T y⟫`. - have hAdj : ⟪x, T y⟫ = ⟪(ContinuousLinearMap.adjoint T) x, y⟫ := by + have hAdj : ⟪x, T y⟫ = ⟪(T†) x, y⟫ := by -- `adjoint_inner_left` is: `⟪(T†) y, x⟫ = ⟪y, T x⟫`. simpa using (ContinuousLinearMap.adjoint_inner_left (A := T) (x := y) (y := x)).symm exact hAdj.trans hy0 @@ -167,7 +168,7 @@ lemma starProjection_mem_centralizer_of_isReducing (hK : IsReducing S K) : K.starProjection ∈ Set.centralizer S := by intro T hT have hInv : IsInvariant T K := (hK T hT).1 - have hInvAdj : IsInvariant (ContinuousLinearMap.adjoint T) K := (hK T hT).2 + have hInvAdj : IsInvariant (T†) K := (hK T hT).2 have hInvOrth : IsInvariant T Kᗮ := orthogonalComplement_invariant_of_adjoint_invariant (T := T) hInvAdj exact commutes_starProjection_of_invariant (T := T) (K := K) hInv hInvOrth From 3f3c2dea191267447fba6f89612fca9cbb5a333c Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 12:46:01 +0000 Subject: [PATCH 013/113] =?UTF-8?q?refactor(gns):=20state=20GNS=20construc?= =?UTF-8?q?tion=20with=20=E2=9F=AA=C2=B7,=C2=B7=E2=9F=AB=20and=20=E2=80=A0?= =?UTF-8?q?=20notation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite the GNS construction's inner products as `⟪·,·⟫_ℂ` and the representation adjoint as `†` throughout statements and proofs, so the defining identities (`inner_ξω_eq`, `state_recovery`, `πω_star`) read as in the operator-algebra literature and match their docstrings. Two calc steps lifting the inner product across the quotient/completion coercion keep the explicit `@inner` form (no type anchor for the notation's instance metavariable) with an explanatory comment; the explicit `@norm` on the quotient is likewise retained. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../CStarAlgebra/GNS/Construction.lean | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean index c5b4645..adf996a 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean @@ -2,6 +2,7 @@ module public import Mathlib.Analysis.InnerProductSpace.Completion public import Mathlib.Analysis.Normed.Operator.Extend +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.HilbertSpace public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Ideal public import QuantumSystem.Algebra.CStarAlgebra.State.Continuity @@ -14,6 +15,7 @@ namespace GNS namespace Construction open ComplexConjugate NNReal Topology Filter +open scoped InnerProductSpace Adjoint variable {A : Type*} [NonUnitalCStarAlgebra A] variable (ω : State ℂ A) @@ -104,7 +106,7 @@ noncomputable instance instInnerProductSpaceQuot : InnerProductSpace ℂ (A ⧸ `InnerProductSpace` instance on the quotient is built reducibly from the corresponding `InnerProductSpace.Core`. -/ private lemma inner_quotient_eq (x y : A ⧸ Nω) : - @inner ℂ (A ⧸ Nω) _ x y = innerQuotient ω x y := rfl + ⟪x, y⟫_ℂ = innerQuotient ω x y := rfl /-- The squared norm of the class `[x]` equals the real part `Re (ω (star x * x))`. -/ private lemma norm_sq_eq_inner (x : A) : @@ -185,7 +187,7 @@ lemma πω'_mul (a b : A) (c : A ⧸ Nω) : πω' ω (a * b) c = πω' ω a (π /-- Adjoint property of the algebraic action: `⟪πω'(a) b, c⟫ = ⟪b, πω'(a*) c⟫`. -/ lemma πω'_inner (a : A) (b c : A ⧸ Nω) : - @inner ℂ (A ⧸ Nω) _ (πω' ω a b) c = @inner ℂ (A ⧸ Nω) _ b (πω' ω (star a) c) := by + ⟪πω' ω a b, c⟫_ℂ = ⟪b, πω' ω (star a) c⟫_ℂ := by refine Quotient.inductionOn₂' b c fun b' c' => ?_ unfold πω' simp only [Quotient.liftOn'_mk''] @@ -236,7 +238,7 @@ noncomputable def πω'CLM (a : A) : (A ⧸ Nω) →L[ℂ] (A ⧸ Nω) := dense quotient into its Hilbert space completion. -/ noncomputable def πω (a : A) : 𝓑(Hω) := ContinuousLinearMap.extend - (UniformSpace.Completion.toComplL.comp (πω'CLM ω a)) + (UniformSpace.Completion.toComplL ∘L (πω'CLM ω a)) (UniformSpace.Completion.toComplL (𝕜 := ℂ) (E := A ⧸ Nω)) /-- Agreement on the dense subspace: `πω(a) (↑x) = ↑(πω'(a) x)` for `x : A ⧸ Nω`. -/ @@ -260,27 +262,27 @@ lemma πω_mul (a b : A) : πω ω (a * b) = πω ω a ∘L πω ω b := by intro x simp [ContinuousLinearMap.comp_apply, πω_apply_coe, πω'_mul] -/-- *-preservation: `(πω(a)).adjoint = πω (star a)`. -/ -lemma πω_star (a : A) : (πω ω a).adjoint = πω ω (star a) := by +/-- *-preservation: `(πω a)† = πω (star a)`. -/ +lemma πω_star (a : A) : (πω ω a)† = πω ω (star a) := by ext x refine DenseRange.induction_on - (p := fun x => (πω ω a).adjoint x = πω ω (star a) x) + (p := fun x => (πω ω a)† x = πω ω (star a) x) (UniformSpace.Completion.denseRange_coe (α := A ⧸ Nω)) x - (isClosed_eq ((πω ω a).adjoint).continuous (πω ω (star a)).continuous) + (isClosed_eq ((πω ω a)†).continuous (πω ω (star a)).continuous) (fun c => by -- Reduce to checking equality of inner products with arbitrary y (Riesz representation) have : ∀ y, - @inner ℂ Hω _ ((πω ω a).adjoint (↑c)) y = @inner ℂ Hω _ (πω ω (star a) (↑c)) y := by + ⟪(πω ω a)† (↑c), y⟫_ℂ = ⟪πω ω (star a) (↑c), y⟫_ℂ := by intro y refine DenseRange.induction_on (p := fun y => - @inner ℂ Hω _ ((πω ω a).adjoint (↑c)) y = @inner ℂ Hω _ (πω ω (star a) (↑c)) y) + ⟪(πω ω a)† (↑c), y⟫_ℂ = ⟪πω ω (star a) (↑c), y⟫_ℂ) (UniformSpace.Completion.denseRange_coe (α := A ⧸ Nω)) y (isClosed_eq (Continuous.inner continuous_const continuous_id) (Continuous.inner continuous_const continuous_id)) (fun d => by -- Now both vectors are in the dense subspace; rewrite via the quotient-level identity - change @inner ℂ Hω _ ((πω ω a).adjoint (↑c)) (↑d) = @inner ℂ Hω _ (πω ω (star a) (↑c)) (↑d) + change ⟪(πω ω a)† (↑c), (↑d)⟫_ℂ = ⟪πω ω (star a) (↑c), (↑d)⟫_ℂ rw [ContinuousLinearMap.adjoint_inner_left] simp only [πω_apply_coe] rw [UniformSpace.Completion.inner_coe, UniformSpace.Completion.inner_coe] @@ -439,13 +441,13 @@ lemma stateOnHilbert_coe (x : A ⧸ Nω) : (h_e := (UniformSpace.Completion.isUniformEmbedding_coe (α := A ⧸ Nω)).isUniformInducing)] /-- Riesz identification: `⟪ξω, x⟫ = stateOnHilbert x`. -/ -lemma inner_ξω_eq (x : Hω) : @inner ℂ Hω _ (ξω ω) x = stateOnHilbert ω x := by +lemma inner_ξω_eq (x : Hω) : ⟪ξω ω, x⟫_ℂ = stateOnHilbert ω x := by unfold ξω rw [@InnerProductSpace.toDual_symm_apply ℂ Hω _ _ _ _] /-- Recovery of the original state on the quotient: `ω x = ⟪ξω, [x]⟫`. -/ lemma state_recovery_quot (x : A) : - ω x = @inner ℂ Hω _ (ξω ω) (↑(Quotient.mk'' x : A ⧸ Nω) : Hω) := by + ω x = ⟪ξω ω, (↑(Quotient.mk'' x : A ⧸ Nω) : Hω)⟫_ℂ := by rw [inner_ξω_eq] rw [stateOnHilbert_coe] rfl @@ -467,17 +469,19 @@ lemma πω_cyclic_identity (b : A) : intro yq obtain ⟨c, rfl⟩ := Quotient.exists_rep yq -- Typeclass instances are resolved using the renamed quotient instances - calc @inner ℂ Hω _ (πω ω b (ξω ω)) (↑(Quotient.mk'' c : A ⧸ Nω)) - = @inner ℂ Hω _ (ξω ω) (ContinuousLinearMap.adjoint (πω ω b) (↑(Quotient.mk'' c : A ⧸ Nω))) := by + calc ⟪πω ω b (ξω ω), (↑(Quotient.mk'' c : A ⧸ Nω) : Hω)⟫_ℂ + = ⟪ξω ω, (πω ω b)† (↑(Quotient.mk'' c : A ⧸ Nω) : Hω)⟫_ℂ := by rw [ContinuousLinearMap.adjoint_inner_right] - _ = @inner ℂ Hω _ (ξω ω) (πω ω (star b) (↑(Quotient.mk'' c : A ⧸ Nω))) := by + _ = ⟪ξω ω, πω ω (star b) (↑(Quotient.mk'' c : A ⧸ Nω) : Hω)⟫_ℂ := by rw [πω_star] - _ = @inner ℂ Hω _ (ξω ω) (↑(Quotient.mk'' (star b * c) : A ⧸ Nω)) := by rw [πω_apply_quotient_coe] + _ = ⟪ξω ω, (↑(Quotient.mk'' (star b * c) : A ⧸ Nω) : Hω)⟫_ℂ := by rw [πω_apply_quotient_coe] _ = stateOnHilbert ω (↑(Quotient.mk'' (star b * c) : A ⧸ Nω)) := by rw [inner_ξω_eq] _ = stateOnQuot ω (Quotient.mk'' (star b * c)) := by rw [stateOnHilbert_coe] _ = ω (star b * c) := rfl _ = innerQuotient ω (Quotient.mk'' b) (Quotient.mk'' c) := by unfold innerQuotient; simp + -- The bare quotient/completion coercions give the elaborator no type anchor for the + -- `⟪·,·⟫_ℂ` instance metavariable, so the inner product is spelled explicitly here. _ = @inner ℂ (A ⧸ Nω) _ (Quotient.mk'' b) (Quotient.mk'' c) := rfl _ = @inner ℂ Hω _ (↑(Quotient.mk'' b : A ⧸ Nω)) (↑(Quotient.mk'' c : A ⧸ Nω)) := by -- Lift inner product from dense subspace into completion @@ -503,7 +507,7 @@ lemma ξω_is_cyclic : Dense (↑(Submodule.span ℂ {πω ω a (ξω ω) | a : /-- GNS identity for the constructed triplet: `ω a = ⟪ξω, πω a ξω⟫`. -/ lemma state_recovery (a : A) : - ω a = @inner ℂ Hω _ (ξω ω) (πω ω a (ξω ω)) := by + ω a = ⟪ξω ω, πω ω a (ξω ω)⟫_ℂ := by rw [πω_cyclic_identity] exact state_recovery_quot ω a @@ -753,15 +757,15 @@ lemma approxUnit_eval_tendsto_one : Tendsto (fun e : A => ω e) (CStarAlgebra.approximateUnit A) (nhds (1 : ℂ)) := by classical have h_vec := tendsto_on_vector (ω := ω) (x := ξω ω) - have h_inner : Continuous fun v : Hω => @inner ℂ Hω _ (ξω ω) v := + have h_inner : Continuous fun v : Hω => ⟪ξω ω, v⟫_ℂ := Continuous.inner continuous_const continuous_id have h_comp : - Tendsto (fun e : A => @inner ℂ Hω _ (ξω ω) (πω ω e (ξω ω))) + Tendsto (fun e : A => ⟪ξω ω, πω ω e (ξω ω)⟫_ℂ) (CStarAlgebra.approximateUnit A) - (nhds (@inner ℂ Hω _ (ξω ω) (ξω ω))) := + (nhds ⟪ξω ω, ξω ω⟫_ℂ) := (h_inner.tendsto (ξω ω)).comp h_vec have h_eq : - (fun e : A => @inner ℂ Hω _ (ξω ω) (πω ω e (ξω ω))) = + (fun e : A => ⟪ξω ω, πω ω e (ξω ω)⟫_ℂ) = fun e : A => ω e := by funext e simpa using (state_recovery (ω := ω) e).symm From 2aeecea2b992473bf3aa0347e617347826857223 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 21 Jun 2026 12:46:10 +0000 Subject: [PATCH 014/113] =?UTF-8?q?refactor(cstar):=20adopt=20=E2=9F=AA?= =?UTF-8?q?=C2=B7,=C2=B7=E2=9F=AB=20and=20=E2=80=A0=20notation=20in=20repr?= =?UTF-8?q?esentation=20layer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spell the adjoint as `†` and inner products as `⟪·,·⟫_ℂ` across the `CStarRep` representation layer (unitary equivalence, conjugation, irreducibility, hom, direct sums) and the WOT double-commutant development, so intertwiner and adjoint identities read as in the source texts. Comments and docstrings using `U⋆`/`(·)*` for the adjoint are unified to `†`. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Algebra/CStarAlgebra/GNS/DirectSum.lean | 7 ++-- .../Representation/Conjugation.lean | 36 ++++++++++--------- .../Representation/DirectSum.lean | 4 ++- .../CStarAlgebra/Representation/Hom.lean | 5 ++- .../Representation/Irreducible.lean | 15 ++++---- .../Representation/UnitaryEquiv.lean | 32 +++++++++-------- .../DoubleCommutant/WOTClosedSubAlgebra.lean | 12 ++++--- 7 files changed, 64 insertions(+), 47 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean index 793e5e9..8e4a165 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean @@ -3,9 +3,12 @@ module public import Mathlib.Analysis.CStarAlgebra.Hom public import Mathlib.Analysis.InnerProductSpace.l2Space public import QuantumSystem.Algebra.CStarAlgebra.GNS.PureState +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation @[expose] public section +open scoped Adjoint + namespace GNS namespace DirectSum @@ -124,10 +127,10 @@ noncomputable def directSumCLM (a : A) : 𝓑(Hilbert A) := LinearMap.mkContinuous (directSumLinearMap a) ‖a‖ (componentWiseMap_norm_bound a) /-- The adjoint of the direct sum operator equals the direct sum operator of the adjoint: -`(directSumCLM a)* = directSumCLM (star a)`. This follows from the *-homomorphism property +`(directSumCLM a)† = directSumCLM (star a)`. This follows from the *-homomorphism property of each component GNS representation. -/ lemma directSumCLM_adjoint (a : A) : - ContinuousLinearMap.adjoint (directSumCLM a) = directSumCLM (star a) := by + (directSumCLM a)† = directSumCLM (star a) := by refine ContinuousLinearMap.ext fun x => ?_ apply ext_inner_right ℂ intro y diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean index 34c61e1..8eb6db1 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean @@ -11,7 +11,7 @@ representation** is the `CStarRep A` on `K` whose action sends `a : A` to the bounded operator ``` -U ∘L R.π a ∘L U⋆ : K →L[ℂ] K. +U ∘L R.π a ∘L U† : K →L[ℂ] K. ``` The unitary `U` itself intertwines `R` with `R.conjBy U`, so the two @@ -33,7 +33,7 @@ DHR-localisation region. ## Main results -* `CStarRep.conjBy_π_apply` — `(R.conjBy U).π a = U R.π a U⋆`. +* `CStarRep.conjBy_π_apply` — `(R.conjBy U).π a = U R.π a U†`. * `CStarRep.conjBy_π_eq_of_intertwined` — if the intertwining identity `U ∘L R.π a = T ∘L U` holds at a particular operator `T`, then `(R.conjBy U).π a = T`. This is the bridge to the DHR structure @@ -49,13 +49,15 @@ DHR-localisation region. @[expose] public section +open scoped Adjoint + namespace CStarRep variable {A : Type*} [NonUnitalCStarAlgebra A] /-- The **conjugated representation** of `R : CStarRep A` by a unitary `U : UnitaryMap R.H K`: the carrier is `K` and the action is -`a ↦ U ∘L R.π a ∘L U⋆`. +`a ↦ U ∘L R.π a ∘L U†`. Internally the underlying non-unital star-algebra homomorphism is the composition of `R.π` with the conjugation-by-`U` star-algebra @@ -72,11 +74,11 @@ noncomputable def conjBy (R : CStarRep A) {K : Type*} [ComplexHilbertSpace K] (U : UnitaryMap R.H K) : (R.conjBy U).H = K := rfl /-- The action of the conjugated representation: `(R.conjBy U).π a` is -the operator `U ∘L R.π a ∘L U⋆` on `K`. -/ +the operator `U ∘L R.π a ∘L U†` on `K`. -/ @[simp] lemma conjBy_π_apply (R : CStarRep A) {K : Type*} [ComplexHilbertSpace K] (U : UnitaryMap R.H K) (a : A) : (R.conjBy U).π a = - U.toContinuousLinearMap ∘L R.π a ∘L U.toContinuousLinearMap.adjoint := by + U.toContinuousLinearMap ∘L R.π a ∘L U.toContinuousLinearMap† := by -- `conjStarAlgEquiv` is defined so that `e.conjStarAlgEquiv x = e ∘L x ∘L e.symm` -- and `UnitaryMap.toLinearIsometryEquiv` is built with `toFun = U.toCLM` and -- `invFun = U.toCLM.adjoint`, so both sides reduce to the same CLM. @@ -86,27 +88,27 @@ the operator `U ∘L R.π a ∘L U⋆` on `K`. -/ /-- The **canonical unitary equivalence** `R ≃ R.conjBy U`: the intertwining unitary is `U` itself, and the intertwining identity is -`U ∘L R.π a = (U R.π a U⋆) ∘L U`, which follows from `U⋆ U = id`. -/ +`U ∘L R.π a = (U R.π a U†) ∘L U`, which follows from `U† U = id`. -/ noncomputable def conjByUnitaryEquiv (R : CStarRep A) {K : Type*} [ComplexHilbertSpace K] (U : UnitaryMap R.H K) : CStarRep.UnitaryEquiv R (R.conjBy U) where unitary_map := U intertwines a := by -- LHS: `U ∘L R.π a`. - -- RHS: `(R.conjBy U).π a ∘L U = U ∘L R.π a ∘L U⋆ ∘L U = U ∘L R.π a` - -- using `U⋆ U = id` from `U.adjoint_comp`. + -- RHS: `(R.conjBy U).π a ∘L U = U ∘L R.π a ∘L U† ∘L U = U ∘L R.π a` + -- using `U† U = id` from `U.adjoint_comp`. rw [conjBy_π_apply] apply ContinuousLinearMap.ext intro x - have h : U.toContinuousLinearMap.adjoint + have h : U.toContinuousLinearMap† (U.toContinuousLinearMap x) = x := by have := congrArg (fun (f : R.H →L[ℂ] R.H) => f x) U.adjoint_comp simpa using this - -- Goal: `U (R.π a x) = U (R.π a (U⋆ (U x)))`. Unfold nested + -- Goal: `U (R.π a x) = U (R.π a (U† (U x)))`. Unfold nested -- `.comp` applications and then rewrite with `h`. change U.toContinuousLinearMap ((R.π a) x) = - U.toContinuousLinearMap ((R.π a) (U.toContinuousLinearMap.adjoint + U.toContinuousLinearMap ((R.π a) (U.toContinuousLinearMap† (U.toContinuousLinearMap x))) rw [h] @@ -129,19 +131,19 @@ lemma conjBy_π_eq_of_intertwined {R : CStarRep A} {a : A} {T : K →L[ℂ] K} (hUa : U.toContinuousLinearMap ∘L R.π a = T ∘L U.toContinuousLinearMap) : (R.conjBy U).π a = T := by - -- From `U ∘L R.π a = T ∘L U`, post-compose with `U⋆`: - -- `U ∘L R.π a ∘L U⋆ = T ∘L U ∘L U⋆ = T` using `U U⋆ = id`. + -- From `U ∘L R.π a = T ∘L U`, post-compose with `U†`: + -- `U ∘L R.π a ∘L U† = T ∘L U ∘L U† = T` using `U U† = id`. rw [conjBy_π_apply] apply ContinuousLinearMap.ext intro y - -- Apply `hUa` at the point `U⋆ y`. + -- Apply `hUa` at the point `U† y`. have hy := congrArg - (fun (f : R.H →L[ℂ] K) => f (U.toContinuousLinearMap.adjoint y)) hUa + (fun (f : R.H →L[ℂ] K) => f (U.toContinuousLinearMap† y)) hUa simp only [ContinuousLinearMap.coe_comp', Function.comp_apply] at hy ⊢ rw [hy] - -- Remaining: `T (U (U⋆ y)) = T y`. + -- Remaining: `T (U (U† y)) = T y`. have hUU : U.toContinuousLinearMap - (U.toContinuousLinearMap.adjoint y) = y := by + (U.toContinuousLinearMap† y) = y := by have := congrArg (fun (f : K →L[ℂ] K) => f y) U.comp_adjoint simpa using this diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean index adc15ac..499d7b0 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean @@ -4,6 +4,7 @@ public import Mathlib.Analysis.CStarAlgebra.Spectrum public import Mathlib.Analysis.InnerProductSpace.l2Space public import Mathlib.Data.Real.StarOrdered public import QuantumSystem.Algebra.CStarAlgebra.Representation.Family +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation /-! # Direct sum of a sector family @@ -47,6 +48,7 @@ decomposition. The skeleton version @[expose] public section open ENNReal +open scoped Adjoint namespace SectorFamily @@ -232,7 +234,7 @@ noncomputable def directSumCLM (F : SectorFamily.{u, v, w} A) (a : A) : /-- Block-diagonality is compatible with the `*`-structure. -/ lemma directSumCLM_adjoint (F : SectorFamily.{u, v, w} A) (a : A) : - ContinuousLinearMap.adjoint (F.directSumCLM a) = F.directSumCLM (star a) := by + (F.directSumCLM a)† = F.directSumCLM (star a) := by refine ContinuousLinearMap.ext fun x => ?_ apply ext_inner_right ℂ intro y diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean index 31f79c0..8c61b87 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Hom.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation /-! # Intertwiners between `CStarRep`s @@ -30,6 +31,8 @@ isomorphisms in this category. @[expose] public section +open scoped Adjoint + namespace CStarRep variable {A : Type*} [NonUnitalCStarAlgebra A] @@ -107,7 +110,7 @@ noncomputable def toHom (U : UnitaryEquiv R₁ R₂) : Hom R₁ R₂ where @[simp] lemma symm_toHom (U : UnitaryEquiv R₁ R₂) : U.symm.toHom.toContinuousLinearMap = - U.unitary_map.toContinuousLinearMap.adjoint := rfl + U.unitary_map.toContinuousLinearMap† := rfl @[simp] lemma refl_toHom (R : CStarRep A) : (UnitaryEquiv.refl R).toHom = Hom.id R := by diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean index 54c622f..1c27020 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/Irreducible.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation /-! # Irreducibility for `CStarRep` @@ -29,6 +30,8 @@ descend to the quotient). @[expose] public section +open scoped Adjoint + namespace CStarRep variable {A : Type*} [NonUnitalCStarAlgebra A] @@ -75,11 +78,11 @@ private lemma isIrreducible_of {R₁ R₂ : CStarRep A} refine Or.inl ?_ refine le_antisymm ?_ bot_le intro w hw - -- Surjectivity of `f`: `w = f (f.adjoint w)` since `f ∘L f.adjoint = 1`. - have hsurj : f (f.adjoint w) = w := by + -- Surjectivity of `f`: `w = f (f† w)` since `f ∘L f† = 1`. + have hsurj : f (f† w) = w := by have := congrArg (fun (g : R₂.H →L[ℂ] R₂.H) => g w) U.unitary_map.comp_adjoint simpa using this - set x := f.adjoint w with hx_def + set x := f† w with hx_def have hx_mem : x ∈ W' := by change f x ∈ W rw [hx_def]; rw [hsurj] @@ -93,12 +96,12 @@ private lemma isIrreducible_of {R₁ R₂ : CStarRep A} refine Or.inr ?_ refine le_antisymm le_top ?_ intro w _ - have hsurj : f (f.adjoint w) = w := by + have hsurj : f (f† w) = w := by have := congrArg (fun (g : R₂.H →L[ℂ] R₂.H) => g w) U.unitary_map.comp_adjoint simpa using this - have hx_mem : f.adjoint w ∈ W' := + have hx_mem : f† w ∈ W' := htop ▸ Submodule.mem_top - have hfx : f (f.adjoint w) ∈ W := hx_mem + have hfx : f (f† w) ∈ W := hx_mem rw [hsurj] at hfx exact hfx diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean index 026c6a0..350e72a 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/UnitaryEquiv.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.CStarAlgebra.Representation +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation /-! # Unitary equivalence of `CStarRep`s @@ -32,6 +33,8 @@ unrelated origin. @[expose] public section +open scoped Adjoint + namespace CStarRep variable {A : Type*} [NonUnitalCStarAlgebra A] @@ -66,7 +69,7 @@ noncomputable def refl (R : CStarRep A) : UnitaryEquiv R R where noncomputable def symm {R₁ R₂ : CStarRep A} (U : UnitaryEquiv R₁ R₂) : UnitaryEquiv R₂ R₁ where unitary_map := - { toContinuousLinearMap := U.unitary_map.toContinuousLinearMap.adjoint + { toContinuousLinearMap := U.unitary_map.toContinuousLinearMap† adjoint_comp := by rw [ContinuousLinearMap.adjoint_adjoint] exact U.unitary_map.comp_adjoint @@ -80,18 +83,17 @@ noncomputable def symm {R₁ R₂ : CStarRep A} (U : UnitaryEquiv R₁ R₂) : -- `a ↦ star a` (and using `star (star a) = a`) yields the goal. have h := U.intertwines (star a) have h' : - (U.unitary_map.toContinuousLinearMap ∘L R₁.π (star a)).adjoint = - (R₂.π (star a) ∘L U.unitary_map.toContinuousLinearMap).adjoint := by + (U.unitary_map.toContinuousLinearMap ∘L R₁.π (star a))† = + (R₂.π (star a) ∘L U.unitary_map.toContinuousLinearMap)† := by rw [h] rw [ContinuousLinearMap.adjoint_comp, ContinuousLinearMap.adjoint_comp] at h' - -- Now `(π₁ (star a))† ∘L U†.adjoint.adjoint = U†.adjoint.adjoint ∘L (π₂ (star a))†`. - -- But the LHS is `(π₁ (star a))† ∘L U†` after no rewriting since adjoint sits in - -- the outer position. The relevant simp lemma: `(π a)† = π (star a)`. - have hπ₁ : (R₁.π (star a)).adjoint = R₁.π a := by + -- Now `h' : (π₁ (star a))† ∘L U† = U† ∘L (π₂ (star a))†`. + -- It remains to rewrite `(πᵢ (star a))† = πᵢ a` via `(π a)† = π (star a)` and `star_star`. + have hπ₁ : (R₁.π (star a))† = R₁.π a := by have := (R₁.π).map_star' (star a) rw [ContinuousLinearMap.star_eq_adjoint, star_star] at this exact this.symm - have hπ₂ : (R₂.π (star a)).adjoint = R₂.π a := by + have hπ₂ : (R₂.π (star a))† = R₂.π a := by have := (R₂.π).map_star' (star a) rw [ContinuousLinearMap.star_eq_adjoint, star_star] at this exact this.symm @@ -112,7 +114,7 @@ noncomputable def trans {R₁ R₂ R₃ : CStarRep A} simp only [ContinuousLinearMap.adjoint_comp, ContinuousLinearMap.coe_comp', Function.comp_apply, ContinuousLinearMap.one_apply] have hV : - V.unitary_map.toContinuousLinearMap.adjoint + V.unitary_map.toContinuousLinearMap† (V.unitary_map.toContinuousLinearMap (U.unitary_map.toContinuousLinearMap x)) = U.unitary_map.toContinuousLinearMap x := by have := congrArg @@ -121,7 +123,7 @@ noncomputable def trans {R₁ R₂ R₃ : CStarRep A} simpa using this rw [hV] have hU : - U.unitary_map.toContinuousLinearMap.adjoint + U.unitary_map.toContinuousLinearMap† (U.unitary_map.toContinuousLinearMap x) = x := by have := congrArg (fun (f : R₁.H →L[ℂ] R₁.H) => f x) U.unitary_map.adjoint_comp @@ -133,17 +135,17 @@ noncomputable def trans {R₁ R₂ R₃ : CStarRep A} Function.comp_apply, ContinuousLinearMap.one_apply] have hU : U.unitary_map.toContinuousLinearMap - (U.unitary_map.toContinuousLinearMap.adjoint - (V.unitary_map.toContinuousLinearMap.adjoint y)) = - V.unitary_map.toContinuousLinearMap.adjoint y := by + (U.unitary_map.toContinuousLinearMap† + (V.unitary_map.toContinuousLinearMap† y)) = + V.unitary_map.toContinuousLinearMap† y := by have := congrArg - (fun (f : R₂.H →L[ℂ] R₂.H) => f (V.unitary_map.toContinuousLinearMap.adjoint y)) + (fun (f : R₂.H →L[ℂ] R₂.H) => f (V.unitary_map.toContinuousLinearMap† y)) U.unitary_map.comp_adjoint simpa using this rw [hU] have hV : V.unitary_map.toContinuousLinearMap - (V.unitary_map.toContinuousLinearMap.adjoint y) = y := by + (V.unitary_map.toContinuousLinearMap† y) = y := by have := congrArg (fun (f : R₃.H →L[ℂ] R₃.H) => f y) V.unitary_map.comp_adjoint simpa using this diff --git a/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean b/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean index 36de546..dcb23e6 100644 --- a/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean +++ b/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean @@ -3,6 +3,7 @@ module public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.DiagonalAmplification public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.InvariantSubspace public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.WeakOperatorTopology +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation /-! # The double commutant theorem (hard half) @@ -67,6 +68,7 @@ To prove the hard-half statement `A'' ⊆ A`, we argue by separation: namespace WOTClosedSubalgebra open InnerProductSpace WeakOperatorTopology +open scoped Adjoint variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] @@ -153,14 +155,14 @@ lemma isReducing_cyclicSubspace (A : StarSubalgebra ℂ B) (x : H) : refine ⟨?_, ?_⟩ · exact isInvariant_cyclicSubspace_of_mem (H := H) (A := A) (x := x) (a := a) ha · -- Use `A` is star-closed. - have ha' : ContinuousLinearMap.adjoint a ∈ (A : Set B) := by + have ha' : a† ∈ (A : Set B) := by -- `star` on `B` is adjoint. have : (star a) ∈ (A : Set B) := A.star_mem' ha simpa [ContinuousLinearMap.star_eq_adjoint] using this -- Now apply invariance to `a†`. simpa using (isInvariant_cyclicSubspace_of_mem (H := H) (A := A) (x := x) - (a := ContinuousLinearMap.adjoint a) ha') + (a := a†) ha') /-- `T` preserves the reducing subspaces for `S` if it leaves invariant every `S`-reducing subspace (and also its orthogonal complement). -/ @@ -279,14 +281,14 @@ theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) f ((toWOTEquiv (H := H)) S) = g (diagonal (H := H) (n := n) S x) := by classical have hg : g (diagonal (H := H) (n := n) S x) = - ∑ i : Fin n, @inner ℂ H _ (uFun i) (S (xFun i)) := by + ∑ i : Fin n, ⟪uFun i, S (xFun i)⟫_ℂ := by simp only [g, u, x] rw [InnerProductSpace.toDual_apply_apply, PiLp.inner_apply] congr 1 funext i simp only [diagonal_apply, uFun, xFun, WithLp.equiv_symm_apply] have hf : f ((toWOTEquiv (H := H)) S) = - ∑ i : Fin n, @inner ℂ H _ (uFun i) (S (xFun i)) := by + ∑ i : Fin n, ⟪uFun i, S (xFun i)⟫_ℂ := by classical have hsum : (∑ j : (↥I), (coeff j) • ((inducingFnRestrictCLM (H := H) I) ((toWOTEquiv (H := H)) S) j)) = @@ -314,7 +316,7 @@ theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) simp only [toWOTEquiv, ContinuousLinearMap.toWOT_apply] conv_lhs => rw [show (e i).1.2 (S (e i).1.1) = - @inner ℂ H _ ((InnerProductSpace.toDual ℂ H).symm (e i).1.2) (S (e i).1.1) from + ⟪(InnerProductSpace.toDual ℂ H).symm (e i).1.2, S (e i).1.1⟫_ℂ from InnerProductSpace.toDual_symm_apply.symm] simp only [uFun, xFun, inner_smul_left, starRingEnd_self_apply, smul_eq_mul] simpa [hg] using hf From 98c276c67bf6649fa5f001871fca16bc1a869a12 Mon Sep 17 00:00:00 2001 From: suzuki Date: Wed, 24 Jun 2026 11:54:14 +0000 Subject: [PATCH 015/113] refactor: replace bespoke matrixFunction/matrixLog with Mathlib cfc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eliminate the custom spectral functional calculus `matrixFunction` (and the `matrixLog` defined on top of it), expressing all matrix functional calculus directly through Mathlib's continuous functional calculus `cfc` / `CFC.rpow`: - Löwner/Jensen convexity definitions and the Order/Effros/LiebConcavity operator-convexity proofs (rpow integral representation, compression). - von Neumann / relative entropy, Kronecker log-tensor identity, SSA. - `matrixSqrt` / `matrixInvSqrt` redefined via `CFC.rpow`. - New standalone cfc helpers: `cfc_spectral_eq`, `trace_cfc`, `trace_mul_cfc`, `cfc_isHermitian`, `mul_cfc_isHermitian`, `cfc_add_const_eq`, `cfc_inv_add_const`, `cfc_resolvent`, `cfc_compression_of_commuting`. - Delete `matrixFunction` and all `matrixFunction_*` lemmas. The `matrixLog → cfc` migration is inseparable from the `matrixFunction` removal (matrixLog was defined via matrixFunction), so the coupled entropy-module reorganization it required is bundled here as well (MutualInfoProduct, SSAProduct, StrongSubadditivityEval, partial-trace bridges, region-index equivalences). Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 7 + QuantumSystem/Algebra/LocalNet/Basic.lean | 68 +- .../Analysis/Channel/PartialTrace.lean | 214 +++++++ .../Analysis/Entropy/KroneckerProduct.lean | 128 +--- .../Analysis/Entropy/MutualInfoProduct.lean | 99 +++ .../Analysis/Entropy/RelativeEntropy.lean | 42 +- QuantumSystem/Analysis/Entropy/SSA.lean | 83 +-- .../Analysis/Entropy/SSAProduct.lean | 302 +++++++++ .../Entropy/StrongSubadditivityEval.lean | 252 ++++++++ .../Analysis/Entropy/VonNeumannEntropy.lean | 63 +- QuantumSystem/Analysis/Matrix/Effros.lean | 52 +- .../Matrix/HermitianFunctionalCalculus.lean | 580 +++++------------- .../Matrix/KroneckerPartialTraceBridge.lean | 84 +++ .../Analysis/Matrix/LiebConcavity.lean | 18 +- QuantumSystem/Analysis/Matrix/Order.lean | 464 +++++--------- .../Analysis/Matrix/PartialTrace.lean | 12 + .../LinearAlgebra/Matrix/PartialTrace.lean | 98 +++ .../LinearAlgebra/Matrix/PosDef.lean | 32 + QuantumSystem/State.lean | 10 +- 19 files changed, 1575 insertions(+), 1033 deletions(-) create mode 100644 QuantumSystem/Analysis/Channel/PartialTrace.lean create mode 100644 QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean create mode 100644 QuantumSystem/Analysis/Entropy/SSAProduct.lean create mode 100644 QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean create mode 100644 QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean create mode 100644 QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean create mode 100644 QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PosDef.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 273eb60..219b006 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -26,13 +26,18 @@ public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal +public import QuantumSystem.Analysis.Channel.PartialTrace public import QuantumSystem.Analysis.Entropy.KroneckerProduct +public import QuantumSystem.Analysis.Entropy.MutualInfoProduct public import QuantumSystem.Analysis.Entropy.Regularize public import QuantumSystem.Analysis.Entropy.RelativeEntropy public import QuantumSystem.Analysis.Entropy.SSA +public import QuantumSystem.Analysis.Entropy.SSAProduct +public import QuantumSystem.Analysis.Entropy.StrongSubadditivityEval public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy public import QuantumSystem.Analysis.Matrix.Effros public import QuantumSystem.Analysis.Matrix.HermitianFunctionalCalculus +public import QuantumSystem.Analysis.Matrix.KroneckerPartialTraceBridge public import QuantumSystem.Analysis.Matrix.LiebConcavity public import QuantumSystem.Analysis.Matrix.Order public import QuantumSystem.Analysis.Matrix.PartialTrace @@ -59,6 +64,8 @@ public import QuantumSystem.ForMathlib.Analysis.Matrix.Basic public import QuantumSystem.ForMathlib.Analysis.Matrix.Hermitian public import QuantumSystem.ForMathlib.Analysis.Matrix.Order public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun +public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace +public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PosDef public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.StarAlgEquiv public import QuantumSystem.ForMathlib.LinearAlgebra.Span.Def public import QuantumSystem.ForMathlib.LinearAlgebra.Trace diff --git a/QuantumSystem/Algebra/LocalNet/Basic.lean b/QuantumSystem/Algebra/LocalNet/Basic.lean index 84db3a8..b0af94e 100644 --- a/QuantumSystem/Algebra/LocalNet/Basic.lean +++ b/QuantumSystem/Algebra/LocalNet/Basic.lean @@ -151,6 +151,21 @@ Both are direct definitions with concrete `toFun`, so every projection evaluates variable (L : LocalNet) +/-- **1-element factorisation**: `regionIdx {a} ≃ localIdx a`. Evaluation at the single site `a`. -/ +def regionIdxSingletonEquiv (a : L.sites) : + L.regionIdx ({a} : Finset L.sites) ≃ L.localIdx a where + toFun f := f ⟨a, Finset.mem_singleton_self a⟩ + invFun x := fun ⟨s, hs⟩ => (Finset.mem_singleton.mp hs) ▸ x + left_inv f := by + funext ⟨s, hs⟩ + obtain rfl : s = a := Finset.mem_singleton.mp hs + rfl + right_inv x := rfl + +@[simp] lemma regionIdxSingletonEquiv_apply (a : L.sites) + (f : L.regionIdx ({a} : Finset L.sites)) : + L.regionIdxSingletonEquiv a f = f ⟨a, Finset.mem_singleton_self a⟩ := rfl + /-- **2-element factorisation**: `regionIdx {a, b} ≃ localIdx a × localIdx b` when `a ≠ b`. Direct definition with concrete `toFun` so both projections evaluate by `rfl`. -/ def regionIdxPairEquiv {a b : L.sites} (hab : a ≠ b) : @@ -191,12 +206,12 @@ def regionIdxPairEquiv {a b : L.sites} (hab : a ≠ b) : f ⟨b, Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)⟩) := rfl /-- Closed-form first projection of `regionIdxPairEquiv` — picks out the value at site `a`. -/ -@[simp] private lemma regionIdxPairEquiv_apply_fst {a b : L.sites} (hab : a ≠ b) +@[simp] lemma regionIdxPairEquiv_apply_fst {a b : L.sites} (hab : a ≠ b) (f : L.regionIdx ({a, b} : Finset L.sites)) : (L.regionIdxPairEquiv hab f).1 = f ⟨a, Finset.mem_insert_self a {b}⟩ := rfl /-- Closed-form second projection of `regionIdxPairEquiv` — picks out the value at site `b`. -/ -@[simp] private lemma regionIdxPairEquiv_apply_snd {a b : L.sites} (hab : a ≠ b) +@[simp] lemma regionIdxPairEquiv_apply_snd {a b : L.sites} (hab : a ≠ b) (f : L.regionIdx ({a, b} : Finset L.sites)) : (L.regionIdxPairEquiv hab f).2 = f ⟨b, Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)⟩ := rfl @@ -248,24 +263,67 @@ def regionIdxTripleEquiv {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac · simp [hca, hcb] /-- Closed-form first projection of `regionIdxTripleEquiv` — value at site `a`. -/ -@[simp] private lemma regionIdxTripleEquiv_apply_fst {a b c : L.sites} +@[simp] lemma regionIdxTripleEquiv_apply_fst {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) (f : L.regionIdx ({a, b, c} : Finset L.sites)) : (L.regionIdxTripleEquiv hab hbc hac f).1 = f ⟨a, Finset.mem_insert_self a {b, c}⟩ := rfl /-- Second projection of `regionIdxTripleEquiv` — value at site `b`. -/ -@[simp] private lemma regionIdxTripleEquiv_apply_snd_fst {a b c : L.sites} +@[simp] lemma regionIdxTripleEquiv_apply_snd_fst {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) (f : L.regionIdx ({a, b, c} : Finset L.sites)) : (L.regionIdxTripleEquiv hab hbc hac f).2.1 = f ⟨b, Finset.mem_insert_of_mem (Finset.mem_insert_self b {c})⟩ := rfl /-- Third projection of `regionIdxTripleEquiv` — value at site `c`. -/ -@[simp] private lemma regionIdxTripleEquiv_apply_snd_snd {a b c : L.sites} +@[simp] lemma regionIdxTripleEquiv_apply_snd_snd {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) (f : L.regionIdx ({a, b, c} : Finset L.sites)) : (L.regionIdxTripleEquiv hab hbc hac f).2.2 = f ⟨c, Finset.mem_insert_of_mem (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl))⟩ := rfl +/-- **Compatibility of the triple factorisation with the `{a, b}`-cut.** Reading a region index +of `{a, b, c}` that was assembled from an `{a, b}`-part `ab` and a complement-part `cc` (via +`combineIdx`) through the three-element factorisation returns the `a`- and `b`-values from `ab` +(via `regionIdxPairEquiv`) and the `c`-value from `cc`. This is the index-level statement that +the associative regrouping `(localIdx a × localIdx b) × localIdx c` underlying `combineIdx` for +`{a, b} ⊆ {a, b, c}` agrees with the right-associated `regionIdxTripleEquiv`. -/ +theorem regionIdxTripleEquiv_combineIdx {a b c : L.sites} + (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) + (h_ab : ({a, b} : Finset L.sites) ⊆ {a, b, c}) + (ab : L.regionIdx ({a, b} : Finset L.sites)) + (cc : L.regionIdx (({a, b, c} : Finset L.sites) \ {a, b})) + (hc : c ∈ ({a, b, c} : Finset L.sites) \ {a, b}) : + L.regionIdxTripleEquiv hab hbc hac (L.combineIdx h_ab (ab, cc)) + = ((L.regionIdxPairEquiv hab ab).1, (L.regionIdxPairEquiv hab ab).2, cc ⟨c, hc⟩) := by + have hca : c ∉ ({a, b} : Finset L.sites) := (Finset.mem_sdiff.mp hc).2 + refine Prod.ext ?_ (Prod.ext ?_ ?_) <;> simp [hca] + +/-- **Compatibility of the triple factorisation with the `{b, c}`-cut.** The dual of +`regionIdxTripleEquiv_combineIdx` for the inclusion `{b, c} ⊆ {a, b, c}`: the `a`-value comes from +the complement part, the `b`- and `c`-values from the `{b, c}`-part via `regionIdxPairEquiv`. -/ +theorem regionIdxTripleEquiv_combineIdx_bc {a b c : L.sites} + (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) + (h_bc : ({b, c} : Finset L.sites) ⊆ {a, b, c}) + (bc : L.regionIdx ({b, c} : Finset L.sites)) + (aa : L.regionIdx (({a, b, c} : Finset L.sites) \ {b, c})) + (ha : a ∈ ({a, b, c} : Finset L.sites) \ {b, c}) : + L.regionIdxTripleEquiv hab hbc hac (L.combineIdx h_bc (bc, aa)) + = (aa ⟨a, ha⟩, (L.regionIdxPairEquiv hbc bc).1, (L.regionIdxPairEquiv hbc bc).2) := by + have haa : a ∉ ({b, c} : Finset L.sites) := (Finset.mem_sdiff.mp ha).2 + refine Prod.ext ?_ (Prod.ext ?_ ?_) <;> simp [haa] + +/-- **Compatibility of the pair factorisation with the `{a}`-cut.** For `{a} ⊆ {a, b}`, the +`a`-value comes from the singleton part, the `b`-value from the complement part. -/ +theorem regionIdxPairEquiv_combineIdx {a b : L.sites} (hab : a ≠ b) + (h_a : ({a} : Finset L.sites) ⊆ {a, b}) + (ma : L.regionIdx ({a} : Finset L.sites)) + (mb : L.regionIdx (({a, b} : Finset L.sites) \ {a})) + (hb : b ∈ ({a, b} : Finset L.sites) \ {a}) : + L.regionIdxPairEquiv hab (L.combineIdx h_a (ma, mb)) + = (L.regionIdxSingletonEquiv a ma, mb ⟨b, hb⟩) := by + have hba : b ∉ ({a} : Finset L.sites) := (Finset.mem_sdiff.mp hb).2 + refine Prod.ext ?_ ?_ <;> simp [hba] + end LocalNet diff --git a/QuantumSystem/Analysis/Channel/PartialTrace.lean b/QuantumSystem/Analysis/Channel/PartialTrace.lean new file mode 100644 index 0000000..89958ea --- /dev/null +++ b/QuantumSystem/Analysis/Channel/PartialTrace.lean @@ -0,0 +1,214 @@ +module + +public import QuantumSystem.Channel +public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace + +/-! +# Partial trace as a quantum channel (product index types) + +The **partial trace** on plain product index types `X × Y`, packaged as a completely positive +trace-preserving map (`QuantumChannel`). This is the `LocalNet`-free analogue of +`Matrix.QuantumChannel.restrict` (`Analysis/Matrix/PartialTrace.lean`): it traces out the right +factor `Y` of a matrix on `X × Y`, leaving a matrix on `X`. The construction mirrors the region +version with `LocalNet.combineIdx (a, b)` replaced by the plain pair `(x, y)`. + +We also package conjugation by an index equivalence (`reindexₗ`) as a channel, and compose the two +into the trace-out-`C` channel `QuantumChannel.traceOutC : QuantumChannel (A × B × C) (A × B)`, +whose action is exactly the `lean-eval` marginal map +`M ↦ traceRight (M.reindex (prodAssoc).symm (prodAssoc).symm)`. + +## Main definitions + +* `Matrix.partialTraceRightₗ` — right partial trace as a `ℂ`-linear map. +* `Matrix.QuantumChannel.partialTraceRight` — bundled quantum channel tracing out `Y`. +* `Matrix.QuantumChannel.reindex` — conjugation by an index equivalence, as a channel. +* `Matrix.QuantumChannel.traceOutC` — trace out the `C` factor of `A × B × C`. +-/ + +@[expose] public section + +namespace Matrix + +open scoped ComplexOrder + +/-! ### Positive semidefiniteness and trace facts for the partial trace -/ + +/-- The right partial trace preserves positive semidefiniteness (it is a sum of principal +submatrices). -/ +theorem traceRight_posSemidef {l n : Type*} [Fintype n] + {M : Matrix (l × n) (l × n) ℂ} (hM : M.PosSemidef) : (Matrix.traceRight M).PosSemidef := by + have hsum : Matrix.traceRight M + = ∑ k : n, M.submatrix (fun i : l => (i, k)) (fun j : l => (j, k)) := by + ext i j; simp [Matrix.traceRight_apply, Matrix.sum_apply, Matrix.submatrix_apply] + rw [hsum] + exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) + +/-- The left partial trace preserves positive semidefiniteness. -/ +theorem traceLeft_posSemidef {l n : Type*} [Fintype n] + {M : Matrix (n × l) (n × l) ℂ} (hM : M.PosSemidef) : (Matrix.traceLeft M).PosSemidef := by + have hsum : Matrix.traceLeft M + = ∑ k : n, M.submatrix (fun i : l => (k, i)) (fun j : l => (k, j)) := by + ext i j; simp [Matrix.traceLeft_apply, Matrix.sum_apply, Matrix.submatrix_apply] + rw [hsum] + exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) + +/-- Reindexing by an index equivalence preserves the trace. -/ +@[simp] theorem trace_reindex_self {n m : Type*} [Fintype n] [Fintype m] (e : n ≃ m) + (M : Matrix n n ℂ) : (M.reindex e e).trace = M.trace := by + simp only [Matrix.trace, Matrix.diag_apply, Matrix.reindex_apply, Matrix.submatrix_apply] + exact Equiv.sum_comp e.symm (fun i => M i i) + +/-- The right partial trace of the identity scales by the cardinality of the traced factor. -/ +theorem traceRight_one {X Y : Type*} [DecidableEq X] [Fintype Y] [DecidableEq Y] : + Matrix.traceRight (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card Y : ℂ) • (1 : Matrix X X ℂ) := by + ext i j + simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] + by_cases hij : i = j + · subst hij; simp [Finset.card_univ] + · simp [hij] + +/-- The left partial trace of the identity scales by the cardinality of the traced factor. -/ +theorem traceLeft_one {X Y : Type*} [Fintype X] [DecidableEq X] [DecidableEq Y] : + Matrix.traceLeft (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card X : ℂ) • (1 : Matrix Y Y ℂ) := by + ext i j + simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] + by_cases hij : i = j + · subst hij; simp [Finset.card_univ] + · simp [hij] + +/-! ### Right partial trace as a linear map -/ + +/-- `Matrix.traceRight` as a `ℂ`-linear map `Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix X X ℂ`. -/ +noncomputable def partialTraceRightₗ {X Y : Type*} [Fintype Y] : + Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix X X ℂ where + toFun M := Matrix.traceRight M + map_add' M N := by + ext i j; simp only [traceRight_apply, Matrix.add_apply, Finset.sum_add_distrib] + map_smul' c M := by + ext i j + simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, RingHom.id_apply, Finset.mul_sum] + +@[simp] lemma partialTraceRightₗ_apply {X Y : Type*} [Fintype Y] (M : Matrix (X × Y) (X × Y) ℂ) : + partialTraceRightₗ M = Matrix.traceRight M := rfl + +/-- `Matrix.traceLeft` as a `ℂ`-linear map `Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix Y Y ℂ`. -/ +noncomputable def partialTraceLeftₗ {X Y : Type*} [Fintype X] : + Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix Y Y ℂ where + toFun M := Matrix.traceLeft M + map_add' M N := by + ext i j; simp only [traceLeft_apply, Matrix.add_apply, Finset.sum_add_distrib] + map_smul' c M := by + ext i j + simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, RingHom.id_apply, Finset.mul_sum] + +@[simp] lemma partialTraceLeftₗ_apply {X Y : Type*} [Fintype X] (M : Matrix (X × Y) (X × Y) ℂ) : + partialTraceLeftₗ M = Matrix.traceLeft M := rfl + +/-! ### Kraus operators and complete positivity -/ + +/-- Kraus operator for the right partial trace, indexed by `y : Y`: `K_y x p = [p = (x, y)]`. -/ +def traceRightKraus {X Y : Type*} [DecidableEq X] [DecidableEq Y] (y : Y) : + Matrix X (X × Y) ℂ := + Matrix.of fun x p => if p = (x, y) then (1 : ℂ) else 0 + +theorem isCompletelyPositive_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : + IsCompletelyPositive (partialTraceRightₗ (X := X) (Y := Y)) := by + classical + refine ⟨Fintype.card Y, fun i => traceRightKraus ((Fintype.equivFin Y).symm i), fun M => ?_⟩ + rw [partialTraceRightₗ_apply] + ext i j + rw [traceRight_apply, Matrix.sum_apply, ← (Fintype.equivFin Y).symm.sum_comp + (fun y => M (i, y) (j, y))] + refine Finset.sum_congr rfl fun p _ => ?_ + -- Goal: M (i, y) (j, y) = (K_y * M * K_yᴴ) i j with `y = (equivFin Y).symm p` + -- (mul is `Matrix.mul` from `IsCompletelyPositive`). + symm + rw [Matrix.mul_apply, Finset.sum_eq_single (j, (Fintype.equivFin Y).symm p)] + · rw [Matrix.mul_apply, Finset.sum_eq_single (i, (Fintype.equivFin Y).symm p)] + · simp [traceRightKraus, Matrix.conjTranspose_apply] + · intro q _ hq + simp only [traceRightKraus, Matrix.of_apply] + rw [if_neg hq]; ring + · simp + · intro q _ hq + simp only [traceRightKraus, Matrix.conjTranspose_apply, Matrix.of_apply, + apply_ite (star · : ℂ → ℂ), star_one, star_zero] + rw [if_neg hq]; simp + · simp + +theorem isTracePreserving_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : + IsTracePreserving (partialTraceRightₗ (X := X) (Y := Y)) := + fun M => by rw [partialTraceRightₗ_apply]; exact trace_traceRight M + +/-- Right partial trace (trace out `Y`) as a bundled `QuantumChannel`. -/ +noncomputable def QuantumChannel.partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : + Matrix.QuantumChannel (X × Y) X := + ⟨partialTraceRightₗ, isCompletelyPositive_partialTraceRight, isTracePreserving_partialTraceRight⟩ + +/-! ### Conjugation by an index equivalence as a channel -/ + +/-- Conjugation by a reindex `e : Z ≃ W`: `M ↦ M.submatrix e.symm e.symm`, as a linear map. -/ +noncomputable def reindexₗ {Z W : Type*} (e : Z ≃ W) : + Matrix Z Z ℂ →ₗ[ℂ] Matrix W W ℂ where + toFun M := M.submatrix e.symm e.symm + map_add' M N := by ext w w'; simp [Matrix.submatrix_apply] + map_smul' c M := by ext w w'; simp [Matrix.submatrix_apply] + +@[simp] lemma reindexₗ_apply {Z W : Type*} (e : Z ≃ W) (M : Matrix Z Z ℂ) : + reindexₗ e M = M.submatrix e.symm e.symm := rfl + +/-- Kraus operator (permutation matrix) for `reindexₗ e`: `P w z = [z = e.symm w]`. -/ +def reindexKraus {Z W : Type*} [DecidableEq Z] (e : Z ≃ W) : Matrix W Z ℂ := + Matrix.of fun w z => if z = e.symm w then (1 : ℂ) else 0 + +theorem isCompletelyPositive_reindexₗ {Z W : Type*} [Fintype Z] (e : Z ≃ W) : + IsCompletelyPositive (reindexₗ e) := by + classical + refine ⟨1, fun _ => reindexKraus e, fun M => ?_⟩ + simp only [Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton] + ext w w' + rw [reindexₗ_apply, Matrix.submatrix_apply] + symm + rw [Matrix.mul_apply, Finset.sum_eq_single (e.symm w')] + · rw [Matrix.mul_apply, Finset.sum_eq_single (e.symm w)] + · simp [reindexKraus] + · intro q _ hq + simp only [reindexKraus, Matrix.of_apply] + rw [if_neg hq]; ring + · simp + · intro z _ hz + simp only [reindexKraus, Matrix.conjTranspose_apply, Matrix.of_apply, + apply_ite (star · : ℂ → ℂ), star_one, star_zero] + rw [if_neg hz]; simp + · simp + +theorem isTracePreserving_reindexₗ {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : + IsTracePreserving (reindexₗ e) := by + intro M + rw [reindexₗ_apply] + exact trace_reindex_self e M + +/-- Conjugation by an index equivalence as a bundled `QuantumChannel`. -/ +noncomputable def QuantumChannel.reindex {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : + Matrix.QuantumChannel Z W := + ⟨reindexₗ e, isCompletelyPositive_reindexₗ e, isTracePreserving_reindexₗ e⟩ + +/-! ### Trace-out-`C` channel for `A × B × C` -/ + +/-- Trace out the `C` factor of `A × B × C`, landing on `A × B`. Its action is the `lean-eval` +marginal map `M ↦ traceRight (M.reindex (prodAssoc).symm (prodAssoc).symm)`. -/ +noncomputable def QuantumChannel.traceOutC {A B C : Type*} [Fintype A] [Fintype B] [Fintype C] : + Matrix.QuantumChannel (A × B × C) (A × B) := + ⟨(partialTraceRightₗ (X := A × B) (Y := C)).comp (reindexₗ (Equiv.prodAssoc A B C).symm), + QuantumChannel.comp (QuantumChannel.reindex (Equiv.prodAssoc A B C).symm) + QuantumChannel.partialTraceRight⟩ + +@[simp] lemma QuantumChannel.traceOutC_val_apply {A B C : Type*} + [Fintype A] [Fintype B] [Fintype C] (M : Matrix (A × B × C) (A × B × C) ℂ) : + (QuantumChannel.traceOutC (A := A) (B := B) (C := C)).val M + = Matrix.traceRight + (M.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) := by + change partialTraceRightₗ (reindexₗ (Equiv.prodAssoc A B C).symm M) = _ + rw [partialTraceRightₗ_apply, reindexₗ_apply, Matrix.reindex_apply] + +end Matrix diff --git a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean index 599a15f..80caf52 100644 --- a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean +++ b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean @@ -1,7 +1,6 @@ module public import QuantumSystem.Analysis.CFC.Diagonal -public import QuantumSystem.Analysis.Matrix.PartialTrace public import QuantumSystem.State /-! @@ -17,7 +16,7 @@ This file is the hub for **Kronecker-product calculus on bipartite matrices**: * preservation of Hermitian / unitary structure under `⊗ₖ`, * Kronecker spectral decomposition, * the **log-tensor identity** - `matrixLog (A ⊗ₖ B) = matrixLog A ⊗ₖ 1 + 1 ⊗ₖ matrixLog B` for PosDef `A`, `B`, + `cfc Real.log (A ⊗ₖ B) = cfc Real.log A ⊗ₖ 1 + 1 ⊗ₖ cfc Real.log B` for PosDef `A`, `B`, * the **equivalence-indexed partial trace** `partialTrace` (for `e : X ≃ A × B`, retain `A` and sum over `B`), * and the **Heisenberg duality at product type** @@ -33,11 +32,9 @@ only after reindexing by `LocalNet.combineIdx`. The proof of the log-tensor identity uses the spectral decomposition of `A ⊗ B` constructed explicitly from spectral decompositions of `A` and `B`, combined -with **spectral invariance** of `matrixFunction` (derived from -`Matrix.matrixFunction_eq_cfc` and `StarAlgHomClass.map_cfc` on the ⋆-algebra -automorphism given by conjugation by a unitary). Working via `matrixFunction` -(spectral, bare `Matrix n n ℂ`) instead of the `CStarMatrix` wrapper avoids the -instance diamond that blocked a previous `cfc`-only approach. +with **spectral invariance** of `cfc` (derived from `cfc_spectral_eq` and +`StarAlgHomClass.map_cfc` on the ⋆-algebra automorphism given by conjugation by +a unitary). ## Main definitions @@ -49,7 +46,7 @@ instance diamond that blocked a previous `cfc`-only approach. * `DensityMatrix.kronecker_toMatrix` — underlying-matrix unfolding. * `Matrix.IsHermitian.kronecker` — Kronecker of Hermitian matrices is Hermitian. * `Matrix.kronecker_eq_unitary_conj_diagonal` — Kronecker spectral decomposition. -* `Matrix.matrixLog_kronecker_posDef` — the log-tensor identity. +* `Matrix.cfc_log_kronecker_posDef` — the log-tensor identity. * `Matrix.partialTrace_apply` — entrywise unfolding of the equivalence-indexed partial trace. * `Matrix.restrict_eq_partialTrace_combineIdx` / `Matrix.restrict_compl_eq_partialTrace_combineIdx` — LocalNet restriction as an @@ -121,30 +118,15 @@ theorem kronecker_eq_unitary_conj_diagonal section LogTensor -/-- `matrixLog` of a unitary conjugate of a positive real diagonal is the same -unitary conjugation of the diagonal logarithm. Auxiliary for the log-tensor identity. -/ -private lemma matrixLog_unitary_conj_diagonal - {k : Type*} [Fintype k] [DecidableEq k] - (W : unitary (Matrix k k ℂ)) (d : k → ℝ) (hd : ∀ i, 0 < d i) - (hM : ((W : Matrix k k ℂ) * diagonal (fun i => ((d i : ℝ) : ℂ)) * - (W : Matrix k k ℂ)ᴴ).IsHermitian) : - matrixLog ((W : Matrix k k ℂ) * diagonal (fun i => ((d i : ℝ) : ℂ)) * - (W : Matrix k k ℂ)ᴴ) hM = - (W : Matrix k k ℂ) * - diagonal (fun i => ((Real.log (d i) : ℝ) : ℂ)) * (W : Matrix k k ℂ)ᴴ := by - unfold matrixLog - rw [matrixFunction_eq_cfc] - exact cfc_log_unitary_conj_diagonal W d hd - /-- **Log-tensor identity.** For positive-definite matrices `A` and `B`, the matrix logarithm of the Kronecker product decomposes as the sum of tensor-embedded logs: -`matrixLog (A ⊗ₖ B) = matrixLog A ⊗ₖ 1 + 1 ⊗ₖ matrixLog B`. -/ -theorem matrixLog_kronecker_posDef +`cfc Real.log (A ⊗ₖ B) = cfc Real.log A ⊗ₖ 1 + 1 ⊗ₖ cfc Real.log B`. -/ +theorem cfc_log_kronecker_posDef {A : Matrix n n ℂ} (hA : A.PosDef) {B : Matrix m m ℂ} (hB : B.PosDef) : - matrixLog (A ⊗ₖ B) (IsHermitian.kronecker hA.1 hB.1) = - matrixLog A hA.1 ⊗ₖ (1 : Matrix m m ℂ) + - (1 : Matrix n n ℂ) ⊗ₖ matrixLog B hB.1 := by + cfc Real.log (A ⊗ₖ B) = + cfc Real.log A ⊗ₖ (1 : Matrix m m ℂ) + + (1 : Matrix n n ℂ) ⊗ₖ cfc Real.log B := by -- Spectral data set U_A := (hA.1.eigenvectorUnitary : Matrix n n ℂ) with hU_A_def set U_B := (hB.1.eigenvectorUnitary : Matrix m m ℂ) with hU_B_def @@ -191,29 +173,19 @@ theorem matrixLog_kronecker_posDef rw [h] congr 1; congr 1 funext ij; push_cast; ring - -- Hermitianness of Kronecker - have hAB_herm : (A ⊗ₖ B).IsHermitian := IsHermitian.kronecker hA.1 hB.1 -- Positivity of the diagonal product have h_dA_dB_pos : ∀ ij : n × m, 0 < (dA ij.1 * dB ij.2 : ℝ) := fun ij => mul_pos (hdA_pos ij.1) (hdB_pos ij.2) - -- matrixLog of A ⊗ B via aux lemma - have hAB_herm' : ((W : Matrix (n × m) (n × m) ℂ) * - diagonal (fun ij : n × m => (((dA ij.1 * dB ij.2 : ℝ) : ℂ))) * - (W : Matrix (n × m) (n × m) ℂ)ᴴ).IsHermitian := by - rw [← hAB_decomp]; exact hAB_herm - have h_matrixLog_AB : - matrixLog (A ⊗ₖ B) hAB_herm = + -- cfc Real.log of A ⊗ B via aux lemma + have h_cfcLog_AB : + cfc Real.log (A ⊗ₖ B) = (W : Matrix (n × m) (n × m) ℂ) * diagonal (fun ij : n × m => ((Real.log (dA ij.1 * dB ij.2) : ℝ) : ℂ)) * (W : Matrix (n × m) (n × m) ℂ)ᴴ := by - rw [show matrixLog (A ⊗ₖ B) hAB_herm = - matrixLog ((W : Matrix (n × m) (n × m) ℂ) * - diagonal (fun ij : n × m => (((dA ij.1 * dB ij.2 : ℝ) : ℂ))) * - (W : Matrix (n × m) (n × m) ℂ)ᴴ) hAB_herm' from ?_] - · exact matrixLog_unitary_conj_diagonal W - (fun ij : n × m => (dA ij.1 * dB ij.2 : ℝ)) h_dA_dB_pos hAB_herm' - · congr 1 - rw [h_matrixLog_AB] + rw [hAB_decomp] + exact cfc_log_unitary_conj_diagonal W + (fun ij : n × m => (dA ij.1 * dB ij.2 : ℝ)) h_dA_dB_pos + rw [h_cfcLog_AB] -- Split log(dA*dB) = log dA + log dB have h_log_split : diagonal (fun ij : n × m => ((Real.log (dA ij.1 * dB ij.2) : ℝ) : ℂ)) = @@ -249,8 +221,8 @@ theorem matrixLog_kronecker_posDef ← mul_kronecker_mul, ← mul_kronecker_mul] -- Clean up: U_A * 1 * U_Aᴴ = 1, U_B * 1 * U_Bᴴ = 1 rw [Matrix.mul_one U_A, hUA_self', Matrix.mul_one U_B, hUB_self'] - -- Now unfold matrixLog of A and B via their spectral decomposition - rw [matrixLog_spectral_eq hA.1, matrixLog_spectral_eq hB.1] + -- Now unfold cfc Real.log of A and B via their spectral decomposition + rw [cfc_log_spectral_eq hA.1, cfc_log_spectral_eq hB.1] end LogTensor @@ -286,68 +258,6 @@ omit [Fintype m] [DecidableEq n] [DecidableEq m] in partialTrace (A := m) (B := n) (Equiv.prodComm n m) ρ b b' = ∑ a : n, ρ (a, b) (a, b') := rfl -/-! ### LocalNet bridge - -These lemmas identify `Matrix.restrict` on a `LocalNet` with the equivalence-indexed -partial trace of the reindexed matrix induced by `LocalNet.combineIdx`. -/ - -section LocalNetBridge - -variable {L : LocalNet} - -/-- Combining via `h : Λ ⊆ Λ_total` agrees with combining via the complementary split, -after transporting the remaining factor along `Λ_total \ (Λ_total \ Λ) = Λ`. -/ -private lemma combineIdx_swap_apply - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (x : L.regionIdx Λ) (y : L.regionIdx (Λ_total \ Λ)) : - L.combineIdx h (x, y) = - L.combineIdx Finset.sdiff_subset - (y, L.regionIdxCongr (sdiff_sdiff_eq_self h).symm x) := by - have h_eq : Λ_total \ (Λ_total \ Λ) = Λ := sdiff_sdiff_eq_self h - funext ⟨s, hs⟩ - by_cases hsΛ : s ∈ Λ - · have hns_compl : s ∉ Λ_total \ Λ := fun h_in => (Finset.mem_sdiff.mp h_in).2 hsΛ - have hs_recast : s ∈ Λ_total \ (Λ_total \ Λ) := by - rw [h_eq] - exact hsΛ - rw [LocalNet.combineIdx_apply_mem h _ _ ⟨s, hs⟩ hsΛ, - LocalNet.combineIdx_apply_not_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hns_compl, - LocalNet.regionIdxCongr_apply (L := L) h_eq.symm x hsΛ hs_recast] - · have hs_compl : s ∈ Λ_total \ Λ := Finset.mem_sdiff.mpr ⟨hs, hsΛ⟩ - rw [LocalNet.combineIdx_apply_not_mem h _ _ ⟨s, hs⟩ hsΛ, - LocalNet.combineIdx_apply_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hs_compl] - -/-- Restriction to `Λ` equals the partial trace of the reindexed matrix induced by -`combineIdx h`, retaining the `Λ` factor. -/ -theorem restrict_eq_partialTrace_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.localAlgebra Λ_total) (x x' : L.regionIdx Λ) : - Matrix.restrict h ρ x x' = - Matrix.partialTrace - (A := L.regionIdx Λ) (B := L.regionIdx (Λ_total \ Λ)) - (Equiv.refl (L.regionIdx Λ × L.regionIdx (Λ_total \ Λ))) - (ρ.submatrix (L.combineIdx h) (L.combineIdx h)) x x' := by - rw [Matrix.partialTrace_refl_apply, Matrix.restrict_apply] - simp [Matrix.submatrix_apply] - -/-- Restriction to the complement of `Λ` equals the partial trace of the reindexed matrix -induced by `combineIdx h`, retaining the complementary factor. -/ -theorem restrict_compl_eq_partialTrace_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.localAlgebra Λ_total) (y y' : L.regionIdx (Λ_total \ Λ)) : - Matrix.restrict Finset.sdiff_subset ρ y y' = - Matrix.partialTrace - (A := L.regionIdx (Λ_total \ Λ)) (B := L.regionIdx Λ) - (Equiv.prodComm (L.regionIdx Λ) (L.regionIdx (Λ_total \ Λ))) - (ρ.submatrix (L.combineIdx h) (L.combineIdx h)) y y' := by - rw [Matrix.partialTrace_prodComm_apply, Matrix.restrict_apply] - rw [← (L.regionIdxCongr (sdiff_sdiff_eq_self h).symm).sum_comp - (fun z => ρ (L.combineIdx Finset.sdiff_subset (y, z)) - (L.combineIdx Finset.sdiff_subset (y', z)))] - refine Finset.sum_congr rfl fun x _ => ?_ - rw [Matrix.submatrix_apply, combineIdx_swap_apply h x y, combineIdx_swap_apply h x y'] - -end LocalNetBridge /-! ### Heisenberg duality at product type diff --git a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean b/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean new file mode 100644 index 0000000..19089e0 --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean @@ -0,0 +1,99 @@ +module + +public import QuantumSystem.Analysis.Entropy.KroneckerProduct +public import QuantumSystem.Analysis.Entropy.RelativeEntropy +public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy + +/-! +# Mutual-information identity (product-type form) + +The relative-entropy form of quantum mutual information for a bipartite density matrix on a plain +product index type `n × m`: + + `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B)`. + +This is `LocalNet`-free; it is the analytic core reused both by the AQFT strong-subadditivity proof +(`Analysis/Entropy/SSA.lean`) and by the product-form proof (`Analysis/Entropy/SSAProduct.lean`). +-/ + +@[expose] public section + +namespace Matrix + +open scoped Kronecker MatrixOrder ComplexOrder QuantumInfo + +variable {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] + +/-! ### Product-type relative-entropy identity -/ + +/-- **Mutual-information identity (product-type form)**: for a bipartite density +matrix `ρ_AB : DensityMatrix (n × m)` whose canonical partial traces coincide with PosDef +factor states `ρ_A` and `ρ_B`, the relative entropy w.r.t. the product `ρ_A ⊗ ρ_B` +equals `-S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -/ +theorem relativeEntropy_kronecker_marginals_product + (ρ_AB : DensityMatrix (n × m)) + (ρ_A : DensityMatrix n) (hρ_A : ρ_A.toMatrix.PosDef) + (ρ_B : DensityMatrix m) (hρ_B : ρ_B.toMatrix.PosDef) + (h_A_partialTrace : tr₂(ρ_AB.toMatrix) = ρ_A.toMatrix) + (h_B_partialTrace : tr₁(ρ_AB.toMatrix) = ρ_B.toMatrix) : + D(ρ_AB ∥ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B) := by + classical + have hρ_A_kron_pos : (ρ_A ⊗ ρ_B).toMatrix.PosDef := by + rw [DensityMatrix.kronecker_toMatrix]; exact hρ_A.kronecker hρ_B + -- supp(ρ) ⊆ supp(ρ_A ⊗ ρ_B) holds for PosDef σ. + have h_supp : suppSubset ρ_AB.toMatrix (ρ_A ⊗ ρ_B).toMatrix := by + intro v hv + have hinj : Function.Injective (ρ_A ⊗ ρ_B).toMatrix.mulVec := + Matrix.mulVec_injective_iff_isUnit.mpr hρ_A_kron_pos.isUnit + have h0 : (ρ_A ⊗ ρ_B).toMatrix.mulVec 0 = 0 := by simp + have hv_zero : v = 0 := hinj (hv.trans h0.symm) + rw [hv_zero]; simp + unfold relativeEntropy + simp only [h_supp, if_true] + -- log of ρ_A ⊗ ρ_B decomposes via cfc_log_kronecker_posDef. + have h_log_kron : cfc Real.log (ρ_A ⊗ ρ_B).toMatrix = + cfc Real.log ρ_A.toMatrix ⊗ₖ (1 : Matrix m m ℂ) + + (1 : Matrix n n ℂ) ⊗ₖ cfc Real.log ρ_B.toMatrix := + cfc_log_kronecker_posDef hρ_A hρ_B + -- The trace identity after substitution. + have h_trace_log_kron : + Tr (ρ_AB.toMatrix * cfc Real.log (ρ_A ⊗ ρ_B).toMatrix) = + Tr (ρ_A.toMatrix * cfc Real.log ρ_A.toMatrix) + + Tr (ρ_B.toMatrix * cfc Real.log ρ_B.toMatrix) := by + rw [h_log_kron, Matrix.mul_add, Matrix.trace_add, trace_mul_kronecker_one_right, + trace_mul_kronecker_one_left, h_A_partialTrace, h_B_partialTrace] + -- Split (log ρ - log(ρ_A⊗ρ_B)) and reduce trace. + have h_split : Tr (ρ_AB.toMatrix * (cfc Real.log ρ_AB.toMatrix - + cfc Real.log (ρ_A ⊗ ρ_B).toMatrix)) = + Tr (ρ_AB.toMatrix * cfc Real.log ρ_AB.toMatrix) - + Tr (ρ_AB.toMatrix * cfc Real.log (ρ_A ⊗ ρ_B).toMatrix) := by + rw [Matrix.mul_sub, Matrix.trace_sub] + -- Translate to the goal in EReal. + change (↑(Tr (ρ_AB.toMatrix * (cfc Real.log ρ_AB.toMatrix - + cfc Real.log (ρ_A ⊗ ρ_B).toMatrix))).re : EReal) = + -S(ρ_AB) + S(ρ_A) + S(ρ_B) + rw [h_split, Complex.sub_re, h_trace_log_kron, Complex.add_re] + -- Now: ↑((Tr(ρ · log ρ)).re - ((Tr(ρ_A · log ρ_A)).re + (Tr(ρ_B · log ρ_B)).re)) + -- = -S(ρ) + S(ρ_A) + S(ρ_B) + -- Express the LHS Real value: + set α : ℝ := (Tr (ρ_AB.toMatrix * cfc Real.log ρ_AB.toMatrix)).re with hα + set β : ℝ := (Tr (ρ_A.toMatrix * cfc Real.log ρ_A.toMatrix)).re with hβ + set γ : ℝ := (Tr (ρ_B.toMatrix * cfc Real.log ρ_B.toMatrix)).re with hγ + -- And the S values: + change (↑(α - (β + γ)) : EReal) = -S(ρ_AB) + S(ρ_A) + S(ρ_B) + have hSρ : S(ρ_AB) = -α := by + change -(Tr (ρ_AB.toMatrix * DensityMatrix.log ρ_AB)).re = -α + rfl + have hSρ_A : S(ρ_A) = -β := by + change -(Tr (ρ_A.toMatrix * DensityMatrix.log ρ_A)).re = -β + rfl + have hSρ_B : S(ρ_B) = -γ := by + change -(Tr (ρ_B.toMatrix * DensityMatrix.log ρ_B)).re = -γ + rfl + rw [hSρ, hSρ_A, hSρ_B] + -- Goal in EReal: ↑(α - (β + γ)) = -↑(-α) + ↑(-β) + ↑(-γ) + -- Equivalent Real identity: + have h_real : α - (β + γ) = -(-α) + (-β) + (-γ) := by ring + exact_mod_cast h_real + +end Matrix diff --git a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean index 87afa6c..2cd1473 100644 --- a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean @@ -230,8 +230,8 @@ private lemma trace_ρlogρ_eq (ρ : DensityMatrix n) : have hρ_spec := spectral_expand ρ.toMatrix ρ.isHermitian -- log(ρ) = U * diag(log ev) * Uᴴ have hlogρ_spec : log ρ = U * diagonal (fun i => (Real.log (ev_ρ i) : ℂ)) * Uᴴ := by - unfold DensityMatrix.log matrixLog matrixFunction - rfl + unfold DensityMatrix.log + exact cfc_log_spectral_eq ρ.isHermitian -- ρ * log(ρ) = U * diag(ev) * Uᴴ * U * diag(log ev) * Uᴴ = U * diag(ev * log ev) * Uᴴ -- First rewrite log, then ρ have h1 : (ρ.toMatrix * log ρ).trace.re = @@ -276,12 +276,10 @@ private lemma trace_ρlogσ_eq (ρ σ : DensityMatrix n) : set W := eigW ρ σ set ev_ρ := ρ.isHermitian.eigenvalues set ev_σ := σ.isHermitian.eigenvalues - have hρ : ρ.toMatrix = U * diagonal (fun i => (ev_ρ i : ℂ)) * Uᴴ := by - have h := (matrixFunction_id ρ.isHermitian).symm - unfold matrixFunction at h - simpa [Function.comp] using h + have hρ : ρ.toMatrix = U * diagonal (fun i => (ev_ρ i : ℂ)) * Uᴴ := + spectral_expand ρ.toMatrix ρ.isHermitian have hlogσ : log σ = V * diagonal (fun i => (Real.log (ev_σ i) : ℂ)) * Vᴴ := by - unfold DensityMatrix.log matrixLog matrixFunction; rfl + unfold DensityMatrix.log; exact cfc_log_spectral_eq σ.isHermitian have hUHV : Uᴴ * V = Wᴴ := by calc Uᴴ * V = Uᴴ * (Vᴴ)ᴴ := by rw [conjTranspose_conjTranspose] _ = (Vᴴ * U)ᴴ := by rw [conjTranspose_mul] @@ -675,9 +673,11 @@ private lemma trace_rpow_mul_double_sum (ρ σ : DensityMatrix n) (s : ℝ) : have hpsdρ := ρ.posSemidef have hpsdσ := σ.posSemidef have hρs : ρ.toMatrix ^ s = U * diagonal (fun i => ((ev_ρ i ^ s : ℝ) : ℂ)) * Uᴴ := by - rw [← matrixFunction_rpow_eq hpsdρ]; unfold matrixFunction; rfl + rw [CFC.rpow_eq_cfc_real (a := ρ.toMatrix) (ha := by rw [Matrix.le_iff, sub_zero]; exact hpsdρ), + cfc_spectral_eq ρ.isHermitian (fun x => x ^ s)] have hσs : σ.toMatrix ^ (1 - s) = V * diagonal (fun j => ((ev_σ j ^ (1 - s) : ℝ) : ℂ)) * Vᴴ := by - rw [← matrixFunction_rpow_eq hpsdσ]; unfold matrixFunction; rfl + rw [CFC.rpow_eq_cfc_real (a := σ.toMatrix) (ha := by rw [Matrix.le_iff, sub_zero]; exact hpsdσ), + cfc_spectral_eq σ.isHermitian (fun x => x ^ (1 - s))] have hVU : Vᴴ * U = W := rfl rw [hρs, hσs] -- Use cyclic trace property and W = Vᴴ * U to reduce to W D_ρ Wᴴ D_σ @@ -1733,19 +1733,19 @@ theorem relativeEntropy_map_starAlgEquiv_posDef simp only [h_supp_map, h_supp, if_true] congr 1 change (Tr ((ρ.map φ hφ).toMatrix * - (matrixLog (ρ.map φ hφ).toMatrix (ρ.map φ hφ).isHermitian - - matrixLog (σ.map φ hφ).toMatrix (σ.map φ hφ).isHermitian))).re = + (cfc Real.log (ρ.map φ hφ).toMatrix - + cfc Real.log (σ.map φ hφ).toMatrix))).re = (Tr (ρ.toMatrix * - (matrixLog ρ.toMatrix ρ.isHermitian - - matrixLog σ.toMatrix σ.isHermitian))).re - have h_log_ρ : matrixLog (ρ.map φ hφ).toMatrix (ρ.map φ hφ).isHermitian = - φ (matrixLog ρ.toMatrix ρ.isHermitian) := by - change matrixLog (φ ρ.toMatrix) _ = _ - exact matrixLog_map_starAlgEquiv hρ φ - have h_log_σ : matrixLog (σ.map φ hφ).toMatrix (σ.map φ hφ).isHermitian = - φ (matrixLog σ.toMatrix σ.isHermitian) := by - change matrixLog (φ σ.toMatrix) _ = _ - exact matrixLog_map_starAlgEquiv hσ φ + (cfc Real.log ρ.toMatrix - + cfc Real.log σ.toMatrix))).re + have h_log_ρ : cfc Real.log (ρ.map φ hφ).toMatrix = + φ (cfc Real.log ρ.toMatrix) := by + change cfc Real.log (φ ρ.toMatrix) = _ + exact cfc_log_map_starAlgEquiv hρ φ + have h_log_σ : cfc Real.log (σ.map φ hφ).toMatrix = + φ (cfc Real.log σ.toMatrix) := by + change cfc Real.log (φ σ.toMatrix) = _ + exact cfc_log_map_starAlgEquiv hσ φ rw [h_log_ρ, h_log_σ, DensityMatrix.map_toMatrix, ← map_sub, ← map_mul, hφ] /-- Specialisation of `relativeEntropy_map_starAlgEquiv_posDef` to reindexing. -/ diff --git a/QuantumSystem/Analysis/Entropy/SSA.lean b/QuantumSystem/Analysis/Entropy/SSA.lean index d03306f..7266842 100644 --- a/QuantumSystem/Analysis/Entropy/SSA.lean +++ b/QuantumSystem/Analysis/Entropy/SSA.lean @@ -4,6 +4,8 @@ public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.RelativeEntropy public import QuantumSystem.Analysis.Entropy.Regularize public import QuantumSystem.Analysis.Matrix.PartialTrace +public import QuantumSystem.Analysis.Matrix.KroneckerPartialTraceBridge +public import QuantumSystem.Analysis.Entropy.MutualInfoProduct /-! # Strong subadditivity of the von Neumann entropy (LocalNet form) @@ -67,87 +69,6 @@ AQFT-natural form: @[expose] public section -namespace Matrix - -open scoped Kronecker MatrixOrder ComplexOrder QuantumInfo - -variable {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] - -/-! ### Product-type relative-entropy identity -/ - -/-- **Mutual-information identity (product-type form)**: for a bipartite density -matrix `ρ_AB : DensityMatrix (n × m)` whose canonical partial traces coincide with PosDef -factor states `ρ_A` and `ρ_B`, the relative entropy w.r.t. the product `ρ_A ⊗ ρ_B` -equals `-S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -/ -theorem relativeEntropy_kronecker_marginals_product - (ρ_AB : DensityMatrix (n × m)) - (ρ_A : DensityMatrix n) (hρ_A : ρ_A.toMatrix.PosDef) - (ρ_B : DensityMatrix m) (hρ_B : ρ_B.toMatrix.PosDef) - (h_A_partialTrace : tr₂(ρ_AB.toMatrix) = ρ_A.toMatrix) - (h_B_partialTrace : tr₁(ρ_AB.toMatrix) = ρ_B.toMatrix) : - D(ρ_AB ∥ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B) := by - classical - have hρ_A_kron_pos : (ρ_A ⊗ ρ_B).toMatrix.PosDef := by - rw [DensityMatrix.kronecker_toMatrix]; exact hρ_A.kronecker hρ_B - -- supp(ρ) ⊆ supp(ρ_A ⊗ ρ_B) holds for PosDef σ. - have h_supp : suppSubset ρ_AB.toMatrix (ρ_A ⊗ ρ_B).toMatrix := by - intro v hv - have hinj : Function.Injective (ρ_A ⊗ ρ_B).toMatrix.mulVec := - Matrix.mulVec_injective_iff_isUnit.mpr hρ_A_kron_pos.isUnit - have h0 : (ρ_A ⊗ ρ_B).toMatrix.mulVec 0 = 0 := by simp - have hv_zero : v = 0 := hinj (hv.trans h0.symm) - rw [hv_zero]; simp - unfold relativeEntropy - simp only [h_supp, if_true] - -- log of ρ_A ⊗ ρ_B decomposes via matrixLog_kronecker_posDef. - -- The two `IsHermitian` proofs differ proof-wise but match by Prop irrelevance. - have h_log_kron : matrixLog (ρ_A ⊗ ρ_B).toMatrix (ρ_A ⊗ ρ_B).isHermitian = - matrixLog ρ_A.toMatrix hρ_A.1 ⊗ₖ (1 : Matrix m m ℂ) + - (1 : Matrix n n ℂ) ⊗ₖ matrixLog ρ_B.toMatrix hρ_B.1 := - matrixLog_kronecker_posDef hρ_A hρ_B - -- The trace identity after substitution. - have h_trace_log_kron : - Tr (ρ_AB.toMatrix * matrixLog (ρ_A ⊗ ρ_B).toMatrix (ρ_A ⊗ ρ_B).isHermitian) = - Tr (ρ_A.toMatrix * matrixLog ρ_A.toMatrix hρ_A.1) + - Tr (ρ_B.toMatrix * matrixLog ρ_B.toMatrix hρ_B.1) := by - rw [h_log_kron, Matrix.mul_add, Matrix.trace_add, trace_mul_kronecker_one_right, - trace_mul_kronecker_one_left, h_A_partialTrace, h_B_partialTrace] - -- Split (log ρ - log(ρ_A⊗ρ_B)) and reduce trace. - have h_split : Tr (ρ_AB.toMatrix * (matrixLog ρ_AB.toMatrix ρ_AB.isHermitian - - matrixLog (ρ_A ⊗ ρ_B).toMatrix (ρ_A ⊗ ρ_B).isHermitian)) = - Tr (ρ_AB.toMatrix * matrixLog ρ_AB.toMatrix ρ_AB.isHermitian) - - Tr (ρ_AB.toMatrix * matrixLog (ρ_A ⊗ ρ_B).toMatrix (ρ_A ⊗ ρ_B).isHermitian) := by - rw [Matrix.mul_sub, Matrix.trace_sub] - -- Translate to the goal in EReal. - change (↑(Tr (ρ_AB.toMatrix * (matrixLog ρ_AB.toMatrix ρ_AB.isHermitian - - matrixLog (ρ_A ⊗ ρ_B).toMatrix (ρ_A ⊗ ρ_B).isHermitian))).re : EReal) = - -S(ρ_AB) + S(ρ_A) + S(ρ_B) - rw [h_split, Complex.sub_re, h_trace_log_kron, Complex.add_re] - -- Now: ↑((Tr(ρ · log ρ)).re - ((Tr(ρ_A · log ρ_A)).re + (Tr(ρ_B · log ρ_B)).re)) - -- = -S(ρ) + S(ρ_A) + S(ρ_B) - -- Express the LHS Real value: - set α : ℝ := (Tr (ρ_AB.toMatrix * matrixLog ρ_AB.toMatrix ρ_AB.isHermitian)).re with hα - set β : ℝ := (Tr (ρ_A.toMatrix * matrixLog ρ_A.toMatrix hρ_A.1)).re with hβ - set γ : ℝ := (Tr (ρ_B.toMatrix * matrixLog ρ_B.toMatrix hρ_B.1)).re with hγ - -- And the S values: - change (↑(α - (β + γ)) : EReal) = -S(ρ_AB) + S(ρ_A) + S(ρ_B) - have hSρ : S(ρ_AB) = -α := by - change -(Tr (ρ_AB.toMatrix * DensityMatrix.log ρ_AB)).re = -α - rfl - have hSρ_A : S(ρ_A) = -β := by - change -(Tr (ρ_A.toMatrix * DensityMatrix.log ρ_A)).re = -β - rfl - have hSρ_B : S(ρ_B) = -γ := by - change -(Tr (ρ_B.toMatrix * DensityMatrix.log ρ_B)).re = -γ - rfl - rw [hSρ, hSρ_A, hSρ_B] - -- Goal in EReal: ↑(α - (β + γ)) = -↑(-α) + ↑(-β) + ↑(-γ) - -- Equivalent Real identity: - have h_real : α - (β + γ) = -(-α) + (-β) + (-γ) := by ring - exact_mod_cast h_real - -end Matrix - /-! ### Strong subadditivity (LocalNet form, PosDef case) The main theorem. We use the bipartite mutual-information identity twice diff --git a/QuantumSystem/Analysis/Entropy/SSAProduct.lean b/QuantumSystem/Analysis/Entropy/SSAProduct.lean new file mode 100644 index 0000000..ee4a876 --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/SSAProduct.lean @@ -0,0 +1,302 @@ +module + +public import QuantumSystem.Analysis.Entropy.MutualInfoProduct +public import QuantumSystem.Analysis.Channel.PartialTrace + +/-! +# Strong subadditivity of the von Neumann entropy (product form, LocalNet-free) + +This file proves strong subadditivity (SSA) directly on plain product index types +`A × B × C`, with marginals taken by the positional partial traces `Matrix.traceLeft` / +`Matrix.traceRight`. It uses NO `LocalNet`, `regionIdx`, `combineIdx`, `restrict`, or three-site +net: the proof is the bare finite-dimensional quantum-information argument + +1. the mutual-information identity `Matrix.relativeEntropy_kronecker_marginals_product` + (applied to the `(A : B×C)` and `(A : B)` bipartitions), and +2. the data-processing inequality `Matrix.relativeEntropy_channel_le` for the + trace-out-`C` channel `Matrix.QuantumChannel.traceOutC`. + +The `lean-eval` density-matrix statement `LeanEval.Physics.strong_subadditivity_density` is then a +direct corollary (in `StrongSubadditivityEval.lean`), replacing the previous reduction through the +three-site `LocalNet`. + +## Main results + +* `DensityMatrix.vonNeumannEntropy_SSA_product_posDef` — SSA on `A × B × C` for a positive + definite density matrix. +* `DensityMatrix.vonNeumannEntropy_SSA_product` — SSA on `A × B × C` for an arbitrary density + matrix (via regularisation). +-/ + +@[expose] public section + +namespace Matrix + +open scoped Kronecker MatrixOrder ComplexOrder QuantumInfo + +/-! ### Bridges between `Matrix.partialTrace` and `Matrix.traceLeft`/`traceRight` -/ + +/-- `tr₂` (trace out the second factor) is `Matrix.traceRight`. -/ +@[simp] lemma partialTrace_refl_eq_traceRight {X Y : Type*} [Fintype Y] (M : Matrix (X × Y) (X × Y) ℂ) : + Matrix.partialTrace (Equiv.refl (X × Y)) M = Matrix.traceRight M := by + ext i j; rw [Matrix.partialTrace_refl_apply, traceRight_apply] + +/-- `tr₁` (trace out the first factor) is `Matrix.traceLeft`. -/ +@[simp] lemma partialTrace_prodComm_eq_traceLeft {X Y : Type*} [Fintype X] + (M : Matrix (X × Y) (X × Y) ℂ) : + Matrix.partialTrace (Equiv.prodComm X Y) M = Matrix.traceLeft M := by + ext i j; rw [Matrix.partialTrace_prodComm_apply, traceLeft_apply] + +/-! ### Associativity of iterated partial traces over `prodAssoc` -/ + +variable {A B C : Type*} [Fintype A] [Fintype B] [Fintype C] + +omit [Fintype A] in +/-- Tracing out `C` (after the associativity reindex to `(A×B)×C`) then `B` equals tracing out +`B × C` directly. -/ +lemma traceRight_traceRight_submatrix_prodAssoc (M : Matrix (A × B × C) (A × B × C) ℂ) : + Matrix.traceRight (Matrix.traceRight + (M.submatrix (Equiv.prodAssoc A B C) (Equiv.prodAssoc A B C))) + = Matrix.traceRight M := by + ext a a' + simp only [traceRight_apply, Matrix.submatrix_apply, Equiv.prodAssoc_apply] + rw [Fintype.sum_prod_type] + +omit [Fintype B] in +/-- Tracing out `C` (after the reindex) then `A` equals tracing out `C` of (trace out `A`). -/ +lemma traceLeft_traceRight_submatrix_prodAssoc (M : Matrix (A × B × C) (A × B × C) ℂ) : + Matrix.traceLeft (Matrix.traceRight + (M.submatrix (Equiv.prodAssoc A B C) (Equiv.prodAssoc A B C))) + = Matrix.traceRight (Matrix.traceLeft M) := by + ext b b' + simp only [traceLeft_apply, traceRight_apply, Matrix.submatrix_apply, Equiv.prodAssoc_apply] + rw [Finset.sum_comm] + +omit [Fintype A] [Fintype B] in +/-- Tracing out `C` of `(M_A ⊗ M_BC)` reassociated to `(A×B)×C` factors through `M_BC`. -/ +lemma traceRight_submatrix_prodAssoc_kronecker (M_A : Matrix A A ℂ) + (M_BC : Matrix (B × C) (B × C) ℂ) : + Matrix.traceRight ((M_A ⊗ₖ M_BC).submatrix (Equiv.prodAssoc A B C) (Equiv.prodAssoc A B C)) + = M_A ⊗ₖ Matrix.traceRight M_BC := by + ext p q + simp only [traceRight_apply, Matrix.submatrix_apply, Equiv.prodAssoc_apply, + Matrix.kroneckerMap_apply] + rw [Finset.mul_sum] + +end Matrix + +namespace DensityMatrix + +open Matrix +open scoped Kronecker MatrixOrder ComplexOrder Matrix.QuantumInfo + +/-! ### Bundled partial-trace marginals -/ + +/-- Partial trace over the right factor of a density matrix: `DensityMatrix (X × Y) → DensityMatrix X`. -/ +noncomputable def ptRight {X Y : Type*} [Fintype X] [DecidableEq X] [Fintype Y] [DecidableEq Y] + (ρ : DensityMatrix (X × Y)) : DensityMatrix X where + toMatrix := Matrix.traceRight ρ.toMatrix + posSemidef := Matrix.traceRight_posSemidef ρ.posSemidef + trace_eq_one := by rw [Matrix.trace_traceRight]; exact ρ.trace_eq_one + +@[simp] lemma ptRight_toMatrix {X Y : Type*} [Fintype X] [DecidableEq X] [Fintype Y] [DecidableEq Y] + (ρ : DensityMatrix (X × Y)) : (ρ.ptRight).toMatrix = Matrix.traceRight ρ.toMatrix := rfl + +/-- Partial trace over the left factor of a density matrix: `DensityMatrix (X × Y) → DensityMatrix Y`. -/ +noncomputable def ptLeft {X Y : Type*} [Fintype X] [DecidableEq X] [Fintype Y] [DecidableEq Y] + (ρ : DensityMatrix (X × Y)) : DensityMatrix Y where + toMatrix := Matrix.traceLeft ρ.toMatrix + posSemidef := Matrix.traceLeft_posSemidef ρ.posSemidef + trace_eq_one := by rw [Matrix.trace_traceLeft]; exact ρ.trace_eq_one + +@[simp] lemma ptLeft_toMatrix {X Y : Type*} [Fintype X] [DecidableEq X] [Fintype Y] [DecidableEq Y] + (ρ : DensityMatrix (X × Y)) : (ρ.ptLeft).toMatrix = Matrix.traceLeft ρ.toMatrix := rfl + +/-! ### Strong subadditivity (product form) -/ + +variable {A B C : Type*} [Fintype A] [DecidableEq A] [Fintype B] [DecidableEq B] + [Fintype C] [DecidableEq C] + +/-- **Strong subadditivity (product form, positive definite case).** For a positive definite +density matrix `ρ` on `A × B × C`, with all four marginals positive definite, +`S(ρ) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC)`. -/ +theorem vonNeumannEntropy_SSA_product_posDef + (ρ_ABC : DensityMatrix (A × B × C)) + (ρ_A : DensityMatrix A) (ρ_AB : DensityMatrix (A × B)) + (ρ_BC : DensityMatrix (B × C)) (ρ_B : DensityMatrix B) + (h_A : ρ_A = ρ_ABC.ptRight) + (h_AB : ρ_AB = (ρ_ABC.mapEquiv (Equiv.prodAssoc A B C)).ptRight) + (h_BC : ρ_BC = ρ_ABC.ptLeft) (h_B : ρ_B = ρ_ABC.ptLeft.ptRight) + (hA : ρ_A.toMatrix.PosDef) (hBC : ρ_BC.toMatrix.PosDef) (hB : ρ_B.toMatrix.PosDef) : + S(ρ_ABC) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC) := by + subst h_A h_AB h_BC h_B + classical + set ρ_A := ρ_ABC.ptRight with hρ_A + set ρ_BC := ρ_ABC.ptLeft with hρ_BC + set ρ_AB := (ρ_ABC.mapEquiv (Equiv.prodAssoc A B C)).ptRight with hρ_AB + set ρ_B := ρ_ABC.ptLeft.ptRight with hρ_B + -- Mutual-information identity for the `(A : B×C)` split of `ρ_ABC`. + have h_tr2 : tr₂(ρ_ABC.toMatrix) = ρ_A.toMatrix := by + rw [hρ_A, ptRight_toMatrix]; exact partialTrace_refl_eq_traceRight ρ_ABC.toMatrix + have h_tr1 : tr₁(ρ_ABC.toMatrix) = ρ_BC.toMatrix := by + rw [hρ_BC, ptLeft_toMatrix]; exact partialTrace_prodComm_eq_traceLeft ρ_ABC.toMatrix + have h_id1 : D(ρ_ABC ∥ ρ_A ⊗ ρ_BC) = -S(ρ_ABC) + S(ρ_A) + S(ρ_BC) := + Matrix.relativeEntropy_kronecker_marginals_product ρ_ABC ρ_A hA ρ_BC hBC h_tr2 h_tr1 + -- Mutual-information identity for the `(A : B)` split of `ρ_AB`. + have h_tr2' : tr₂(ρ_AB.toMatrix) = ρ_A.toMatrix := by + rw [hρ_AB, hρ_A, ptRight_toMatrix, ptRight_toMatrix, DensityMatrix.mapEquiv_toMatrix, + partialTrace_refl_eq_traceRight] + exact traceRight_traceRight_submatrix_prodAssoc ρ_ABC.toMatrix + have h_tr1' : tr₁(ρ_AB.toMatrix) = ρ_B.toMatrix := by + rw [hρ_AB, hρ_B, ptRight_toMatrix, ptRight_toMatrix, ptLeft_toMatrix, + DensityMatrix.mapEquiv_toMatrix, partialTrace_prodComm_eq_traceLeft] + exact traceLeft_traceRight_submatrix_prodAssoc ρ_ABC.toMatrix + have h_id2 : D(ρ_AB ∥ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B) := + Matrix.relativeEntropy_kronecker_marginals_product ρ_AB ρ_A hA ρ_B hB h_tr2' h_tr1' + -- Data-processing inequality for the trace-out-`C` channel. + set Φ := Matrix.QuantumChannel.traceOutC (A := A) (B := B) (C := C) with hΦ + have h_Φρ_ABC : Φ ρ_ABC = ρ_AB := by + apply DensityMatrix.ext + change Φ.val ρ_ABC.toMatrix = ρ_AB.toMatrix + rw [hΦ, Matrix.QuantumChannel.traceOutC_val_apply, hρ_AB, ptRight_toMatrix, + DensityMatrix.mapEquiv_toMatrix, Matrix.reindex_apply, Equiv.symm_symm] + have h_Φσ : Φ (ρ_A ⊗ ρ_BC) = ρ_A ⊗ ρ_B := by + apply DensityMatrix.ext + change Φ.val (ρ_A ⊗ ρ_BC).toMatrix = (ρ_A ⊗ ρ_B).toMatrix + rw [hΦ, Matrix.QuantumChannel.traceOutC_val_apply, DensityMatrix.kronecker_toMatrix, + DensityMatrix.kronecker_toMatrix, Matrix.reindex_apply, Equiv.symm_symm, + Matrix.traceRight_submatrix_prodAssoc_kronecker] + simp only [hρ_B, hρ_BC, ptRight_toMatrix, ptLeft_toMatrix] + have h_dpi : D(Φ ρ_ABC ∥ Φ (ρ_A ⊗ ρ_BC)) ≤ D(ρ_ABC ∥ ρ_A ⊗ ρ_BC) := + Matrix.relativeEntropy_channel_le Φ ρ_ABC (ρ_A ⊗ ρ_BC) + rw [h_Φρ_ABC, h_Φσ, h_id2, h_id1] at h_dpi + have h_real : -S(ρ_AB) + S(ρ_A) + S(ρ_B) ≤ -S(ρ_ABC) + S(ρ_A) + S(ρ_BC) := by exact_mod_cast h_dpi + linarith + +/-! ### Regularisation: commutation of marginals with `regularize` -/ + +/-- The right partial trace of the maximally mixed state is maximally mixed. -/ +lemma traceRight_maximallyMixed {X Y : Type*} [Fintype X] [DecidableEq X] [Nonempty X] + [Fintype Y] [DecidableEq Y] [Nonempty Y] : + Matrix.traceRight (DensityMatrix.maximallyMixed (n := X × Y)).toMatrix + = (DensityMatrix.maximallyMixed (n := X)).toMatrix := by + rw [DensityMatrix.maximallyMixed_toMatrix, DensityMatrix.maximallyMixed_toMatrix, + ← Matrix.partialTraceRightₗ_apply, map_smul, Matrix.partialTraceRightₗ_apply, + Matrix.traceRight_one, smul_smul] + congr 1 + rw [Fintype.card_prod] + have hX : (Fintype.card X : ℂ) ≠ 0 := Nat.cast_ne_zero.mpr Fintype.card_ne_zero + have hY : (Fintype.card Y : ℂ) ≠ 0 := Nat.cast_ne_zero.mpr Fintype.card_ne_zero + push_cast + field_simp + +/-- The left partial trace of the maximally mixed state is maximally mixed. -/ +lemma traceLeft_maximallyMixed {X Y : Type*} [Fintype X] [DecidableEq X] [Nonempty X] + [Fintype Y] [DecidableEq Y] [Nonempty Y] : + Matrix.traceLeft (DensityMatrix.maximallyMixed (n := X × Y)).toMatrix + = (DensityMatrix.maximallyMixed (n := Y)).toMatrix := by + rw [DensityMatrix.maximallyMixed_toMatrix, DensityMatrix.maximallyMixed_toMatrix, + ← Matrix.partialTraceLeftₗ_apply, map_smul, Matrix.partialTraceLeftₗ_apply, + Matrix.traceLeft_one, smul_smul] + congr 1 + rw [Fintype.card_prod] + have hX : (Fintype.card X : ℂ) ≠ 0 := Nat.cast_ne_zero.mpr Fintype.card_ne_zero + have hY : (Fintype.card Y : ℂ) ≠ 0 := Nat.cast_ne_zero.mpr Fintype.card_ne_zero + push_cast + field_simp + +variable {A B C : Type*} [Fintype A] [DecidableEq A] [Fintype B] [DecidableEq B] + [Fintype C] [DecidableEq C] + +/-- `ptRight` commutes with `regularize`. -/ +lemma ptRight_regularize {X Y : Type*} [Fintype X] [DecidableEq X] [Nonempty X] + [Fintype Y] [DecidableEq Y] [Nonempty Y] (ρ : DensityMatrix (X × Y)) {ε : ℝ} + (hε : 0 ≤ ε) (hε' : ε ≤ 1) : + (DensityMatrix.regularize ρ hε hε').ptRight = DensityMatrix.regularize ρ.ptRight hε hε' := by + apply DensityMatrix.ext + rw [ptRight_toMatrix, DensityMatrix.regularize_toMatrix, DensityMatrix.regularize_toMatrix, + ptRight_toMatrix, ← Matrix.partialTraceRightₗ_apply, map_add, map_smul, map_smul, + Matrix.partialTraceRightₗ_apply, Matrix.partialTraceRightₗ_apply, traceRight_maximallyMixed] + +/-- `ptLeft` commutes with `regularize`. -/ +lemma ptLeft_regularize {X Y : Type*} [Fintype X] [DecidableEq X] [Nonempty X] + [Fintype Y] [DecidableEq Y] [Nonempty Y] (ρ : DensityMatrix (X × Y)) {ε : ℝ} + (hε : 0 ≤ ε) (hε' : ε ≤ 1) : + (DensityMatrix.regularize ρ hε hε').ptLeft = DensityMatrix.regularize ρ.ptLeft hε hε' := by + apply DensityMatrix.ext + rw [ptLeft_toMatrix, DensityMatrix.regularize_toMatrix, DensityMatrix.regularize_toMatrix, + ptLeft_toMatrix, ← Matrix.partialTraceLeftₗ_apply, map_add, map_smul, map_smul, + Matrix.partialTraceLeftₗ_apply, Matrix.partialTraceLeftₗ_apply, traceLeft_maximallyMixed] + +/-- **Strong subadditivity (product form).** For any density matrix `ρ` on `A × B × C`, +`S(ρ) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC)`. Obtained from the positive-definite case by regularisation +and a limit. -/ +theorem vonNeumannEntropy_SSA_product [Nonempty A] [Nonempty B] [Nonempty C] + (ρ_ABC : DensityMatrix (A × B × C)) + (ρ_AB : DensityMatrix (A × B)) (ρ_BC : DensityMatrix (B × C)) (ρ_B : DensityMatrix B) + (h_AB : ρ_AB = (ρ_ABC.mapEquiv (Equiv.prodAssoc A B C)).ptRight) + (h_BC : ρ_BC = ρ_ABC.ptLeft) (h_B : ρ_B = ρ_ABC.ptLeft.ptRight) : + S(ρ_ABC) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC) := by + subst h_AB h_BC h_B + set ρ_AB := (ρ_ABC.mapEquiv (Equiv.prodAssoc A B C)).ptRight with hρ_AB + set ρ_BC := ρ_ABC.ptLeft with hρ_BC + set ρ_B := ρ_ABC.ptLeft.ptRight with hρ_B + let f_full : ℝ → ℝ := fun ε => ∑ i, Real.negMulLog + ((1 - ε) * ρ_ABC.isHermitian.eigenvalues i + ε / Fintype.card (A × B × C)) + let f_B : ℝ → ℝ := fun ε => ∑ i, Real.negMulLog + ((1 - ε) * ρ_B.isHermitian.eigenvalues i + ε / Fintype.card B) + let f_AB : ℝ → ℝ := fun ε => ∑ i, Real.negMulLog + ((1 - ε) * ρ_AB.isHermitian.eigenvalues i + ε / Fintype.card (A × B)) + let f_BC : ℝ → ℝ := fun ε => ∑ i, Real.negMulLog + ((1 - ε) * ρ_BC.isHermitian.eigenvalues i + ε / Fintype.card (B × C)) + have h_ineq_pos : ∀ ε : ℝ, 0 < ε → ε ≤ 1 → f_full ε + f_B ε ≤ f_AB ε + f_BC ε := by + intro ε hε_pos hε_le + have hA_pos : ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptRight).toMatrix.PosDef := by + rw [ptRight_regularize]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le + have hBC_pos : ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptLeft).toMatrix.PosDef := by + rw [ptLeft_regularize]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le + have hB_pos : + ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptLeft.ptRight).toMatrix.PosDef := by + rw [ptLeft_regularize, ptRight_regularize]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le + have h_ssa := vonNeumannEntropy_SSA_product_posDef + (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) _ _ _ _ rfl rfl rfl rfl + hA_pos hBC_pos hB_pos + rw [show (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptLeft.ptRight + = DensityMatrix.regularize ρ_B hε_pos.le hε_le from by + rw [ptLeft_regularize, ptRight_regularize, hρ_B], + show ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).mapEquiv (Equiv.prodAssoc A B C)).ptRight + = DensityMatrix.regularize ρ_AB hε_pos.le hε_le from by + rw [← DensityMatrix.regularize_mapEquiv, ptRight_regularize, hρ_AB], + show (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptLeft + = DensityMatrix.regularize ρ_BC hε_pos.le hε_le from by + rw [ptLeft_regularize, hρ_BC]] at h_ssa + rw [Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_ABC hε_pos.le hε_le, + Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_B hε_pos.le hε_le, + Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_AB hε_pos.le hε_le, + Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_BC hε_pos.le hε_le] at h_ssa + exact h_ssa + have h_cont_full : Filter.Tendsto f_full (nhds 0) (nhds S(ρ_ABC)) := + Matrix.tendsto_negMulLog_regularize_sum_zero ρ_ABC + have h_cont_B : Filter.Tendsto f_B (nhds 0) (nhds S(ρ_B)) := + Matrix.tendsto_negMulLog_regularize_sum_zero ρ_B + have h_cont_AB : Filter.Tendsto f_AB (nhds 0) (nhds S(ρ_AB)) := + Matrix.tendsto_negMulLog_regularize_sum_zero ρ_AB + have h_cont_BC : Filter.Tendsto f_BC (nhds 0) (nhds S(ρ_BC)) := + Matrix.tendsto_negMulLog_regularize_sum_zero ρ_BC + have h_within : ∀ᶠ ε in nhdsWithin (0 : ℝ) (Set.Ioi 0), + f_full ε + f_B ε ≤ f_AB ε + f_BC ε := by + rw [eventually_nhdsWithin_iff] + have h_le_one : ∀ᶠ ε in nhds (0 : ℝ), ε ≤ 1 := + Filter.eventually_of_mem (IsOpen.mem_nhds isOpen_Iio (by norm_num : (0 : ℝ) < 1)) + (fun ε hε => le_of_lt hε) + filter_upwards [h_le_one] with ε hε_le_one hε_pos + exact h_ineq_pos ε hε_pos hε_le_one + have h_LHS_lim : Filter.Tendsto (fun ε => f_AB ε + f_BC ε) (nhdsWithin (0 : ℝ) (Set.Ioi 0)) + (nhds (S(ρ_AB) + S(ρ_BC))) := + (h_cont_AB.add h_cont_BC).mono_left nhdsWithin_le_nhds + have h_RHS_lim : Filter.Tendsto (fun ε => f_full ε + f_B ε) (nhdsWithin (0 : ℝ) (Set.Ioi 0)) + (nhds (S(ρ_ABC) + S(ρ_B))) := + (h_cont_full.add h_cont_B).mono_left nhdsWithin_le_nhds + exact le_of_tendsto_of_tendsto h_RHS_lim h_LHS_lim h_within + +end DensityMatrix diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean new file mode 100644 index 0000000..900ab9a --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean @@ -0,0 +1,252 @@ +module + +public import QuantumSystem.Analysis.Entropy.SSAProduct +public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PosDef + +/-! +# Strong subadditivity in the `lean-eval` formulation + +This file reproduces the statement of strong subadditivity of the von Neumann entropy as posed in +[`lean-eval`](https://github.com/leanprover/lean-eval) (`LeanEval/Physics/StrongSubadditivity.lean`) +and proves it by reducing to the project's `DensityMatrix.vonNeumannEntropy_SSA`. + +The `lean-eval` problem states, for a tripartite **positive semidefinite** matrix `M_ABC` +(deliberately *not* normalised — normalisation is a positive affine transformation on the entropy): + + `entropy M_ABC + entropy M_B ≤ entropy M_AB + entropy M_BC`, + +where `entropy M = -Re (Tr (M * cfc Real.log M))` and the marginals are the positional partial +traces `Matrix.traceLeft`/`Matrix.traceRight`. + +## Bridge to the project's entropy + +The project's `Matrix.vonNeumannEntropy` is defined for a `DensityMatrix` via `DensityMatrix.log`, +i.e. Mathlib's `cfc Real.log`. The lemma +`LeanEval.Physics.entropy_toMatrix_eq_vonNeumannEntropy` records that the two notions of +entropy coincide on a density matrix. +-/ + +@[expose] public section + +open Matrix +open scoped Matrix.QuantumInfo ComplexOrder MatrixOrder + +namespace LeanEval + +namespace Physics + +variable {n : Type*} [Fintype n] [DecidableEq n] + +/-- Von Neumann entropy of a quantum state (the `lean-eval` definition, via Mathlib's continuous +functional calculus). -/ +noncomputable def entropy (M : Matrix n n ℂ) : ℝ := + -Complex.re (Matrix.trace (M * cfc Real.log M)) + +/-- On a density matrix the `lean-eval` `entropy` coincides with the project's +`Matrix.vonNeumannEntropy`. -/ +theorem entropy_toMatrix_eq_vonNeumannEntropy (ρ : DensityMatrix n) : + entropy ρ.toMatrix = S(ρ) := by + rw [entropy, Matrix.vonNeumannEntropy, DensityMatrix.log] + rfl + +/-- The `lean-eval` `entropy` of a positive semidefinite matrix equals the spectral sum +`∑ᵢ negMulLog λᵢ`, with `Real.negMulLog 0 = 0` accounting for the kernel. Valid for any PSD +matrix (not necessarily normalised). -/ +theorem entropy_eq_negMulLog_sum (M : Matrix n n ℂ) (hM : M.PosSemidef) : + entropy M = ∑ i, Real.negMulLog (hM.1.eigenvalues i) := by + rw [entropy, trace_mul_cfc hM.1, + Complex.re_sum, ← Finset.sum_neg_distrib] + refine Finset.sum_congr rfl (fun i _ => ?_) + rw [← Complex.ofReal_mul, Complex.ofReal_re, Real.negMulLog] + ring + +/-- The entropy of the zero matrix is `0`. -/ +@[simp] theorem entropy_zero : entropy (0 : Matrix n n ℂ) = 0 := by + rw [entropy] + simp + +/-- A real-valued function is continuous on any finite set (the subspace topology is discrete). -/ +private lemma continuousOn_of_finite {s : Set ℝ} (hs : s.Finite) (g : ℝ → ℝ) : + ContinuousOn g s := by + rw [continuousOn_iff_continuous_restrict] + have : Finite s := hs.to_subtype + exact continuous_of_discreteTopology + +/-- The real spectrum of a Hermitian matrix is finite. -/ +private lemma spectrum_real_finite {N : Matrix n n ℂ} (hN : N.IsHermitian) : + (spectrum ℝ N).Finite := by + rw [hN.spectrum_real_eq_range_eigenvalues] + exact Set.finite_range _ + +/-- The real part of the trace of a Hermitian matrix is the sum of its eigenvalues. -/ +private lemma trace_re_eq_sum_eigenvalues {N : Matrix n n ℂ} (hN : N.IsHermitian) : + (N.trace).re = ∑ i, hN.eigenvalues i := by + have h : N.trace = ∑ i, ((hN.eigenvalues i : ℝ) : ℂ) := by + have hsa : IsSelfAdjoint N := hN + conv_lhs => rw [← cfc_id' (R := ℝ) (a := N) hsa] + rw [trace_cfc hN] + rw [h, Complex.re_sum] + simp + +/-- **Scale law for the entropy.** For `c > 0` and a positive semidefinite matrix `N`, +`entropy (c • N) = c · entropy N − c · log c · Tr N`. With `c = Tr N` this expresses the +normalisation of an unnormalised state as a positive affine transformation on the entropy. -/ +theorem entropy_smul {c : ℝ} (hc : 0 < c) {N : Matrix n n ℂ} (hN : N.PosSemidef) : + entropy (c • N) = c * entropy N - c * Real.log c * (N.trace).re := by + have hsa : IsSelfAdjoint N := hN.1 + have hf_cont : ContinuousOn (fun x => c * x) (spectrum ℝ N) := + (continuous_const.mul continuous_id).continuousOn + have hlog_cont : ContinuousOn Real.log ((fun x => c * x) '' spectrum ℝ N) := + continuousOn_of_finite ((spectrum_real_finite hN.1).image _) _ + have hgc_cont : ContinuousOn (fun x => Real.log (c * x)) (spectrum ℝ N) := + continuousOn_of_finite (spectrum_real_finite hN.1) _ + have hCN : (c • N : Matrix n n ℂ) = cfc (fun x => c * x) N := by + rw [cfc_const_mul (R := ℝ) c (fun x => x) N, cfc_id' (R := ℝ) (a := N) hsa] + have hlogCN : cfc Real.log (c • N) = cfc (fun x => Real.log (c * x)) N := by + conv_lhs => rw [hCN] + rw [← cfc_comp Real.log (fun x => c * x) N hsa hlog_cont hf_cont] + rfl + have hprod : (c • N) * cfc Real.log (c • N) = + cfc (fun x => (c * x) * Real.log (c * x)) N := by + rw [hlogCN, hCN, ← cfc_mul (fun x => c * x) (fun x => Real.log (c * x)) N hf_cont hgc_cont] + rw [entropy, hprod, trace_cfc hN.1, + Complex.re_sum, entropy_eq_negMulLog_sum N hN, + trace_re_eq_sum_eigenvalues hN.1, Finset.mul_sum, Finset.mul_sum, + ← Finset.sum_sub_distrib, ← Finset.sum_neg_distrib] + refine Finset.sum_congr rfl (fun i _ => ?_) + simp only [Complex.ofReal_re] + rw [Real.negMulLog] + rcases eq_or_lt_of_le (hN.1.posSemidef_iff_eigenvalues_nonneg.mp hN i) with h0 | hpos + · rw [← h0]; simp + · rw [Real.log_mul (ne_of_gt hc) (ne_of_gt hpos)]; ring + + +/-! ### Reduction to independent universes and to positive semidefinite matrices + +The `lean-eval` statement allows the three factors `A`, `B`, `C` to live in independent universes, +and works with an arbitrary positive semidefinite matrix (not necessarily a normalised state). +We reduce it to `strong_subadditivity_density` (same universe, normalised) in two steps: +`ULift`-reindexing into a common universe, then normalisation via the entropy scale law. -/ + +section Independent + +universe uA uB uC + +variable {A : Type uA} {B : Type uB} {C : Type uC} + [Fintype A] [DecidableEq A] [Nonempty A] + [Fintype B] [DecidableEq B] [Nonempty B] + [Fintype C] [DecidableEq C] [Nonempty C] + +/-- **Strong subadditivity of the von Neumann entropy** (the `lean-eval` statement). For any +positive semidefinite `M_ABC` on `A × B × C`, +`S(M_ABC) + S(M_B) ≤ S(M_AB) + S(M_BC)`, where the marginals are obtained by partial traces. +The proof normalises `M_ABC` to a state via the entropy scale law and invokes the +`LocalNet`-free product-form core `DensityMatrix.vonNeumannEntropy_SSA_product`. -/ +theorem strong_subadditivity (M_ABC : Matrix (A × B × C) (A × B × C) ℂ) (h : M_ABC.PosSemidef) : + let M_AB : Matrix (A × B) (A × B) ℂ := + Matrix.traceRight (M_ABC.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) + let M_BC : Matrix (B × C) (B × C) ℂ := M_ABC.traceLeft + let M_B : Matrix B B ℂ := M_BC.traceRight + entropy M_ABC + entropy M_B ≤ entropy M_AB + entropy M_BC := by + intro M_AB M_BC M_B + have htr_nn : (0 : ℂ) ≤ M_ABC.trace := h.trace_nonneg + have ht_re : (0 : ℝ) ≤ (M_ABC.trace).re := (Complex.nonneg_iff.mp htr_nn).1 + have ht_im : (M_ABC.trace).im = 0 := (Complex.nonneg_iff.mp htr_nn).2.symm + have htrace_real : M_ABC.trace = (((M_ABC.trace).re : ℝ) : ℂ) := by + apply Complex.ext <;> simp [ht_im] + rcases eq_or_lt_of_le ht_re with ht0 | ht_pos + · -- `Tr M_ABC = 0` forces `M_ABC = 0`; all marginals and entropies vanish. + have hM0 : M_ABC = 0 := by rw [← h.trace_eq_zero_iff, htrace_real, ← ht0]; simp + simp [M_AB, M_BC, M_B, hM0, Matrix.reindex_apply, entropy_zero] + · -- Normalise `M_ABC = t • ρ` with `ρ` a state, then apply the density-matrix version. + set t : ℝ := (M_ABC.trace).re with ht_def + have htr_smul : Tr ((t⁻¹ : ℝ) • M_ABC) = (t⁻¹ : ℝ) • Tr M_ABC := by + simp only [Matrix.trace, Matrix.diag_apply, Matrix.smul_apply] + exact Finset.smul_sum.symm + have ρtrace : Tr ((t⁻¹ : ℝ) • M_ABC) = 1 := by + rw [htr_smul, htrace_real, Complex.real_smul, ← Complex.ofReal_mul, + inv_mul_cancel₀ (ne_of_gt ht_pos), Complex.ofReal_one] + let ρ : DensityMatrix (A × B × C) := + ⟨(t⁻¹ : ℝ) • M_ABC, Matrix.posSemidef_smul_nonneg (inv_nonneg.mpr ht_re) h, ρtrace⟩ + have hMeq : M_ABC = t • ρ.toMatrix := (smul_inv_smul₀ (ne_of_gt ht_pos) M_ABC).symm + have hρ_tr : (ρ.toMatrix.trace).re = 1 := by rw [ρ.trace_eq_one]; simp + -- Each marginal of `M_ABC` is `t` times the corresponding marginal of `ρ`. + have hM_B : M_B = t • Matrix.traceRight (Matrix.traceLeft ρ.toMatrix) := by + calc + Matrix.traceRight (Matrix.traceLeft M_ABC) + = Matrix.traceRight (Matrix.traceLeft (t • ρ.toMatrix)) := by rw [hMeq] + _ = Matrix.traceRight (t • Matrix.traceLeft ρ.toMatrix) := by + rw [show Matrix.traceLeft (t • ρ.toMatrix) = t • Matrix.traceLeft ρ.toMatrix from by + exact Matrix.traceLeft_smul (l := B × C) (n := A) t ρ.toMatrix] + _ = t • Matrix.traceRight (Matrix.traceLeft ρ.toMatrix) := by + exact Matrix.traceRight_smul (l := B) (n := C) t (Matrix.traceLeft ρ.toMatrix) + have hM_BC : M_BC = t • Matrix.traceLeft ρ.toMatrix := by + calc + Matrix.traceLeft M_ABC = Matrix.traceLeft (t • ρ.toMatrix) := by rw [hMeq] + _ = t • Matrix.traceLeft ρ.toMatrix := by + exact Matrix.traceLeft_smul (l := B × C) (n := A) t ρ.toMatrix + have hM_AB : M_AB = t • Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm) := by + have hrs : (t • ρ.toMatrix).reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm + = t • ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm := by + ext p q; simp [Matrix.reindex_apply, Matrix.submatrix_apply] + calc + Matrix.traceRight (M_ABC.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) + = Matrix.traceRight ((t • ρ.toMatrix).reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm) := by rw [hMeq] + _ = Matrix.traceRight (t • ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm) := by rw [hrs] + _ = t • Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm) := by + exact Matrix.traceRight_smul (l := A × B) (n := C) t + (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) + -- Positive semidefiniteness and unit trace of the `ρ`-marginals (for the scale law). + have hρB : (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)).PosSemidef := + Matrix.traceRight_posSemidef (Matrix.traceLeft_posSemidef ρ.posSemidef) + have hρB_tr : (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)).trace.re = 1 := by + rw [Matrix.trace_traceRight, Matrix.trace_traceLeft, ρ.trace_eq_one]; simp + have hρBC : (Matrix.traceLeft ρ.toMatrix).PosSemidef := Matrix.traceLeft_posSemidef ρ.posSemidef + have hρBC_tr : (Matrix.traceLeft ρ.toMatrix).trace.re = 1 := by + rw [Matrix.trace_traceLeft, ρ.trace_eq_one]; simp + have hρAB : (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm)).PosSemidef := + Matrix.traceRight_posSemidef ((Matrix.posSemidef_submatrix_equiv _).mpr ρ.posSemidef) + have hρAB_tr : (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm)).trace.re = 1 := by + rw [Matrix.trace_traceRight, Matrix.trace_reindex_self, ρ.trace_eq_one]; simp + -- Scale law on each entropy. + have key_ABC : entropy M_ABC = t * entropy ρ.toMatrix - t * Real.log t := by + rw [congrArg entropy hMeq, entropy_smul ht_pos ρ.posSemidef, hρ_tr]; ring + have key_B : entropy M_B + = t * entropy (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)) - t * Real.log t := by + rw [hM_B, entropy_smul ht_pos hρB, hρB_tr]; ring + have key_BC : entropy M_BC + = t * entropy (Matrix.traceLeft ρ.toMatrix) - t * Real.log t := by + rw [hM_BC, entropy_smul ht_pos hρBC, hρBC_tr]; ring + have key_AB : entropy M_AB + = t * entropy (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm)) - t * Real.log t := by + rw [hM_AB, entropy_smul ht_pos hρAB, hρAB_tr]; ring + rw [key_ABC, key_B, key_AB, key_BC] + -- The density-matrix SSA in `entropy` form, obtained directly from the product-form core. + have hSSA : entropy ρ.toMatrix + entropy (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)) + ≤ entropy (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm)) + entropy (Matrix.traceLeft ρ.toMatrix) := by + have e_full : entropy ρ.toMatrix = S(ρ) := entropy_toMatrix_eq_vonNeumannEntropy ρ + have e_B : entropy (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)) + = S(ρ.ptLeft.ptRight) := entropy_toMatrix_eq_vonNeumannEntropy ρ.ptLeft.ptRight + have e_BC : entropy (Matrix.traceLeft ρ.toMatrix) = S(ρ.ptLeft) := + entropy_toMatrix_eq_vonNeumannEntropy ρ.ptLeft + have e_AB : entropy (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm + (Equiv.prodAssoc A B C).symm)) = S((ρ.mapEquiv (Equiv.prodAssoc A B C)).ptRight) := by + simp only [Matrix.reindex_apply, Equiv.symm_symm] + exact entropy_toMatrix_eq_vonNeumannEntropy ((ρ.mapEquiv (Equiv.prodAssoc A B C)).ptRight) + rw [e_full, e_B, e_AB, e_BC] + exact DensityMatrix.vonNeumannEntropy_SSA_product ρ _ _ _ rfl rfl rfl + nlinarith [mul_le_mul_of_nonneg_left hSSA ht_pos.le] + +end Independent + +end Physics + +end LeanEval diff --git a/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean b/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean index fdbdd62..a31dfc0 100644 --- a/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean @@ -58,9 +58,9 @@ theorem vonNeumannEntropy_ofReal (ρ : DensityMatrix n) : /-- Von Neumann entropy equals the eigenvalue sum S(ρ) = ∑ᵢ (−λᵢ log λᵢ). -/ theorem vonNeumannEntropy_eq_sum (ρ : DensityMatrix n) : S(ρ) = ∑ i, entropyFun (ρ.isHermitian.eigenvalues i) := by - unfold vonNeumannEntropy DensityMatrix.log matrixLog - change -(Tr (ρ.toMatrix * matrixFunction _ ρ.toMatrix ρ.isHermitian)).re = _ - rw [trace_mul_matrixFunction, Complex.re_sum] + unfold vonNeumannEntropy DensityMatrix.log + change -(Tr (ρ.toMatrix * cfc Real.log ρ.toMatrix)).re = _ + rw [trace_mul_cfc ρ.isHermitian, Complex.re_sum] simp_rw [← Complex.ofReal_mul, Complex.ofReal_re, ← Finset.sum_neg_distrib] congr 1 ext i @@ -89,14 +89,12 @@ theorem vonNeumannEntropy_eq_negMulLog_sum (ρ : DensityMatrix n) : refine Finset.sum_congr rfl fun i _ => ?_ exact entropyFun_eq_negMulLog_of_nonneg (ρ.eigenvalues_nonneg i) -/-- `vonNeumannEntropy` expressed via the spectral matrix function `matrixFunction` - applied to `Real.negMulLog`. This bridges to Mathlib's continuous functional - calculus, enabling continuity arguments. -/ -theorem vonNeumannEntropy_eq_matrixFunction_re (ρ : DensityMatrix n) : +/-- `vonNeumannEntropy` expressed via Mathlib's continuous functional calculus + `cfc` applied to `Real.negMulLog`, enabling continuity arguments. -/ +theorem vonNeumannEntropy_eq_cfc_re (ρ : DensityMatrix n) : vonNeumannEntropy ρ = - (Tr (matrixFunction (fun x : ℝ => (Real.negMulLog x : ℂ)) - ρ.toMatrix ρ.isHermitian)).re := by - rw [matrixFunction_trace, vonNeumannEntropy_eq_negMulLog_sum] + (Tr (cfc Real.negMulLog ρ.toMatrix)).re := by + rw [trace_cfc ρ.isHermitian, vonNeumannEntropy_eq_negMulLog_sum] rw [Complex.re_sum] simp_rw [Complex.ofReal_re] @@ -168,7 +166,8 @@ This follows from the spectral theorem: ρ^s = U diag(λᵢ^s) U†, and trace cyclicity Tr (U D U†) = Tr (D) = ∑ Dᵢᵢ. -/ lemma trace_rpow_eq_sum_pow (ρ : Matrix n n ℂ) (hρ : ρ.PosSemidef) (s : ℝ) : (Tr (ρ ^ s)).re = ∑ i, hρ.1.eigenvalues i ^ s := by - rw [← matrixFunction_rpow_eq hρ s, matrixFunction_trace] + have h0 : (0 : Matrix n n ℂ) ≤ ρ := by rw [Matrix.le_iff, sub_zero]; exact hρ + rw [CFC.rpow_eq_cfc_real (a := ρ) (ha := h0), trace_cfc hρ.1] simp [Complex.ofReal_re] /-- HasDerivAt of eigenvalue rpow sum. @@ -211,12 +210,18 @@ lemma trace_rpow_concave (A B : Matrix n n ℂ) (hA : A.PosSemidef) (hB : B.PosS (hA.real_smul hp).add (hB.real_smul (by linarith)) have hlowner := rpow_isLownerConcave hs0 hs1 n A B hA hB p hp hp1 hpsd_mix.1 simp only [] at hlowner - have hfunc_eq : (fun x : ℝ => ((-x ^ s : ℝ) : ℂ)) = (fun x : ℝ => -(((x ^ s : ℝ) : ℂ))) := by - ext x - exact Complex.ofReal_neg _ - rw [hfunc_eq] at hlowner - rw [matrixFunction_neg hA.1, matrixFunction_neg hB.1, matrixFunction_neg hpsd_mix.1, - matrixFunction_rpow_eq hA, matrixFunction_rpow_eq hB, matrixFunction_rpow_eq hpsd_mix] at hlowner + have hA0 : (0 : Matrix n n ℂ) ≤ A := by rw [Matrix.le_iff, sub_zero]; exact hA + have hB0 : (0 : Matrix n n ℂ) ≤ B := by rw [Matrix.le_iff, sub_zero]; exact hB + have hM0 : (0 : Matrix n n ℂ) ≤ p • A + (1 - p) • B := by + rw [Matrix.le_iff, sub_zero]; exact hpsd_mix + have eA : cfc (fun x : ℝ => -(x ^ s)) A = -(A ^ s) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := A) (ha := hA0)] + have eB : cfc (fun x : ℝ => -(x ^ s)) B = -(B ^ s) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := B) (ha := hB0)] + have eM : cfc (fun x : ℝ => -(x ^ s)) (p • A + (1 - p) • B) = + -((p • A + (1 - p) • B) ^ s) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := p • A + (1 - p) • B) (ha := hM0)] + rw [eA, eB, eM] at hlowner have hlowner' : p • A ^ s + (1 - p) • B ^ s ≤ (p • A + (1 - p) • B) ^ s := by have heq : p • -A ^ s + (1 - p) • -B ^ s = -(p • A ^ s + (1 - p) • B ^ s) := by have h1 : p • -A ^ s = -(p • A ^ s) := smul_neg p (A ^ s) @@ -361,17 +366,17 @@ theorem vonNeumannEntropy_map_starAlgEquiv_posDef (hφ : ∀ A, (φ A).trace = A.trace) : S(ρ.map φ hφ) = S(ρ) := by unfold vonNeumannEntropy - have h_log_eq : matrixLog (ρ.map φ hφ).toMatrix (ρ.map φ hφ).isHermitian = - φ (matrixLog ρ.toMatrix ρ.isHermitian) := by - change matrixLog (φ ρ.toMatrix) _ = _ - exact matrixLog_map_starAlgEquiv hρ φ + have h_log_eq : cfc Real.log (ρ.map φ hφ).toMatrix = + φ (cfc Real.log ρ.toMatrix) := by + change cfc Real.log (φ ρ.toMatrix) = _ + exact cfc_log_map_starAlgEquiv hρ φ have h_tr : Tr ((ρ.map φ hφ).toMatrix * - matrixLog (ρ.map φ hφ).toMatrix (ρ.map φ hφ).isHermitian) = - Tr (ρ.toMatrix * matrixLog ρ.toMatrix ρ.isHermitian) := by + cfc Real.log (ρ.map φ hφ).toMatrix) = + Tr (ρ.toMatrix * cfc Real.log ρ.toMatrix) := by rw [h_log_eq, DensityMatrix.map_toMatrix, ← map_mul, hφ] change -(Tr ((ρ.map φ hφ).toMatrix * - matrixLog (ρ.map φ hφ).toMatrix (ρ.map φ hφ).isHermitian)).re = - -(Tr (ρ.toMatrix * matrixLog ρ.toMatrix ρ.isHermitian)).re + cfc Real.log (ρ.map φ hφ).toMatrix)).re = + -(Tr (ρ.toMatrix * cfc Real.log ρ.toMatrix)).re rw [h_tr] /-- Specialisation of `vonNeumannEntropy_map_starAlgEquiv_posDef` to reindexing. -/ @@ -399,8 +404,7 @@ theorem vonNeumannEntropy_regularize_eq_negMulLog_sum [Nonempty n] (ρ : DensityMatrix n) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : vonNeumannEntropy (DensityMatrix.regularize ρ hε hε') = ∑ i, Real.negMulLog ((1 - ε) * ρ.isHermitian.eigenvalues i + ε / Fintype.card n) := by - rw [vonNeumannEntropy_eq_matrixFunction_re] - rw [matrixFunction_eq_cfc] + rw [vonNeumannEntropy_eq_cfc_re] rw [DensityMatrix.regularize_eq_cfc ρ hε hε'] have hρ_sa : IsSelfAdjoint ρ.toMatrix := ρ.isHermitian rw [← cfc_comp (R := ℝ) Real.negMulLog @@ -408,9 +412,8 @@ theorem vonNeumannEntropy_regularize_eq_negMulLog_sum [Nonempty n] hρ_sa Real.continuous_negMulLog.continuousOn (by fun_prop)] rw [show (Real.negMulLog ∘ (fun x : ℝ => (1 - ε) * x + ε / (Fintype.card n : ℝ))) = (fun x : ℝ => Real.negMulLog ((1 - ε) * x + ε / (Fintype.card n : ℝ))) from rfl] - rw [← matrixFunction_eq_cfc ρ.isHermitian - (fun x : ℝ => Real.negMulLog ((1 - ε) * x + ε / Fintype.card n))] - rw [matrixFunction_trace, Complex.re_sum] + rw [trace_cfc ρ.isHermitian + (fun x : ℝ => Real.negMulLog ((1 - ε) * x + ε / Fintype.card n)), Complex.re_sum] simp_rw [Complex.ofReal_re] /-- The eigenvalue-formula function `ε ↦ ∑ᵢ Real.negMulLog ((1-ε) λᵢ + ε/d)` is diff --git a/QuantumSystem/Analysis/Matrix/Effros.lean b/QuantumSystem/Analysis/Matrix/Effros.lean index 297aea7..d879051 100644 --- a/QuantumSystem/Analysis/Matrix/Effros.lean +++ b/QuantumSystem/Analysis/Matrix/Effros.lean @@ -11,7 +11,7 @@ This file formalises the Effros (2008) machinery used to prove Lieb's joint conc ## Contents 1. **Compression lemmas** – `compression_pow_eq`, `compression_aeval_eq`, - `eigenvalues_compression_subset`, and `matrixFunction_compression_of_commuting`: + `eigenvalues_compression_subset`, and `cfc_compression_of_commuting`: the map `X ↦ V† X V` (sandwiching) interacts well with polynomial/functional calculus when `V†V = I` and `M` commutes with `VV†`. 2. **Block diagonal** – `compression_of_fromBlocks_cfc` and related CFC lemmas. @@ -334,12 +334,10 @@ theorem rightMulMatrix_posDef {m : Type*} [Fintype m] [DecidableEq m] /-- Matrix perspective of a function `f` using the Kubo-Ando style formula. Defined for PSD `L` and PD `R`. -/ noncomputable def matrixPerspective {m : Type*} [Fintype m] [DecidableEq m] - (f : ℝ → ℝ) (L R : Matrix m m ℂ) (hL : L.PosSemidef) (hR : R.PosDef) : Matrix m m ℂ := + (f : ℝ → ℝ) (L R : Matrix m m ℂ) (_hL : L.PosSemidef) (hR : R.PosDef) : Matrix m m ℂ := let Rinv := matrixInvSqrt R hR let inner := Rinvᴴ * L * Rinv - let hinner : inner.IsHermitian := - isHermitian_conjTranspose_mul_mul (B := Rinv) (A := L) hL.1 - let fInner := matrixFunction (fun x => (f x : ℂ)) inner hinner + let fInner := cfc f inner let Rhalf := matrixSqrt R hR.posSemidef Rhalf * fInner * Rhalf @@ -485,21 +483,18 @@ theorem matrixPerspective_joint_convex.{v} {m : Type v} [Fintype m] [DecidableEq (isHermitian_conjTranspose_mul_mul (B := A₁) (A := T₁) hT₁_herm) (isHermitian_conjTranspose_mul_mul (B := A₂) (A := T₂) hT₂_herm) have hconv' := hconv (m := m) (A := A₁) (B := A₂) (T₁ := T₁) (T₂ := T₂) hT₁ hT₂ hAB hC + simp only [] at hconv' have hpsd : - (A₁ᴴ * - matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 * A₁ + - A₂ᴴ * - matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 * A₂ - - matrixFunction (fun x => (f x : ℂ)) (A₁ᴴ * T₁ * A₁ + A₂ᴴ * T₂ * A₂) hC + (A₁ᴴ * cfc f T₁ * A₁ + + A₂ᴴ * cfc f T₂ * A₂ - + cfc f (A₁ᴴ * T₁ * A₁ + A₂ᴴ * T₂ * A₂) ).PosSemidef := by simpa [Matrix.le_iff] using hconv' have hpsd' : (Rhalfᴴ * - (A₁ᴴ * - matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 * A₁ + - A₂ᴴ * - matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 * A₂ - - matrixFunction (fun x => (f x : ℂ)) (A₁ᴴ * T₁ * A₁ + A₂ᴴ * T₂ * A₂) hC) * Rhalf + (A₁ᴴ * cfc f T₁ * A₁ + + A₂ᴴ * cfc f T₂ * A₂ - + cfc f (A₁ᴴ * T₁ * A₁ + A₂ᴴ * T₂ * A₂)) * Rhalf ).PosSemidef := hpsd.conjTranspose_mul_mul_same Rhalf have hRhalf_eq : Rhalfᴴ = Rhalf := hRhalf_herm.eq @@ -536,13 +531,9 @@ theorem matrixPerspective_joint_convex.{v} {m : Type v} [Fintype m] [DecidableEq rw [hA₂_adj, mul_smul_comm]; congr 1; rw [← mul_assoc, hRhalf_Rinv, one_mul] have hA₂_Rhalf : A₂ * Rhalf = (Real.sqrt w₂ : ℂ) • R₂half := by simp only [A₂, smul_mul_assoc, mul_assoc, hRinv_Rhalf, mul_one] - -- matrixFunction_congr for the f(C) term (precomputed for performance) - have hmfC : matrixFunction (fun x => (f x : ℂ)) - (A₁ᴴ * T₁ * A₁ + A₂ᴴ * T₂ * A₂) hC = - matrixFunction (fun x => (f x : ℂ)) (Rinvᴴ * L * Rinv) - (isHermitian_conjTranspose_mul_mul (B := Rinv) (A := L) - ((hL₁.real_smul hw₁).add (hL₂.real_smul hw₂)).1) := - matrixFunction_congr (fun x => (f x : ℂ)) hC _ hinner + -- congruence for the f(C) term (precomputed for performance) + have hmfC : cfc f (A₁ᴴ * T₁ * A₁ + A₂ᴴ * T₂ * A₂) = cfc f (Rinvᴴ * L * Rinv) := + congrArg (cfc f) hinner -- Final step: apply sandwich equation and conclude have hfinal : matrixPerspective f L R ((hL₁.real_smul hw₁).add (hL₂.real_smul hw₂)) hR ≤ @@ -576,8 +567,7 @@ lemma perspective_inner_eq_mul_inv {n : Type*} [Fintype n] [DecidableEq n] (hcomm : L * R = R * L) : (matrixInvSqrt R hR)ᴴ * L * matrixInvSqrt R hR = L * R⁻¹ := by rw [perspective_inner_eq_commuting hL hR hcomm] - have hRinv_eq : matrixInvSqrt R hR = R ^ (-1 / 2 : ℝ) := by - simpa [matrixInvSqrt] using matrixFunction_rpow_eq hR.posSemidef (-1 / 2 : ℝ) + have hRinv_eq : matrixInvSqrt R hR = R ^ (-1 / 2 : ℝ) := matrixInvSqrt_eq_rpow hR rw [hRinv_eq] letI : NormedRing (Matrix n n ℂ) := Matrix.linftyOpNormedRing letI : NormedAlgebra ℝ (Matrix n n ℂ) := Matrix.linftyOpNormedAlgebra @@ -767,9 +757,7 @@ lemma perspective_inner_rpow_comm_sqrt_leftRight {m : Type*} [Fintype m] [Decida have hR_nonneg : (0 : Matrix (m × m) (m × m) ℂ) ≤ R := by simpa [Matrix.le_iff] using hR_pd.posSemidef have hR_unit : IsUnit R := hR_pd.isUnit - have hRhalf_eq : T = R ^ (1 / 2 : ℝ) := by - change matrixSqrt R hR_pd.posSemidef = R ^ (1 / 2 : ℝ) - simpa [matrixSqrt] using matrixFunction_rpow_eq hR_pd.posSemidef (1 / 2 : ℝ) + have hRhalf_eq : T = R ^ (1 / 2 : ℝ) := matrixSqrt_eq_rpow hR_pd.posSemidef have hR_det : IsUnit R.det := (Matrix.isUnit_iff_isUnit_det R).mp hR_unit have hLRinv_comm_R : Commute R (L * R⁻¹) := by rw [Commute, SemiconjBy] @@ -805,13 +793,9 @@ theorem matrixPerspective_neg_leftRight_eq {m : Type*} [Fintype m] [DecidableEq set T := matrixSqrt R hR_pd.posSemidef have hinner_psd : (Sᴴ * L * S).PosSemidef := hL_psd.conjTranspose_mul_mul_same S - have hfun_neg : matrixFunction (fun x => ((-(x ^ p) : ℝ) : ℂ)) - (Sᴴ * L * S) hinner_psd.1 = -((Sᴴ * L * S) ^ p) := by - have h1 : (fun x : ℝ => ((-(x ^ p) : ℝ) : ℂ)) = (fun x : ℝ => -((x ^ p : ℝ) : ℂ)) := by - ext x - push_cast - ring - rw [h1, matrixFunction_neg hinner_psd.1, matrixFunction_rpow_eq hinner_psd p] + have hfun_neg : cfc (fun x : ℝ => -(x ^ p)) (Sᴴ * L * S) = -((Sᴴ * L * S) ^ p) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := Sᴴ * L * S) + (ha := by rw [Matrix.le_iff, sub_zero]; exact hinner_psd)] have hRhalf_sq : T * T = R := matrixSqrt_mul_self_posSemidef hR_pd.posSemidef have hinnerp_comm_Rhalf : (Sᴴ * L * S) ^ p * T = T * (Sᴴ * L * S) ^ p := by simpa [L, R, S, T] using diff --git a/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean b/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean index 4b69049..96c2d16 100644 --- a/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean +++ b/QuantumSystem/Analysis/Matrix/HermitianFunctionalCalculus.lean @@ -15,23 +15,24 @@ This file develops the core tools for matrix analysis. Foundational lemmas about matrices, positive semidefiniteness, block-matrix identities, and the Löwner order are in `QuantumSystem.ForMathlib.Analysis.Matrix.*`. +All functional calculus is expressed directly through Mathlib's continuous functional +calculus `cfc`; the spectral expansion `cfc f A = U diag(f(λᵢ)) Uᴴ` is `cfc_spectral_eq`. + ## Main results -### Functional Calculus -- `matrixFunction f A hA`: spectral decomposition f(A) = U diag(f(λᵢ)) U* - for Hermitian A with eigendecomposition A = UΛ U*. -- Algebraic properties: `matrixFunction_id`, `matrixFunction_neg`, `matrixFunction_add`, - `matrixFunction_smul`, `matrixFunction_const`, `matrixFunction_add_const`, etc. -- Complex power instances: `matrixFunction_cpow_zero`, `matrixFunction_cpow_one`. -- Compatibility with Mathlib's CFC: `matrixFunction_eq_cfc`. -- Special functions: `matrixLog`, `matrixSqrt` (via `matrixFunction`). +### Continuous Functional Calculus +- `cfc_spectral_eq`: spectral decomposition `cfc f A = U diag(f(λᵢ)) Uᴴ` + for Hermitian A with eigendecomposition A = UΛ Uᴴ. +- `trace_cfc`, `trace_mul_cfc`: trace formulas `Tr(f(A)) = ∑ f(λᵢ)` and `Tr(A·f(A)) = ∑ λᵢ f(λᵢ)`. +- `cfc_isHermitian`, `mul_cfc_isHermitian`: `f(A)` and `A·f(A)` are Hermitian for real `f`. +- `cfc_add_const_eq`, `cfc_inv_add_const`, `cfc_resolvent`: affine / resolvent identities. +- `cfc_compression_of_commuting`: `Vᴴ f(M) V = f(Vᴴ M V)` for an isometry commuting with `M`. +- Matrix logarithm `cfc Real.log`: `cfc_spectral_eq`, `cfc_log_spectral_eq`, `cfc_log_map_starAlgEquiv`. +- Special functions: `matrixSqrt`, `matrixInvSqrt` defined via `CFC.rpow`. ### Hermitian and PSD Structure -- `matrixFunction_isHermitian`: f(A) is Hermitian when f maps ℝ to ℝ. -- `matrixFunction_posSemidef`: f(A) ≥ 0 when f(λᵢ) ≥ 0 on eigenvalues. -- `matrixFunction_inv_add_const`: (A + tI)⁻¹ from `matrixFunction`. -- `matrixFunction_rpow_eq`: `matrixFunction` agrees with `CFC.rpow` on PSD matrices. -- `matrixSqrt`: the matrix square root A¹⁄² for PSD A. +- `matrixSqrt`: the matrix square root A¹⁄² for PSD A (`= A ^ (1/2 : ℝ)`). +- `matrixInvSqrt`: the matrix inverse square root A⁻¹⁄² for PD A (`= A ^ (-1/2 : ℝ)`). - `matrixInvSqrt_commute_of_commute`: R⁻¹⁄² commutes with L when L and R commute (for PSD L, PD R). @@ -53,205 +54,75 @@ namespace Matrix open scoped MatrixOrder ComplexOrder -/-- Functional calculus for Hermitian matrices via spectral decomposition. -Given f : ℝ → ℂ and a Hermitian matrix A = U Λ U*, we define f(A) = U f(Λ) U* -where f(Λ) applies f to each diagonal entry (eigenvalue). -/ -noncomputable def matrixFunction {m : Type*} [Fintype m] [DecidableEq m] - (f : ℝ → ℂ) (A : Matrix m m ℂ) (hA : A.IsHermitian) : Matrix m m ℂ := - let U : Matrix m m ℂ := hA.eigenvectorUnitary - let Λ := diagonal (fun i => f (hA.eigenvalues i)) - U * Λ * Uᴴ +/-- `cfc f A` of a Hermitian matrix expands into the spectral decomposition +`U · diag(f(λᵢ)) · Uᴴ` attached to the chosen Hermitian proof. -/ +lemma cfc_spectral_eq {m : Type*} [Fintype m] [DecidableEq m] + {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℝ) : + cfc f A = + (hA.eigenvectorUnitary : Matrix m m ℂ) * + diagonal (fun i => ((f (hA.eigenvalues i) : ℝ) : ℂ)) * + (hA.eigenvectorUnitary : Matrix m m ℂ)ᴴ := by + rw [Matrix.IsHermitian.cfc_eq hA f] + unfold Matrix.IsHermitian.cfc + rw [Unitary.conjStarAlgAut_apply] + simp only [Function.comp_def, star_eq_conjTranspose] + rfl -/-- Trace of f(A) equals sum of f(λ_i) by cyclicity of trace and unitarity of U. -/ -lemma matrixFunction_trace {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) (f : ℝ → ℂ) : - (matrixFunction f A hA).trace = ∑ i, f (hA.eigenvalues i) := by - unfold matrixFunction - rw [trace_mul_cycle] +/-- Trace of `cfc f A` equals the sum of `f` over the eigenvalues of `A`. -/ +lemma trace_cfc {m : Type*} [Fintype m] [DecidableEq m] + {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℝ) : + (cfc f A).trace = ∑ i, (f (hA.eigenvalues i) : ℂ) := by + rw [cfc_spectral_eq hA f, trace_mul_cycle] have h := Unitary.coe_star_mul_self hA.eigenvectorUnitary simp only [star_eq_conjTranspose] at h rw [h, Matrix.one_mul] exact trace_diagonal _ -/-- matrixFunction of a real-valued function produces a Hermitian matrix. -/ -lemma matrixFunction_isHermitian {m : Type*} [Fintype m] [DecidableEq m] +/-- `f(A)` is Hermitian for Hermitian `A` and real `f` (continuous functional calculus). -/ +lemma cfc_isHermitian {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℝ) : - (matrixFunction (fun x => (f x : ℂ)) A hA).IsHermitian := by - unfold matrixFunction - -- U * D * Uᴴ is Hermitian when D is Hermitian and U is unitary - have hD : (diagonal (fun i => (f (hA.eigenvalues i) : ℂ))).IsHermitian := by + (cfc f A).IsHermitian := by + rw [cfc_spectral_eq hA f] + have hD : (diagonal (fun i => ((f (hA.eigenvalues i) : ℝ) : ℂ))).IsHermitian := by rw [isHermitian_diagonal_iff] intro i exact Complex.conj_ofReal _ - -- (U D Uᴴ)ᴴ = U Dᴴ Uᴴ = U D Uᴴ since D is Hermitian rw [IsHermitian] simp only [conjTranspose_mul, conjTranspose_conjTranspose] conv_rhs => rw [mul_assoc] rw [hD] -/-- Spectral lemma: matrixFunction(id) = A. -/ -lemma matrixFunction_id {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) : - matrixFunction (fun x => (x : ℂ)) A hA = A := by - unfold matrixFunction - simp only - conv_rhs => rw [hA.spectral_theorem] - unfold Unitary.conjStarAlgAut - simp only [MonoidHom.coe_mk, OneHom.coe_mk] - rfl - -/-- Negation distributes through matrixFunction. -/ -lemma matrixFunction_neg {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℂ) : - matrixFunction (fun x => -f x) A hA = -matrixFunction f A hA := by - unfold matrixFunction - simp only - have hdiag : diagonal (fun i => -f (hA.eigenvalues i)) = - -diagonal (fun i => f (hA.eigenvalues i)) := by - ext i j - simp only [diagonal_apply, neg_apply] - split_ifs <;> ring - rw [hdiag, mul_neg, neg_mul] - -/-- matrixFunction distributes over addition. -/ -lemma matrixFunction_add {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (f g : ℝ → ℂ) : - matrixFunction (fun x => f x + g x) A hA = - matrixFunction f A hA + matrixFunction g A hA := by - unfold matrixFunction - simp only - have hdiag : - diagonal (fun i => f (hA.eigenvalues i) + g (hA.eigenvalues i)) = - diagonal (fun i => f (hA.eigenvalues i)) + - diagonal (fun i => g (hA.eigenvalues i)) := by - ext i j - by_cases h : i = j - · subst h - simp - · simp [h] - rw [hdiag] - rw [Matrix.mul_add, Matrix.add_mul] - -/-- matrixFunction commutes with scalar multiplication. -/ -lemma matrixFunction_smul {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (c : ℂ) (f : ℝ → ℂ) : - matrixFunction (fun x => c * f x) A hA = c • matrixFunction f A hA := by - unfold matrixFunction - simp only - have hdiag : - diagonal (fun i => c * f (hA.eigenvalues i)) = - c • diagonal (fun i => f (hA.eigenvalues i)) := by - ext i j - by_cases h : i = j - · subst h - simp - · simp [h] - rw [hdiag] - rw [Matrix.mul_smul, Matrix.smul_mul] - -/-- matrixFunction of a constant function is a scalar multiple of the identity. -/ -lemma matrixFunction_const {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (c : ℂ) : - matrixFunction (fun _ => c) A hA = c • (1 : Matrix m m ℂ) := by - classical - unfold matrixFunction - simp only - have hdiag : diagonal (fun _ => c) = c • (1 : Matrix m m ℂ) := by - ext i j - by_cases h : i = j - · subst h - simp - · simp [h] - rw [hdiag] - have hU : (hA.eigenvectorUnitary : Matrix m m ℂ) * - (hA.eigenvectorUnitary : Matrix m m ℂ)ᴴ = 1 := by - simpa [star_eq_conjTranspose] using Unitary.coe_mul_star_self hA.eigenvectorUnitary - simp [hU] - -/-- matrixFunction depends only on the matrix value, not on the specific proof term. - If two matrices are equal, their matrixFunctions are equal. -/ -lemma matrixFunction_congr {m : Type*} [Fintype m] [DecidableEq m] - {A B : Matrix m m ℂ} (f : ℝ → ℂ) (hA : A.IsHermitian) (hB : B.IsHermitian) - (hAB : A = B) : matrixFunction f A hA = matrixFunction f B hB := by - subst hAB - rfl - -/-- matrixFunction equals Mathlib's IsHermitian.cfc for real-valued functions. -This connects our spectral decomposition definition to Mathlib's CFC infrastructure. -/ -lemma matrixFunction_eq_cfc {m : Type*} [Fintype m] [DecidableEq m] +/-- `Tr(A · f(A)) = ∑ᵢ λᵢ · f(λᵢ)` for the continuous functional calculus. -/ +lemma trace_mul_cfc {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℝ) : - matrixFunction (fun x => (f x : ℂ)) A hA = cfc f A := by - have h : matrixFunction (fun x => (f x : ℂ)) A hA = hA.cfc f := by - unfold matrixFunction Matrix.IsHermitian.cfc - rw [Unitary.conjStarAlgAut_apply] - simp only [Function.comp_def, star_eq_conjTranspose] - rfl - calc - matrixFunction (fun x => (f x : ℂ)) A hA = hA.cfc f := h - _ = cfc f A := by - simpa using (Matrix.IsHermitian.cfc_eq (A := A) (hA := hA) (f := f)).symm - -/-- `matrixFunction` for the affine function `x ↦ x + t` adds `t • I`. -/ -lemma matrixFunction_add_const {m : Type*} [Fintype m] [DecidableEq m] + (A * cfc f A).trace = ∑ i, ((hA.eigenvalues i : ℂ) * (f (hA.eigenvalues i) : ℂ)) := by + have hfin : (spectrum ℝ A).Finite := by + rw [hA.spectrum_real_eq_range_eigenvalues]; exact Set.finite_range _ + have hcont_id : ContinuousOn (fun x : ℝ => x) (spectrum ℝ A) := continuousOn_id + have hcont_f : ContinuousOn f (spectrum ℝ A) := hfin.continuousOn f + have hsa : IsSelfAdjoint A := hA + have hmul : A * cfc f A = cfc (fun x => x * f x) A := by + rw [cfc_mul (fun x => x) f A hcont_id hcont_f, cfc_id' (R := ℝ) (a := A) hsa] + rw [hmul, trace_cfc hA (fun x => x * f x)] + refine Finset.sum_congr rfl fun i _ => ?_ + push_cast + ring + +/-- `cfc (· + t) A = A + t • I` for Hermitian `A` via the continuous functional calculus. -/ +lemma cfc_add_const_eq {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.IsHermitian) (t : ℝ) : - matrixFunction (fun x => ((x + t : ℝ) : ℂ)) A hA = A + (t : ℂ) • 1 := by - classical - unfold matrixFunction - set U : Matrix m m ℂ := (hA.eigenvectorUnitary : Matrix m m ℂ) - have hdiag : - diagonal (fun i => ((hA.eigenvalues i + t : ℝ) : ℂ)) = - diagonal (fun i => (hA.eigenvalues i : ℂ)) + (t : ℂ) • 1 := by - ext i j - change (diagonal (fun i => ((hA.eigenvalues i + t : ℝ) : ℂ))) i j = - (diagonal (fun i => (hA.eigenvalues i : ℂ))) i j + ((t : ℂ) • (1 : Matrix m m ℂ)) i j - by_cases h : i = j - · subst h - rw [Matrix.diagonal_apply_eq, Matrix.diagonal_apply_eq, Matrix.smul_apply, - Matrix.one_apply_eq, smul_eq_mul, mul_one] - push_cast; ring - · rw [Matrix.diagonal_apply_ne _ h, Matrix.diagonal_apply_ne _ h, Matrix.smul_apply, - Matrix.one_apply_ne h, smul_zero, add_zero] - rw [hdiag] - simp only [Matrix.mul_add, Matrix.add_mul] - have hU : U * Uᴴ = 1 := by - simpa [U, star_eq_conjTranspose] using Unitary.coe_mul_star_self hA.eigenvectorUnitary - have hU1 : U * (1 : Matrix m m ℂ) * Uᴴ = 1 := by - simp [hU] - have hspec := hA.spectral_theorem - rw [Unitary.conjStarAlgAut_apply, star_eq_conjTranspose] at hspec - have hspec' : U * diagonal (fun i => (hA.eigenvalues i : ℂ)) * Uᴴ = A := by - simpa [U, Function.comp] using hspec.symm - -- Rewrite the two diagonal terms using the spectral theorem and unitarity. - calc - U * diagonal (fun i => (hA.eigenvalues i : ℂ)) * Uᴴ + - U * ((t : ℂ) • (1 : Matrix m m ℂ)) * Uᴴ = - A + (t : ℂ) • 1 := by - rw [hspec'] - have hUt : U * ((t : ℂ) • (1 : Matrix m m ℂ)) * Uᴴ = - (t : ℂ) • (U * (1 : Matrix m m ℂ) * Uᴴ) := by - calc - U * ((t : ℂ) • (1 : Matrix m m ℂ)) * Uᴴ = - ((t : ℂ) • (U * (1 : Matrix m m ℂ))) * Uᴴ := by - simp - _ = (t : ℂ) • (U * (1 : Matrix m m ℂ) * Uᴴ) := by - simp - calc - A + U * ((t : ℂ) • (1 : Matrix m m ℂ)) * Uᴴ = - A + (t : ℂ) • (U * (1 : Matrix m m ℂ) * Uᴴ) := by - rw [hUt] - _ = A + (t : ℂ) • 1 := by - calc - A + (t : ℂ) • (U * (1 : Matrix m m ℂ) * Uᴴ) = - A + (t : ℂ) • (U * Uᴴ) := by - simp - _ = A + (t : ℂ) • 1 := by - simp [hU] + cfc (fun x => x + t) A = A + (t : ℂ) • 1 := by + have hsa : IsSelfAdjoint A := hA + have hcont_id : ContinuousOn (fun x : ℝ => x) (spectrum ℝ A) := continuousOn_id + have hcont_c : ContinuousOn (fun _ : ℝ => t) (spectrum ℝ A) := continuousOn_const + rw [cfc_add A (fun x => x) (fun _ => t) hcont_id hcont_c, cfc_id' (R := ℝ) (a := A) hsa, + cfc_const t A, Algebra.algebraMap_eq_smul_one] + congr 1 -/-- `matrixFunction` for `x ↦ (x + t)⁻¹` equals `(A + t•I)⁻¹` when `t > 0` and `A` is PSD. -/ -lemma matrixFunction_inv_add_const {m : Type*} [Fintype m] [DecidableEq m] +/-- `cfc ((· + t)⁻¹) A = (A + t • I)⁻¹` for PSD `A` and `t > 0`. -/ +lemma cfc_inv_add_const {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosSemidef) {t : ℝ} (ht : 0 < t) : - matrixFunction (fun x => ((x + t : ℝ) : ℂ)⁻¹) A hA.1 = - (A + (t : ℂ) • 1)⁻¹ := by + cfc (fun x : ℝ => (x + t)⁻¹) A = (A + (t : ℂ) • 1)⁻¹ := by classical have hA' : A.IsHermitian := hA.1 have hneq : ∀ x ∈ spectrum ℝ A, (x + t) ≠ 0 := by @@ -259,159 +130,48 @@ lemma matrixFunction_inv_add_const {m : Type*} [Fintype m] [DecidableEq m] have hx' : x ∈ Set.range hA'.eigenvalues := by simpa [hA'.spectrum_real_eq_range_eigenvalues] using hx rcases hx' with ⟨i, rfl⟩ - have hx_nonneg : 0 ≤ hA.1.eigenvalues i := hA.eigenvalues_nonneg i - linarith - have hcfcinv : - cfc (fun x : ℝ => (x + t)⁻¹) A = Ring.inverse (cfc (fun x : ℝ => x + t) A) := by + linarith [hA.eigenvalues_nonneg i] + have hcfcinv : cfc (fun x : ℝ => (x + t)⁻¹) A = Ring.inverse (cfc (fun x : ℝ => x + t) A) := by simpa using (cfc_inv (A := Matrix m m ℂ) (f := fun x : ℝ => x + t) (a := A) hneq) - have hcfcaff : cfc (fun x : ℝ => x + t) A = A + (t : ℂ) • 1 := by - have h := matrixFunction_add_const (m := m) hA' t - calc - cfc (fun x : ℝ => x + t) A = - matrixFunction (fun x => ((x + t : ℝ) : ℂ)) A hA' := by - simpa using (matrixFunction_eq_cfc hA' (fun x => x + t)).symm - _ = A + (t : ℂ) • 1 := h + have hcfcaff : cfc (fun x : ℝ => x + t) A = A + (t : ℂ) • 1 := cfc_add_const_eq hA' t have hposdef : (A + (t : ℂ) • 1).PosDef := PosSemidef.add_smul_one_posDef hA ht have hunit : IsUnit (A + (t : ℂ) • 1) := hposdef.isUnit let _ := hunit.invertible have hcfcaff_inv : Ring.inverse (cfc (fun x : ℝ => x + t) A) = (A + (t : ℂ) • 1)⁻¹ := by simpa [hcfcaff] using (Ring.inverse_unit hunit.unit) - have hmf : matrixFunction (fun x => ((x + t : ℝ) : ℂ)⁻¹) A hA.1 = - cfc (fun x : ℝ => (x + t)⁻¹) A := by - simpa using (matrixFunction_eq_cfc hA' (fun x => (x + t)⁻¹)) - rw [hmf, hcfcinv, hcfcaff_inv] + rw [hcfcinv, hcfcaff_inv] -/-- `matrixFunction` agrees with `CFC.rpow` for PSD matrices. -/ -lemma matrixFunction_rpow_eq {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.PosSemidef) (s : ℝ) : - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) A hA.1 = A ^ s := by - have hA0 : 0 ≤ A := by - simpa [Matrix.le_iff] using hA - calc - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) A hA.1 = cfc (fun x : ℝ => x ^ s) A := by - simpa using (matrixFunction_eq_cfc hA.1 (fun x => x ^ s)) - _ = A ^ s := by - symm - exact CFC.rpow_eq_cfc_real (A := Matrix m m ℂ) (a := A) (y := s) (ha := hA0) - -/-- Resolvent form for `matrixFunction` on PSD matrices. -/ -lemma matrixFunction_resolvent {m : Type*} [Fintype m] [DecidableEq m] +/-- Resolvent form for `cfc` on PSD matrices: +`cfc (1 - r·(· + r)⁻¹) A = I - r·(A + r·I)⁻¹` for `r > 0`. -/ +lemma cfc_resolvent {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosSemidef) {r : ℝ} (hr : 0 < r) : - matrixFunction (fun x => ((1 - r * (x + r)⁻¹ : ℝ) : ℂ)) A hA.1 = + cfc (fun x => 1 - r * (x + r)⁻¹) A = (1 : Matrix m m ℂ) - (r : ℂ) • (A + (r : ℂ) • 1)⁻¹ := by - have hfun_inv : (fun x : ℝ => ((x : ℂ) + (r : ℂ))⁻¹) = - (fun x : ℝ => ((x + r : ℝ) : ℂ)⁻¹) := by - funext x - simp - have hfun : (fun x : ℝ => ((1 - r * (x + r)⁻¹ : ℝ) : ℂ)) = - (fun x : ℝ => (1 : ℂ) + -((r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹)) := by - funext x - push_cast - ring - have hconst : matrixFunction (fun _ => (1 : ℂ)) A hA.1 = (1 : Matrix m m ℂ) := by - simpa using (matrixFunction_const (m := m) hA.1 (1 : ℂ)) - have hinv : matrixFunction (fun x => ((x + r : ℝ) : ℂ)⁻¹) A hA.1 = - (A + (r : ℂ) • 1)⁻¹ := by - exact matrixFunction_inv_add_const (m := m) hA hr - calc - matrixFunction (fun x => ((1 - r * (x + r)⁻¹ : ℝ) : ℂ)) A hA.1 = - matrixFunction (fun x => (1 : ℂ) + -((r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹)) A hA.1 := by - rw [hfun] - _ = matrixFunction (fun _ => (1 : ℂ)) A hA.1 + - matrixFunction (fun x => -((r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹)) A hA.1 := by - simpa using (matrixFunction_add hA.1 (fun _ => (1 : ℂ)) - (fun x => -((r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹))) - _ = (1 : Matrix m m ℂ) + - -((r : ℂ) • matrixFunction (fun x => ((x : ℂ) + (r : ℂ))⁻¹) A hA.1) := by - have hsmul : - matrixFunction (fun x => (r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹) A hA.1 = - (r : ℂ) • matrixFunction (fun x => ((x : ℂ) + (r : ℂ))⁻¹) A hA.1 := by - simpa using - (matrixFunction_smul hA.1 (r : ℂ) (fun x => ((x : ℂ) + (r : ℂ))⁻¹)) - have hneg : - matrixFunction (fun x => -((r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹)) A hA.1 = - -((r : ℂ) • matrixFunction (fun x => ((x : ℂ) + (r : ℂ))⁻¹) A hA.1) := by - simpa [hsmul] using - (matrixFunction_neg hA.1 (fun x => (r : ℂ) * ((x : ℂ) + (r : ℂ))⁻¹)) - simp [hconst, hneg] - _ = (1 : Matrix m m ℂ) - (r : ℂ) • (A + (r : ℂ) • 1)⁻¹ := by - calc - (1 : Matrix m m ℂ) + - -((r : ℂ) • matrixFunction (fun x => ((x : ℂ) + (r : ℂ))⁻¹) A hA.1) = - (1 : Matrix m m ℂ) + -((r : ℂ) • (A + (r : ℂ) • 1)⁻¹) := by - have hinv' : - matrixFunction (fun x : ℝ => ((x : ℂ) + (r : ℂ))⁻¹) A hA.1 = - (A + (r : ℂ) • 1)⁻¹ := by - simpa [hfun_inv] using hinv - simp [hinv'] - _ = (1 : Matrix m m ℂ) - (r : ℂ) • (A + (r : ℂ) • 1)⁻¹ := by - simp [sub_eq_add_neg] - -/-- matrixFunction preserves positive semidefiniteness when f maps nonneg eigenvalues to nonneg. -/ -lemma matrixFunction_posSemidef {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.PosSemidef) - (f : ℝ → ℝ) (hf : ∀ i, 0 ≤ f (hA.1.eigenvalues i)) : - (matrixFunction (fun x => (f x : ℂ)) A hA.1).PosSemidef := by - unfold matrixFunction - have hD : (diagonal (fun i => (f (hA.1.eigenvalues i) : ℂ))).PosSemidef := - PosSemidef.diagonal_ofReal hf - have key := hD.conjTranspose_mul_mul_same ((hA.1.eigenvectorUnitary : Matrix m m ℂ)ᴴ) - simp only [conjTranspose_conjTranspose] at key - exact key - -/-- Product of two matrixFunctions is the matrixFunction of the pointwise product. -Since both share the eigenbasis U, f(A) g(A) = U diag(f(λ) · g(λ)) U*. -/ -lemma matrixFunction_mul {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (f g : ℝ → ℂ) : - matrixFunction f A hA * matrixFunction g A hA = - matrixFunction (fun x => f x * g x) A hA := by - unfold matrixFunction - set U : Matrix m m ℂ := (hA.eigenvectorUnitary : Matrix m m ℂ) with hU_def - have hUU : Uᴴ * U = 1 := by - simpa [star_eq_conjTranspose] using Unitary.coe_star_mul_self hA.eigenvectorUnitary - simp only [hU_def, Matrix.mul_assoc] + have hA' : A.IsHermitian := hA.1 + have hneq : ∀ x ∈ spectrum ℝ A, (x + r) ≠ 0 := by + intro x hx + have hx' : x ∈ Set.range hA'.eigenvalues := by + simpa [hA'.spectrum_real_eq_range_eigenvalues] using hx + rcases hx' with ⟨i, rfl⟩ + linarith [hA.eigenvalues_nonneg i] + have hcont_inv : ContinuousOn (fun x : ℝ => (x + r)⁻¹) (spectrum ℝ A) := + ContinuousOn.inv₀ (by fun_prop) hneq + have hcontc : ContinuousOn (fun _ : ℝ => (1 : ℝ)) (spectrum ℝ A) := continuousOn_const + have hcontri : ContinuousOn (fun x : ℝ => r * (x + r)⁻¹) (spectrum ℝ A) := + continuousOn_const.mul hcont_inv + rw [cfc_sub (fun _ : ℝ => (1 : ℝ)) (fun x => r * (x + r)⁻¹) A hcontc hcontri, + cfc_const (1 : ℝ) A, map_one, + cfc_const_mul r (fun x : ℝ => (x + r)⁻¹) A hcont_inv, + cfc_inv_add_const hA hr] congr 1 - rw [← Matrix.mul_assoc Uᴴ U, hUU, Matrix.one_mul, ← Matrix.mul_assoc, diagonal_mul_diagonal] - -/-- Tr(A · f(A)) = ∑ᵢ λᵢ · f(λᵢ). -We first rewrite A as id(A) via `matrixFunction_id`, then apply -`matrixFunction_mul` and `matrixFunction_trace`. -/ -lemma trace_mul_matrixFunction {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) (f : ℝ → ℂ) : - (A * matrixFunction f A hA).trace = - ∑ i, ((hA.eigenvalues i : ℂ) * f (hA.eigenvalues i)) := by - suffices h : (matrixFunction (fun x => (x : ℂ)) A hA * - matrixFunction f A hA).trace = - ∑ i, ((hA.eigenvalues i : ℂ) * f (hA.eigenvalues i)) by - rwa [matrixFunction_id] at h - rw [matrixFunction_mul, matrixFunction_trace] -/-- A Hermitian matrix commutes with any matrixFunction of itself. -This follows from `matrixFunction_id` (A = id(A)) and `matrixFunction_mul` -(id(A) · f(A) = f(A) · id(A) by pointwise commutativity of multiplication). -/ -lemma commute_matrixFunction_self {m : Type*} [Fintype m] [DecidableEq m] - {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℂ) : - Commute A (matrixFunction f A hA) := by - have hlhs : A * matrixFunction f A hA = - matrixFunction (fun x => (x : ℂ) * f x) A hA := by - have := matrixFunction_mul hA (fun x => (x : ℂ)) f - rwa [matrixFunction_id] at this - have hrhs : matrixFunction f A hA * A = - matrixFunction (fun x => f x * (x : ℂ)) A hA := by - have := matrixFunction_mul hA f (fun x => (x : ℂ)) - rwa [matrixFunction_id] at this - change A * matrixFunction f A hA = matrixFunction f A hA * A - rw [hlhs, hrhs] - congr 1; ext x; ring - -/-- The product A · f(A) is Hermitian when A is Hermitian and f : ℝ → ℝ. -Since A and f(A) share the same eigenbasis, they commute; both are Hermitian, -so their product is Hermitian by `IsHermitian.commute_iff`. -/ -lemma mul_matrixFunction_isHermitian {m : Type*} [Fintype m] [DecidableEq m] +/-- The product `A · f(A)` is Hermitian for Hermitian `A` and real `f`. -/ +lemma mul_cfc_isHermitian {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.IsHermitian) (f : ℝ → ℝ) : - (A * matrixFunction (fun x => (f x : ℂ)) A hA).IsHermitian := - (hA.commute_iff (matrixFunction_isHermitian hA f)).mp - (commute_matrixFunction_self hA _) + (A * cfc f A).IsHermitian := by + have hsa : IsSelfAdjoint A := hA + have hcomm : Commute A (cfc f A) := (hsa.commute_cfc (Commute.refl A) f).symm + exact (hA.commute_iff (cfc_isHermitian hA f)).mp hcomm /-- The trace of a Hermitian matrix is real: casting its real part back to ℂ recovers the trace. Proof: Aᴴ = A implies star(Tr A) = Tr(Aᴴ) = Tr A, so Tr A is self-adjoint, @@ -424,29 +184,22 @@ lemma IsHermitian.trace_ofReal_re {m : Type*} [Fintype m] rw [← trace_conjTranspose, hA.eq] exact (RCLike.conj_eq_iff_re (K := ℂ)).mp h -/-- Matrix logarithm for positive definite matrices via spectral decomposition. -/ -noncomputable def matrixLog {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : Matrix m m ℂ := - matrixFunction (fun x => Real.log x) A hA - -/-- `matrixLog` expands into the spectral decomposition attached to the chosen -Hermitian proof. -/ -lemma matrixLog_spectral_eq {m : Type*} [Fintype m] [DecidableEq m] +/-- `cfc Real.log` of a Hermitian matrix (the matrix logarithm) expands into the spectral +decomposition attached to the chosen Hermitian proof. -/ +lemma cfc_log_spectral_eq {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.IsHermitian) : - matrixLog A hA = + cfc Real.log A = (hA.eigenvectorUnitary : Matrix m m ℂ) * diagonal (fun i => ((Real.log (hA.eigenvalues i) : ℝ) : ℂ)) * - (hA.eigenvectorUnitary : Matrix m m ℂ)ᴴ := by - unfold matrixLog matrixFunction - rfl + (hA.eigenvectorUnitary : Matrix m m ℂ)ᴴ := + cfc_spectral_eq hA Real.log -/-- The matrix logarithm commutes with any `*-`algebra equivalence between complex matrix -algebras on PosDef matrices. Continuity is automatic in finite dimensions. -/ -theorem matrixLog_map_starAlgEquiv {m n : Type*} [Fintype m] [DecidableEq m] +/-- The matrix logarithm `cfc Real.log` commutes with any `*-`algebra equivalence between +complex matrix algebras on PosDef matrices. Continuity is automatic in finite dimensions. -/ +theorem cfc_log_map_starAlgEquiv {m n : Type*} [Fintype m] [DecidableEq m] [Fintype n] [DecidableEq n] {M : Matrix m m ℂ} (hM : M.PosDef) (φ : Matrix m m ℂ ≃⋆ₐ[ℂ] Matrix n n ℂ) : - matrixLog (φ M) ((hM.posSemidef.map_starAlgEquiv φ).isHermitian) = - φ (matrixLog M hM.1) := by + cfc Real.log (φ M) = φ (cfc Real.log M) := by letI : NormedRing (Matrix m m ℂ) := Matrix.linftyOpNormedRing letI : NormedAlgebra ℝ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra letI : NormedAlgebra ℂ (Matrix m m ℂ) := Matrix.linftyOpNormedAlgebra @@ -457,8 +210,6 @@ theorem matrixLog_map_starAlgEquiv {m n : Type*} [Fintype m] [DecidableEq m] letI : NormedAlgebra ℂ (Matrix n n ℂ) := Matrix.linftyOpNormedAlgebra letI : CStarAlgebra (Matrix n n ℂ) := by simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := n) (A := ℂ) - unfold matrixLog - rw [matrixFunction_eq_cfc, matrixFunction_eq_cfc] -- View `φ` as an ℝ-`StarAlgHom` to apply `StarAlgHomClass.map_cfc`. let ψ : Matrix m m ℂ →⋆ₐ[ℝ] Matrix n n ℂ := { toAlgHom := (φ.toAlgEquiv.restrictScalars ℝ).toAlgHom @@ -493,24 +244,30 @@ theorem matrixLog_map_starAlgEquiv {m n : Type*} [Fintype m] [DecidableEq m] rw [h_ψ_apply, h_ψ_apply] at h_map exact h_map.symm -/-- Matrix inverse square root via functional calculus for PD matrices. -/ +/-- Matrix inverse square root via the continuous functional calculus for PD matrices. -/ noncomputable def matrixInvSqrt {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.PosDef) : Matrix m m ℂ := - matrixFunction (fun x => (Real.rpow x (-1 / 2 : ℝ) : ℂ)) A hA.1 + (A : Matrix m m ℂ) (_hA : A.PosDef) : Matrix m m ℂ := + cfc (fun x => Real.rpow x (-1 / 2 : ℝ)) A + +/-- `matrixInvSqrt A = A ^ (-1/2)` via `CFC.rpow`. -/ +lemma matrixInvSqrt_eq_rpow {m : Type*} [Fintype m] [DecidableEq m] + {A : Matrix m m ℂ} (hA : A.PosDef) : + matrixInvSqrt A hA = A ^ (-1 / 2 : ℝ) := + (CFC.rpow_eq_cfc_real (a := A) (ha := by rw [Matrix.le_iff, sub_zero]; exact hA.posSemidef)).symm /-- The matrix inverse square root of a PD matrix is Hermitian. -/ lemma matrixInvSqrt_isHermitian {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosDef) : (matrixInvSqrt A hA).IsHermitian := by - unfold matrixInvSqrt - exact matrixFunction_isHermitian hA.1 (fun x => Real.rpow x (-1 / 2 : ℝ)) + rw [matrixInvSqrt] + exact cfc_isHermitian hA.1 (fun x => Real.rpow x (-1 / 2 : ℝ)) /-- For a positive definite matrix `A`, `A^{-1/2} * A * A^{-1/2} = I`. -/ lemma matrixInvSqrt_mul_self {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosDef) : matrixInvSqrt A hA * A * matrixInvSqrt A hA = 1 := by have hS : matrixInvSqrt A hA = A ^ (-1 / 2 : ℝ) := by - simpa [matrixInvSqrt] using (matrixFunction_rpow_eq hA.posSemidef (-1 / 2 : ℝ)) + exact matrixInvSqrt_eq_rpow hA have hAunit : IsUnit A := hA.isUnit have hnonneg : 0 ≤ A := by simpa [Matrix.le_iff] using hA.posSemidef @@ -534,17 +291,23 @@ lemma matrixInvSqrt_mul_self {m : Type*} [Fintype m] [DecidableEq m] ring_nf simpa using (CFC.rpow_zero (a := A) hnonneg) -/-- Matrix square root via functional calculus for PSD matrices. -/ +/-- Matrix square root via the continuous functional calculus for PSD matrices. -/ noncomputable def matrixSqrt {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.PosSemidef) : Matrix m m ℂ := - matrixFunction (fun x => (Real.rpow x (1 / 2 : ℝ) : ℂ)) A hA.1 + (A : Matrix m m ℂ) (_hA : A.PosSemidef) : Matrix m m ℂ := + cfc (fun x => Real.rpow x (1 / 2 : ℝ)) A + +/-- `matrixSqrt A = A ^ (1/2)` via `CFC.rpow`. -/ +lemma matrixSqrt_eq_rpow {m : Type*} [Fintype m] [DecidableEq m] + {A : Matrix m m ℂ} (hA : A.PosSemidef) : + matrixSqrt A hA = A ^ (1 / 2 : ℝ) := + (CFC.rpow_eq_cfc_real (a := A) (ha := by rw [Matrix.le_iff, sub_zero]; exact hA)).symm /-- The matrix square root of a PSD matrix is Hermitian. -/ lemma matrixSqrt_isHermitian {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosSemidef) : (matrixSqrt A hA).IsHermitian := by - unfold matrixSqrt - exact matrixFunction_isHermitian hA.1 (fun x => Real.rpow x (1 / 2 : ℝ)) + rw [matrixSqrt] + exact cfc_isHermitian hA.1 (fun x => Real.rpow x (1 / 2 : ℝ)) /-- For a positive semidefinite matrix `A`, `A^{1/2} * A^{1/2} = A`. -/ lemma matrixSqrt_mul_self_posSemidef {m : Type*} [Fintype m] [DecidableEq m] @@ -552,7 +315,7 @@ lemma matrixSqrt_mul_self_posSemidef {m : Type*} [Fintype m] [DecidableEq m] matrixSqrt A hA * matrixSqrt A hA = A := by classical -- Use the spectral decomposition and diagonal computation. - unfold matrixSqrt matrixFunction + rw [matrixSqrt, cfc_spectral_eq hA.1 (fun x => Real.rpow x (1 / 2 : ℝ))] set U : Matrix m m ℂ := (hA.1.eigenvectorUnitary : Matrix m m ℂ) set D : Matrix m m ℂ := diagonal (fun i => (Real.rpow (hA.1.eigenvalues i) (1 / 2 : ℝ) : ℂ)) @@ -585,7 +348,7 @@ lemma matrixSqrt_mul_self {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosDef) : matrixSqrt A hA.posSemidef * matrixSqrt A hA.posSemidef = A := by have hS : matrixSqrt A hA.posSemidef = A ^ (1 / 2 : ℝ) := by - simpa [matrixSqrt] using (matrixFunction_rpow_eq hA.posSemidef (1 / 2 : ℝ)) + exact matrixSqrt_eq_rpow hA.posSemidef have hAunit : IsUnit A := hA.isUnit calc matrixSqrt A hA.posSemidef * matrixSqrt A hA.posSemidef = @@ -605,9 +368,9 @@ lemma matrixSqrt_mul_matrixInvSqrt {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosDef) : matrixSqrt A hA.posSemidef * matrixInvSqrt A hA = 1 := by have hS : matrixSqrt A hA.posSemidef = A ^ (1 / 2 : ℝ) := by - simpa [matrixSqrt] using (matrixFunction_rpow_eq hA.posSemidef (1 / 2 : ℝ)) + exact matrixSqrt_eq_rpow hA.posSemidef have hSi : matrixInvSqrt A hA = A ^ (-1 / 2 : ℝ) := by - simpa [matrixInvSqrt] using (matrixFunction_rpow_eq hA.posSemidef (-1 / 2 : ℝ)) + exact matrixInvSqrt_eq_rpow hA have hAunit : IsUnit A := hA.isUnit have hnonneg : 0 ≤ A := by simpa [Matrix.le_iff] using hA.posSemidef @@ -627,9 +390,9 @@ lemma matrixInvSqrt_mul_matrixSqrt {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosDef) : matrixInvSqrt A hA * matrixSqrt A hA.posSemidef = 1 := by have hS : matrixSqrt A hA.posSemidef = A ^ (1 / 2 : ℝ) := by - simpa [matrixSqrt] using (matrixFunction_rpow_eq hA.posSemidef (1 / 2 : ℝ)) + exact matrixSqrt_eq_rpow hA.posSemidef have hSi : matrixInvSqrt A hA = A ^ (-1 / 2 : ℝ) := by - simpa [matrixInvSqrt] using (matrixFunction_rpow_eq hA.posSemidef (-1 / 2 : ℝ)) + exact matrixInvSqrt_eq_rpow hA have hAunit : IsUnit A := hA.isUnit have hnonneg : 0 ≤ A := by simpa [Matrix.le_iff] using hA.posSemidef @@ -646,7 +409,7 @@ lemma matrixInvSqrt_mul_matrixSqrt {m : Type*} [Fintype m] [DecidableEq m] /-- For commuting PSD L and PD R, matrixInvSqrt R commutes with L. This follows from the fact that L commutes with R, and CFC (hence rpow) preserves -commutativity. Since matrixInvSqrt R = R^{-1/2} (by matrixFunction_rpow_eq), and +commutativity. Since matrixInvSqrt R = R^{-1/2} (by CFC.rpow), and Commute.cfc_real gives that cfc g R commutes with L when L commutes with R, the result follows. -/ lemma matrixInvSqrt_commute_of_commute {n : Type*} [Fintype n] [DecidableEq n] @@ -658,8 +421,7 @@ lemma matrixInvSqrt_commute_of_commute {n : Type*} [Fintype n] [DecidableEq n] letI : NormedAlgebra ℂ (Matrix n n ℂ) := Matrix.linftyOpNormedAlgebra letI : CStarAlgebra (Matrix n n ℂ) := by simpa [CStarMatrix] using CStarMatrix.instCStarAlgebra (n := n) (A := ℂ) - have hRinv_eq : matrixInvSqrt R hR = R ^ (-1 / 2 : ℝ) := by - simpa [matrixInvSqrt] using matrixFunction_rpow_eq hR.posSemidef (-1 / 2 : ℝ) + have hRinv_eq : matrixInvSqrt R hR = R ^ (-1 / 2 : ℝ) := matrixInvSqrt_eq_rpow hR rw [hRinv_eq] -- R^{-1/2} = cfc(x^{-1/2}, R), so it commutes with L since L commutes with R have hR0 : (0 : Matrix n n ℂ) ≤ R := by simpa [Matrix.le_iff] using hR.posSemidef @@ -667,35 +429,6 @@ lemma matrixInvSqrt_commute_of_commute {n : Type*} [Fintype n] [DecidableEq n] have hcommute : Commute R L := hcomm.symm exact Commute.cfc_real hcommute _ -/-- At p = 0: `matrixFunction (fun x => x ^ 0) A = I`. -/ -lemma matrixFunction_cpow_zero {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : - matrixFunction (fun x => x ^ (0 : ℂ)) A hA = 1 := by - unfold matrixFunction - have h_pow : (fun i => ((hA.eigenvalues i : ℝ) : ℂ) ^ (0 : ℂ)) = (fun _ => 1) := by - ext i - simp [Complex.cpow_zero] - simp only [h_pow, Matrix.diagonal_one, Matrix.mul_one] - have h := Unitary.coe_mul_star_self hA.eigenvectorUnitary - simp only [Unitary.coe_star, star_eq_conjTranspose] at h - exact h - -/-- `matrixFunction (fun x => x ^ 1) A = A`. -/ -lemma matrixFunction_cpow_one {m : Type*} [Fintype m] [DecidableEq m] - (A : Matrix m m ℂ) (hA : A.IsHermitian) : - matrixFunction (fun x => x ^ (1 : ℂ)) A hA = A := by - unfold matrixFunction - have h_pow : (fun i => ((hA.eigenvalues i : ℝ) : ℂ) ^ (1 : ℂ)) = - (fun i => ((hA.eigenvalues i : ℝ) : ℂ)) := by - ext i - simp [Complex.cpow_one] - have h_diag : diagonal (fun i => ((hA.eigenvalues i : ℝ) : ℂ)) = - diagonal (RCLike.ofReal ∘ hA.eigenvalues) := rfl - simp only [h_pow, h_diag] - have h_spec := hA.spectral_theorem - rw [Unitary.conjStarAlgAut_apply, star_eq_conjTranspose] at h_spec - exact h_spec.symm - /-- CFC commutes with unitary conjugation using `Unitary.conjStarAlgAut`. -/ lemma cfc_unitary_conjugation' {m : Type*} [Fintype m] [DecidableEq m] (U : unitary (Matrix m m ℂ)) (M : Matrix m m ℂ) @@ -869,7 +602,7 @@ lemma compression_pow_eq {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [ _ = Vᴴ * M ^ k * V * (Vᴴ * M * V) := by simp only [Matrix.mul_assoc] _ = (Vᴴ * M * V) ^ k * (Vᴴ * M * V) := by rw [ih] --- Helper: matrixFunction f M can be expressed as a polynomial in M +-- Helper: cfc f M can be expressed as a polynomial in M -- (specifically, the Lagrange interpolant at the eigenvalues). -- Hence V†f(M)V = f(V†MV) when V†M^kV = (V†MV)^k. @@ -983,14 +716,15 @@ lemma eigenvalues_compression_subset {n m : Type*} use j exact Complex.ofReal_injective hr -lemma matrixFunction_compression_of_commuting {n m : Type*} +/-- Compression commutes with the continuous functional calculus when `Vᴴ V = 1` and `M` +commutes with `V Vᴴ`: `Vᴴ · f(M) · V = f(Vᴴ M V)`. -/ +lemma cfc_compression_of_commuting {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] (V : Matrix n m ℂ) (M : Matrix n n ℂ) (hM : M.IsHermitian) (hVV : Vᴴ * V = (1 : Matrix m m ℂ)) (hcomm : M * (V * Vᴴ) = V * Vᴴ * M) (f : ℝ → ℝ) (hVM : (Vᴴ * M * V).IsHermitian) : - Vᴴ * matrixFunction (fun x => (f x : ℂ)) M hM * V = - matrixFunction (fun x => (f x : ℂ)) (Vᴴ * M * V) hVM := by + Vᴴ * cfc f M * V = cfc f (Vᴴ * M * V) := by classical -- The key insight: eigenvalues of V†MV are among eigenvalues of M have h_eig_subset := eigenvalues_compression_subset V M hM hVV hcomm hVM @@ -1032,11 +766,6 @@ lemma matrixFunction_compression_of_commuting {n m : Type*} rw [h1, ← Polynomial.aeval_def, Polynomial.aeval_algebraMap_apply_eq_algebraMap_eval, hp_interp_VM i] rfl - unfold matrixFunction - have h_mf_M_eq_cfc : matrixFunction (fun x => (f x : ℂ)) M hM = cfc f M := - matrixFunction_eq_cfc hM f - have h_mf_VM_eq_cfc : matrixFunction (fun x => (f x : ℂ)) (Vᴴ * M * V) hVM = cfc f (Vᴴ * M * V) := - matrixFunction_eq_cfc hVM f have h_cfc_M : cfc f M = hM.cfc f := Matrix.IsHermitian.cfc_eq hM f have h_cfc_VM : cfc f (Vᴴ * M * V) = hVM.cfc f := Matrix.IsHermitian.cfc_eq hVM f have h_cfc_f_eq_p_M : hM.cfc f = hM.cfc (fun x => p.eval x) := by @@ -1072,9 +801,8 @@ lemma matrixFunction_compression_of_commuting {n m : Type*} simp only [p_complex, Polynomial.aeval_map_algebraMap] rw [h1, h2] exact compression_aeval_eq V M hVV hcomm p_complex - calc Vᴴ * matrixFunction (fun x => (f x : ℂ)) M hM * V - = Vᴴ * cfc f M * V := by rw [h_mf_M_eq_cfc] - _ = Vᴴ * hM.cfc f * V := by rw [h_cfc_M] + calc Vᴴ * cfc f M * V + = Vᴴ * hM.cfc f * V := by rw [h_cfc_M] _ = Vᴴ * hM.cfc (fun x => p.eval x) * V := by rw [h_cfc_f_eq_p_M] _ = Vᴴ * cfc (fun x => p.eval x) M * V := by rw [← Matrix.IsHermitian.cfc_eq hM] _ = Vᴴ * Polynomial.aeval M p * V := by rw [h_cfc_p_eq_aeval_M] @@ -1083,11 +811,10 @@ lemma matrixFunction_compression_of_commuting {n m : Type*} _ = hVM.cfc (fun x => p.eval x) := by rw [Matrix.IsHermitian.cfc_eq hVM] _ = hVM.cfc f := by rw [← h_cfc_f_eq_p_VM] _ = cfc f (Vᴴ * M * V) := by rw [← h_cfc_VM] - _ = matrixFunction (fun x => (f x : ℂ)) (Vᴴ * M * V) hVM := by rw [← h_mf_VM_eq_cfc] /-- For an isometry V (V†V = I), PSD A, and s > 0: (VAV†)^s = V A^s V†. -**Proof**: Uses `matrixFunction_compression_of_commuting` to get V†(VAV†)^s V = A^s, +**Proof**: Uses `cfc_compression_of_commuting` to get V†(VAV†)^s V = A^s, then shows (VAV†)^s annihilates the complement (1 - VV†) via kernel preservation. -/ lemma rpow_conj_isometry {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] @@ -1116,14 +843,11 @@ lemma rpow_conj_isometry {n m : Type*} [Fintype n] [Fintype m] -- Step 3: V†(M^s)V = A^s have hVM_herm : (Vᴴ * M * V).IsHermitian := by rw [hstep1]; exact hA.1 have hVMA_rpow : Vᴴ * (M ^ s) * V = A ^ s := by - have h1 := matrixFunction_rpow_eq hM_psd s - have h2 := matrixFunction_compression_of_commuting V M hM_psd.1 hV hcomm (· ^ s) hVM_herm - rw [h1] at h2 - rw [h2] - have h3 : matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) (Vᴴ * M * V) hVM_herm = - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) A hA.1 := by - congr 1 - rw [h3, matrixFunction_rpow_eq hA] + have hM0 : (0 : Matrix m m ℂ) ≤ M := by rw [Matrix.le_iff, sub_zero]; exact hM_psd + have hA0 : (0 : Matrix n n ℂ) ≤ A := by rw [Matrix.le_iff, sub_zero]; exact hA + rw [CFC.rpow_eq_cfc_real (a := M) (ha := hM0), + cfc_compression_of_commuting V M hM_psd.1 hV hcomm (fun x : ℝ => x ^ s) hVM_herm, + hstep1, ← CFC.rpow_eq_cfc_real (a := A) (ha := hA0)] -- Step 4: M * (1 - P) = 0 have hM_annihilate : M * (1 - P) = 0 := by rw [mul_sub, mul_one, hM_def, hP_def, @@ -1199,8 +923,8 @@ lemma rpow_conj_isometry {n m : Type*} [Fintype n] [Fintype m] have hP_herm : Pᴴ = P := by simp [hP_def, Matrix.conjTranspose_mul, conjTranspose_conjTranspose] have hMs_herm : (M ^ s).IsHermitian := by - rw [← matrixFunction_rpow_eq hM_psd] - exact matrixFunction_isHermitian hM_psd.1 (· ^ s) + rw [CFC.rpow_eq_cfc_real (a := M) (ha := by rw [Matrix.le_iff, sub_zero]; exact hM_psd)] + exact cfc_isHermitian hM_psd.1 (fun x : ℝ => x ^ s) -- M^s = M^s * P (from M^s*(1-P)=0) have hMsP_eq : M ^ s = M ^ s * P := by have h := hMs_annihilate @@ -1252,8 +976,8 @@ lemma spectral_expand (A : Matrix n n ℂ) (hA : A.IsHermitian) : A = (hA.eigenvectorUnitary : Matrix n n ℂ) * diagonal (fun i => (hA.eigenvalues i : ℂ)) * (hA.eigenvectorUnitary : Matrix n n ℂ)ᴴ := by - have h := (matrixFunction_id hA).symm - unfold matrixFunction at h + have h := hA.spectral_theorem + rw [Unitary.conjStarAlgAut_apply, star_eq_conjTranspose] at h simpa [Function.comp] using h /-- The j-th column of the eigenvector unitary satisfies the eigenvalue equation: diff --git a/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean b/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean new file mode 100644 index 0000000..b4d8336 --- /dev/null +++ b/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean @@ -0,0 +1,84 @@ +module + +public import QuantumSystem.Analysis.Entropy.KroneckerProduct +public import QuantumSystem.Analysis.Matrix.PartialTrace + +/-! +# LocalNet bridge: restriction as an equivalence-indexed partial trace + +These lemmas identify the `LocalNet` restriction `Matrix.restrict` with the equivalence-indexed +partial trace `Matrix.partialTrace` of the reindexed matrix induced by `LocalNet.combineIdx`. +They are factored out of `Analysis/Entropy/KroneckerProduct.lean` so that the Kronecker-product +and product-type partial-trace API there stays `LocalNet`-free. +-/ + +@[expose] public section + +namespace Matrix + +open scoped Kronecker MatrixOrder ComplexOrder + +/-! ### LocalNet bridge + +These lemmas identify `Matrix.restrict` on a `LocalNet` with the equivalence-indexed +partial trace of the reindexed matrix induced by `LocalNet.combineIdx`. -/ + +section LocalNetBridge + +variable {L : LocalNet} + +/-- Combining via `h : Λ ⊆ Λ_total` agrees with combining via the complementary split, +after transporting the remaining factor along `Λ_total \ (Λ_total \ Λ) = Λ`. -/ +private lemma combineIdx_swap_apply + {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (x : L.regionIdx Λ) (y : L.regionIdx (Λ_total \ Λ)) : + L.combineIdx h (x, y) = + L.combineIdx Finset.sdiff_subset + (y, L.regionIdxCongr (sdiff_sdiff_eq_self h).symm x) := by + have h_eq : Λ_total \ (Λ_total \ Λ) = Λ := sdiff_sdiff_eq_self h + funext ⟨s, hs⟩ + by_cases hsΛ : s ∈ Λ + · have hns_compl : s ∉ Λ_total \ Λ := fun h_in => (Finset.mem_sdiff.mp h_in).2 hsΛ + have hs_recast : s ∈ Λ_total \ (Λ_total \ Λ) := by + rw [h_eq] + exact hsΛ + rw [LocalNet.combineIdx_apply_mem h _ _ ⟨s, hs⟩ hsΛ, + LocalNet.combineIdx_apply_not_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hns_compl, + LocalNet.regionIdxCongr_apply (L := L) h_eq.symm x hsΛ hs_recast] + · have hs_compl : s ∈ Λ_total \ Λ := Finset.mem_sdiff.mpr ⟨hs, hsΛ⟩ + rw [LocalNet.combineIdx_apply_not_mem h _ _ ⟨s, hs⟩ hsΛ, + LocalNet.combineIdx_apply_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hs_compl] + +/-- Restriction to `Λ` equals the partial trace of the reindexed matrix induced by +`combineIdx h`, retaining the `Λ` factor. -/ +theorem restrict_eq_partialTrace_combineIdx + {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (ρ : L.localAlgebra Λ_total) (x x' : L.regionIdx Λ) : + Matrix.restrict h ρ x x' = + Matrix.partialTrace + (A := L.regionIdx Λ) (B := L.regionIdx (Λ_total \ Λ)) + (Equiv.refl (L.regionIdx Λ × L.regionIdx (Λ_total \ Λ))) + (ρ.submatrix (L.combineIdx h) (L.combineIdx h)) x x' := by + rw [Matrix.partialTrace_refl_apply, Matrix.restrict_apply] + simp [Matrix.submatrix_apply] + +/-- Restriction to the complement of `Λ` equals the partial trace of the reindexed matrix +induced by `combineIdx h`, retaining the complementary factor. -/ +theorem restrict_compl_eq_partialTrace_combineIdx + {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (ρ : L.localAlgebra Λ_total) (y y' : L.regionIdx (Λ_total \ Λ)) : + Matrix.restrict Finset.sdiff_subset ρ y y' = + Matrix.partialTrace + (A := L.regionIdx (Λ_total \ Λ)) (B := L.regionIdx Λ) + (Equiv.prodComm (L.regionIdx Λ) (L.regionIdx (Λ_total \ Λ))) + (ρ.submatrix (L.combineIdx h) (L.combineIdx h)) y y' := by + rw [Matrix.partialTrace_prodComm_apply, Matrix.restrict_apply] + rw [← (L.regionIdxCongr (sdiff_sdiff_eq_self h).symm).sum_comp + (fun z => ρ (L.combineIdx Finset.sdiff_subset (y, z)) + (L.combineIdx Finset.sdiff_subset (y', z)))] + refine Finset.sum_congr rfl fun x _ => ?_ + rw [Matrix.submatrix_apply, combineIdx_swap_apply h x y, combineIdx_swap_apply h x y'] + +end LocalNetBridge + +end Matrix diff --git a/QuantumSystem/Analysis/Matrix/LiebConcavity.lean b/QuantumSystem/Analysis/Matrix/LiebConcavity.lean index 46b111b..da15b26 100644 --- a/QuantumSystem/Analysis/Matrix/LiebConcavity.lean +++ b/QuantumSystem/Analysis/Matrix/LiebConcavity.lean @@ -95,11 +95,11 @@ private lemma hsInnerProduct_leftMul_rightMul {m : Type*} [Fintype m] [Decidable -- (A^p * K† * B^{1-p})† = B^{1-p}† * K * (A^p)† -- Since A^p and B^{1-p} are Hermitian (rpow of PSD is PSD hence Hermitian): have hAp_herm : (A ^ p)ᴴ = A ^ p := by - rw [← matrixFunction_rpow_eq hA p] - exact matrixFunction_isHermitian hA.1 (fun x => x ^ p) + rw [CFC.rpow_eq_cfc_real (a := A) (ha := by rw [Matrix.le_iff, sub_zero]; exact hA)] + exact cfc_isHermitian hA.1 (fun x => x ^ p) have hBp_herm : (B ^ (1 - p))ᴴ = B ^ (1 - p) := by - rw [← matrixFunction_rpow_eq hB (1 - p)] - exact matrixFunction_isHermitian hB.1 (fun x => x ^ (1 - p)) + rw [CFC.rpow_eq_cfc_real (a := B) (ha := by rw [Matrix.le_iff, sub_zero]; exact hB)] + exact cfc_isHermitian hB.1 (fun x => x ^ (1 - p)) simp only [Matrix.conjTranspose_mul, Matrix.conjTranspose_conjTranspose, hAp_herm, hBp_herm, Matrix.mul_assoc] -- LHS: Tr(B^{1-p} * K * A^p * K†), RHS: Tr(A^p * K† * B^{1-p} * K) @@ -369,14 +369,14 @@ private lemma rpow_tendsto_smul_one {m : Type*} [Fintype m] [DecidableEq m] Filter.Tendsto (fun ε : ℝ => (A + (ε : ℂ) • (1 : Matrix m m ℂ)) ^ p) (nhdsWithin 0 (Set.Ioi 0)) (nhds (A ^ p)) := by -- Express A^p and (A + ε•1)^p via the continuous functional calculus. - -- Using matrixFunction and cfc, reduce to pointwise convergence of x^p as ε → 0+. - have hA_eq : A ^ p = cfc (fun x : ℝ => x ^ p) A := by - rw [← matrixFunction_rpow_eq hA, matrixFunction_eq_cfc hA.1] + -- Using cfc, reduce to pointwise convergence of x^p as ε → 0+. + have hA_eq : A ^ p = cfc (fun x : ℝ => x ^ p) A := + CFC.rpow_eq_cfc_real (a := A) (ha := by rw [Matrix.le_iff, sub_zero]; exact hA) have hshift_eq : ∀ ε : ℝ, 0 < ε → (A + (ε : ℂ) • (1 : Matrix m m ℂ)) ^ p = cfc (fun x : ℝ => (x + ε) ^ p) A := by intro ε hε - have hcfc_shift : cfc (fun x : ℝ => x + ε) A = A + (ε : ℂ) • (1 : Matrix m m ℂ) := by - rw [← matrixFunction_eq_cfc hA.1]; exact matrixFunction_add_const hA.1 ε + have hcfc_shift : cfc (fun x : ℝ => x + ε) A = A + (ε : ℂ) • (1 : Matrix m m ℂ) := + cfc_add_const_eq hA.1 ε have hcont_p : ContinuousOn (fun x : ℝ => x ^ p) ((fun x : ℝ => x + ε) '' spectrum ℝ A) := by apply ContinuousOn.rpow_const continuousOn_id rintro x ⟨_, hy_spec, rfl⟩ diff --git a/QuantumSystem/Analysis/Matrix/Order.lean b/QuantumSystem/Analysis/Matrix/Order.lean index b9d1502..a307355 100644 --- a/QuantumSystem/Analysis/Matrix/Order.lean +++ b/QuantumSystem/Analysis/Matrix/Order.lean @@ -49,33 +49,33 @@ open scoped MatrixOrder ComplexOrder NNReal A ≤ B (in the Löwner order) implies f(A) ≤ f(B). -/ def IsLownerMonotone (f : ℝ → ℝ) : Prop := ∀ (m : Type*) [Fintype m] [DecidableEq m] - (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef), + (A B : Matrix m m ℂ) (_hA : A.PosSemidef) (_hB : B.PosSemidef), A ≤ B → - let fA := matrixFunction (fun x => (f x : ℂ)) A hA.1 - let fB := matrixFunction (fun x => (f x : ℂ)) B hB.1 + let fA := cfc f A + let fB := cfc f B fA ≤ fB /-- A real function f is Löwner convex if f(tA + (1-t)B) ≤ t · f(A) + (1-t) · f(B) in the Löwner order for all t ∈ [0,1]. -/ def IsLownerConvex (f : ℝ → ℝ) : Prop := ∀ (m : Type*) [Fintype m] [DecidableEq m] - (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef) (t : ℝ), + (A B : Matrix m m ℂ) (_hA : A.PosSemidef) (_hB : B.PosSemidef) (t : ℝ), 0 ≤ t → t ≤ 1 → - ∀ (hC : (t • A + (1 - t) • B).IsHermitian), - let fA := matrixFunction (fun x => (f x : ℂ)) A hA.1 - let fB := matrixFunction (fun x => (f x : ℂ)) B hB.1 - let fC := matrixFunction (fun x => (f x : ℂ)) (t • A + (1 - t) • B) hC + ∀ (_hC : (t • A + (1 - t) • B).IsHermitian), + let fA := cfc f A + let fB := cfc f B + let fC := cfc f (t • A + (1 - t) • B) fC ≤ t • fA + (1 - t) • fB /-- A real function f is Löwner concave if −f is Löwner convex. -/ def IsLownerConcave (f : ℝ → ℝ) : Prop := ∀ (m : Type*) [Fintype m] [DecidableEq m] - (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef) (t : ℝ), + (A B : Matrix m m ℂ) (_hA : A.PosSemidef) (_hB : B.PosSemidef) (t : ℝ), 0 ≤ t → t ≤ 1 → - ∀ (hC : (t • A + (1 - t) • B).IsHermitian), - let fA := matrixFunction (fun x => Complex.ofReal (-f x)) A hA.1 - let fB := matrixFunction (fun x => Complex.ofReal (-f x)) B hB.1 - let fC := matrixFunction (fun x => Complex.ofReal (-f x)) (t • A + (1 - t) • B) hC + ∀ (_hC : (t • A + (1 - t) • B).IsHermitian), + let fA := cfc (fun x => -f x) A + let fB := cfc (fun x => -f x) B + let fC := cfc (fun x => -f x) (t • A + (1 - t) • B) fC ≤ t • fA + (1 - t) • fB /-- Jensen convexity (HPJ sense): compression inequality for two terms. @@ -84,24 +84,24 @@ f(A† T₁ A + B† T₂ B) ≤ A† f(T₁) A + B† f(T₂) B. -/ def IsJensenConvex (f : ℝ → ℝ) : Prop := ∀ (m : Type*) [Fintype m] [DecidableEq m] (A B T₁ T₂ : Matrix m m ℂ) - (hT₁ : T₁.PosSemidef) (hT₂ : T₂.PosSemidef) + (_hT₁ : T₁.PosSemidef) (_hT₂ : T₂.PosSemidef) (_hAB : Aᴴ * A + Bᴴ * B ≤ (1 : Matrix m m ℂ)) - (hC : (Aᴴ * T₁ * A + Bᴴ * T₂ * B).IsHermitian), - let fT₁ := matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 - let fT₂ := matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 - let fC := matrixFunction (fun x => (f x : ℂ)) (Aᴴ * T₁ * A + Bᴴ * T₂ * B) hC + (_hC : (Aᴴ * T₁ * A + Bᴴ * T₂ * B).IsHermitian), + let fT₁ := cfc f T₁ + let fT₂ := cfc f T₂ + let fC := cfc f (Aᴴ * T₁ * A + Bᴴ * T₂ * B) fC ≤ Aᴴ * fT₁ * A + Bᴴ * fT₂ * B /-- Jensen concavity in the HPJ sense: −f is Jensen convex. -/ def IsJensenConcave (f : ℝ → ℝ) : Prop := ∀ (m : Type*) [Fintype m] [DecidableEq m] (A B T₁ T₂ : Matrix m m ℂ) - (hT₁ : T₁.PosSemidef) (hT₂ : T₂.PosSemidef) + (_hT₁ : T₁.PosSemidef) (_hT₂ : T₂.PosSemidef) (_hAB : Aᴴ * A + Bᴴ * B ≤ (1 : Matrix m m ℂ)) - (hC : (Aᴴ * T₁ * A + Bᴴ * T₂ * B).IsHermitian), - let fT₁ := matrixFunction (fun x => Complex.ofReal (-f x)) T₁ hT₁.1 - let fT₂ := matrixFunction (fun x => Complex.ofReal (-f x)) T₂ hT₂.1 - let fC := matrixFunction (fun x => Complex.ofReal (-f x)) (Aᴴ * T₁ * A + Bᴴ * T₂ * B) hC + (_hC : (Aᴴ * T₁ * A + Bᴴ * T₂ * B).IsHermitian), + let fT₁ := cfc (fun x => -f x) T₁ + let fT₂ := cfc (fun x => -f x) T₂ + let fC := cfc (fun x => -f x) (Aᴴ * T₁ * A + Bᴴ * T₂ * B) fC ≤ Aᴴ * fT₁ * A + Bᴴ * fT₂ * B /-- Block diagonal matrix is positive semidefinite if blocks are positive semidefinite. -/ @@ -156,9 +156,7 @@ lemma lownerConvex_compression_le.{v} {n : Type v} {m : Type v} [Fintype n] [Fin {f : ℝ → ℝ} (hconv : IsLownerConvex.{v} f) (hf0 : f 0 ≤ 0) (V : Matrix n m ℂ) (hVV : Vᴴ * V ≤ 1) (T : Matrix n n ℂ) (hT : T.PosSemidef) : - matrixFunction (fun x => (f x : ℂ)) (Vᴴ * T * V) - (isHermitian_conjTranspose_mul_mul (B := V) (A := T) hT.1) ≤ - Vᴴ * matrixFunction (fun x => (f x : ℂ)) T hT.1 * V := by + cfc f (Vᴴ * T * V) ≤ Vᴴ * cfc f T * V := by -- The proof uses the defect technique and the block diagonal CFC formula. classical -- Step 1: Setup the defect matrix D = √(I - V†V) @@ -191,9 +189,6 @@ lemma lownerConvex_compression_le.{v} {n : Type v} {m : Type v} [Fintype n] [Fin simp only [W, T'] at h ⊢ rw [h] simp only [Matrix.mul_zero, Matrix.zero_mul, add_zero] - -- Step 5: Relate matrixFunction to CFC - have hfT_eq : matrixFunction (fun x => (f x : ℂ)) T hT.1 = cfc f T := - matrixFunction_eq_cfc hT.1 f -- Step 6-7: W†f(T')W = V†f(T)V + f(0)·D†D have hWfTW : Wᴴ * cfc f T' * W = Vᴴ * cfc f T * V + (f 0 : ℂ) • (Dᴴ * D) := by @@ -231,10 +226,6 @@ lemma lownerConvex_compression_le.{v} {n : Type v} {m : Type v} [Fintype n] [Fin rw [heq] exact h have hWfTW' : Wᴴ * cfc f T' * W = Vᴴ * cfc f T * V + (f 0 : ℂ) • (Dᴴ * D) := hWfTW - rw [hfT_eq] - have hfVTV_eq : matrixFunction (fun x => (f x : ℂ)) (Vᴴ * T * V) hVTV_herm = - cfc f (Vᴴ * T * V) := matrixFunction_eq_cfc hVTV_herm f - rw [hfVTV_eq] have h_jensen : cfc f (Wᴴ * T' * W) ≤ Wᴴ * cfc f T' * W := by set P : Matrix (n ⊕ m) (n ⊕ m) ℂ := W * Wᴴ with hP_def have hP_sq : P * P = P := by @@ -287,16 +278,7 @@ lemma lownerConvex_compression_le.{v} {n : Type v} {m : Type v} [Fintype n] [Fin have hM_herm' : M.IsHermitian := by rw [hM_eq]; exact hM_herm have hconv_app := hconv (n ⊕ m) T' (S * T' * S) hT'_psd hST'S_psd (1/2) (by norm_num) (by norm_num) hM_herm - have hfT'_eq : matrixFunction (fun x => (f x : ℂ)) T' hT'_herm = cfc f T' := - matrixFunction_eq_cfc hT'_herm f - have hfST'S_eq : matrixFunction (fun x => (f x : ℂ)) (S * T' * S) hST'S_herm = - cfc f (S * T' * S) := matrixFunction_eq_cfc hST'S_herm f - rw [hfT'_eq, hfST'S_eq] at hconv_app - have hfM_conv : matrixFunction (fun x => (f x : ℂ)) - ((1 / 2 : ℝ) • T' + (1 - 1 / 2 : ℝ) • (S * T' * S)) hM_herm = cfc f M := - (matrixFunction_congr _ hM_herm hM_herm' hM_eq.symm).trans - (matrixFunction_eq_cfc hM_herm' f) - rw [hfM_conv] at hconv_app + rw [← hM_eq] at hconv_app have hT'_sa : IsSelfAdjoint T' := by rwa [IsSelfAdjoint, star_eq_conjTranspose] have hcfc_conj : S * cfc f T' * S = cfc f (S * T' * S) := by @@ -334,8 +316,8 @@ lemma lownerConvex_compression_le.{v} {n : Type v} {m : Type v} [Fintype n] [Fin module have hWMW_herm : (Wᴴ * M * W).IsHermitian := isHermitian_conjTranspose_mul_mul (B := W) (A := M) hM_herm' - have h_comp := matrixFunction_compression_of_commuting W M hM_herm' hWW hM_comm f hWMW_herm - rw [matrixFunction_eq_cfc hM_herm' f, matrixFunction_eq_cfc hWMW_herm f, hWMW] at h_comp + have h_comp := cfc_compression_of_commuting W M hM_herm' hWW hM_comm f hWMW_herm + rw [hWMW] at h_comp have h_compress := compression_le hconv_app W rw [h_comp] at h_compress have h_half : (1 - 1 / 2 : ℝ) = (1 / 2 : ℝ) := by norm_num @@ -389,47 +371,24 @@ private lemma compression_of_fromBlocks_cfc {m : Type*} [Fintype m] [DecidableEq (hT₁ : T₁.PosSemidef) (hT₂ : T₂.PosSemidef) (f : ℝ → ℝ) : let V := Matrix.fromRows A B let T := Matrix.fromBlocks T₁ 0 0 T₂ - let hT_herm : T.IsHermitian := by - simpa using Matrix.IsHermitian.fromBlocks hT₁.1 (by simp : (0 : Matrix m m ℂ).IsHermitian) hT₂.1 - Vᴴ * matrixFunction (fun x => (f x : ℂ)) T hT_herm * V = - Aᴴ * matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 * A + - Bᴴ * matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 * B := by + Vᴴ * cfc f T * V = Aᴴ * cfc f T₁ * A + Bᴴ * cfc f T₂ * B := by classical - intro V T hT_herm + intro V T -- Use the CFC block diagonal formula. - have hT_cfc : - matrixFunction (fun x => (f x : ℂ)) T hT_herm = - Matrix.fromBlocks - (matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1) 0 0 - (matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1) := by - have hT_cfc' : matrixFunction (fun x => (f x : ℂ)) T hT_herm = cfc f T := - matrixFunction_eq_cfc hT_herm f - have hT₁_cfc : matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 = cfc f T₁ := - matrixFunction_eq_cfc hT₁.1 f - have hT₂_cfc : matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 = cfc f T₂ := - matrixFunction_eq_cfc hT₂.1 f - have hT_sa : IsSelfAdjoint T := by - simpa [IsSelfAdjoint, Matrix.IsHermitian, star_eq_conjTranspose] using hT_herm - have hT₁_sa : IsSelfAdjoint T₁ := by - simpa [IsSelfAdjoint, Matrix.IsHermitian, star_eq_conjTranspose] using hT₁.1 - have hT₂_sa : IsSelfAdjoint T₂ := by - simpa [IsSelfAdjoint, Matrix.IsHermitian, star_eq_conjTranspose] using hT₂.1 - have hfinite : (spectrum ℝ T₁ ∪ spectrum ℝ T₂).Finite := - (Matrix.finite_real_spectrum (A := T₁)).union (Matrix.finite_real_spectrum (A := T₂)) - have hcont : ContinuousOn f (spectrum ℝ T₁ ∪ spectrum ℝ T₂) := - Set.Finite.continuousOn hfinite f - have hblock := cfc_fromBlocks_diag (m := m) (A := T₁) (D := T₂) hT₁_sa hT₂_sa f hcont - calc - matrixFunction (fun x => (f x : ℂ)) T hT_herm = cfc f T := hT_cfc' - _ = Matrix.fromBlocks (cfc f T₁) 0 0 (cfc f T₂) := by simpa [T] using hblock - _ = Matrix.fromBlocks - (matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1) 0 0 - (matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1) := by simp [hT₁_cfc, hT₂_cfc] + have hT₁_sa : IsSelfAdjoint T₁ := by + simpa [IsSelfAdjoint, Matrix.IsHermitian, star_eq_conjTranspose] using hT₁.1 + have hT₂_sa : IsSelfAdjoint T₂ := by + simpa [IsSelfAdjoint, Matrix.IsHermitian, star_eq_conjTranspose] using hT₂.1 + have hfinite : (spectrum ℝ T₁ ∪ spectrum ℝ T₂).Finite := + (Matrix.finite_real_spectrum (A := T₁)).union (Matrix.finite_real_spectrum (A := T₂)) + have hcont : ContinuousOn f (spectrum ℝ T₁ ∪ spectrum ℝ T₂) := + Set.Finite.continuousOn hfinite f + have hblock := cfc_fromBlocks_diag (m := m) (A := T₁) (D := T₂) hT₁_sa hT₂_sa f hcont + have hT_cfc : cfc f T = Matrix.fromBlocks (cfc f T₁) 0 0 (cfc f T₂) := by + simpa [T] using hblock rw [hT_cfc] simpa [V] using fromRows_compress_blockDiag - (A := A) (B := B) - (T₁ := matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1) - (T₂ := matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1) + (A := A) (B := B) (T₁ := cfc f T₁) (T₂ := cfc f T₂) /-- IsLownerConvex + f(0) ≤ 0 implies HPJ inequality (Matrix Convexity). Theorem 3.1 in Effros 2008, originally Hansen-Pedersen 1981 Theorem 2.1 (i)⟹(iii). @@ -453,10 +412,7 @@ lemma isJensenConvex_of_isLownerConvex.{v} have hVTV : Vᴴ * T * V = Aᴴ * T₁ * A + Bᴴ * T₂ * B := fromRows_compress_blockDiag A B T₁ T₂ -- Step 3: V†f(T)V = A†f(T₁)A + B†f(T₂)B (block diagonal CFC) - have hVfTV : Vᴴ * matrixFunction (fun x => (f x : ℂ)) T - (by simpa using Matrix.IsHermitian.fromBlocks hT₁.1 (by simp : (0 : Matrix m m ℂ).IsHermitian) hT₂.1) * V = - Aᴴ * matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 * A + - Bᴴ * matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 * B := + have hVfTV : Vᴴ * cfc f T * V = Aᴴ * cfc f T₁ * A + Bᴴ * cfc f T₂ * B := compression_of_fromBlocks_cfc A B T₁ T₂ hT₁ hT₂ f have hΔ := Matrix.PosSemidef.one_sub_fromRows A B hAB let Δ := (1 : Matrix m m ℂ) - Vᴴ * V @@ -468,19 +424,12 @@ lemma isJensenConvex_of_isLownerConvex.{v} have : (Dᴴ * D).PosSemidef := by rw [hDD]; exact hΔ exact Matrix.PosSemidef.smul_nonpos hf0 this - have hfC := matrixFunction_congr (fun x => (f x : ℂ)) hC - (isHermitian_conjTranspose_mul_mul (B := V) (A := T) hT_psd.1) hVTV.symm - have hT_herm : T.IsHermitian := by - simpa using Matrix.IsHermitian.fromBlocks hT₁.1 - (by simp : (0 : Matrix m m ℂ).IsHermitian) hT₂.1 - calc matrixFunction (fun x => (f x : ℂ)) (Aᴴ * T₁ * A + Bᴴ * T₂ * B) hC - = matrixFunction (fun x => (f x : ℂ)) (Vᴴ * T * V) - (isHermitian_conjTranspose_mul_mul (B := V) (A := T) hT_psd.1) := hfC - _ ≤ Vᴴ * matrixFunction (fun x => (f x : ℂ)) T hT_herm * V := by + calc cfc f (Aᴴ * T₁ * A + Bᴴ * T₂ * B) + = cfc f (Vᴴ * T * V) := by rw [hVTV] + _ ≤ Vᴴ * cfc f T * V := by have hVV : Vᴴ * V ≤ 1 := by simpa [V, fromRows_conjTranspose_mul_self] using hAB exact lownerConvex_compression_le hconv hf0 V hVV T hT_psd - _ = Aᴴ * matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 * A + - Bᴴ * matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 * B := hVfTV + _ = Aᴴ * cfc f T₁ * A + Bᴴ * cfc f T₂ * B := hVfTV /-- Matrix convexity of matrix inverse in the Löwner order. -/ private lemma inv_lowner_convex_le {m : Type*} [Fintype m] [DecidableEq m] @@ -619,19 +568,22 @@ for any PSD matrices A, B and t ∈ [0,1]. 1. Use the integral representation of xˢ via `exists_measure_nnrpow_eq_integral_cfcₙ_rpowIntegrand₀₁`. 2. Identify the integrand with the resolvent form `1 - u * (x + u)⁻¹` using CFC. 3. Apply the resolvent operator concavity inequality pointwise in u. -4. Integrate and rewrite with `matrixFunction_rpow_eq` to conclude the inequality. -/ +4. Integrate and rewrite with `CFC.rpow_eq_cfc_real` to conclude the inequality. -/ private lemma rpow_operator_concave_le {m : Type*} [Fintype m] [DecidableEq m] {s : ℝ} (hs0 : 0 < s) (hs1 : s ≤ 1) (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (hC : (t • A + (1 - t) • B).IsHermitian) : - t • matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) A hA.1 + - (1 - t) • matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) B hB.1 ≤ - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) (t • A + (1 - t) • B) hC := by + t • A ^ s + (1 - t) • B ^ s ≤ (t • A + (1 - t) • B) ^ s := by classical by_cases hs_eq : s = 1 · subst hs_eq - simp [Real.rpow_one, matrixFunction_id] + have hA0 : (0 : Matrix m m ℂ) ≤ A := by simpa [Matrix.le_iff] using hA + have hB0 : (0 : Matrix m m ℂ) ≤ B := by simpa [Matrix.le_iff] using hB + have hC0 : (0 : Matrix m m ℂ) ≤ t • A + (1 - t) • B := by + simpa [Matrix.le_iff] using (hA.real_smul ht0).add (hB.real_smul (by linarith)) + simp only [CFC.rpow_one (a := A) hA0, CFC.rpow_one (a := B) hB0, + CFC.rpow_one (a := t • A + (1 - t) • B) hC0, le_refl] -- The `attribute [local instance]` directives at the top of this -- `RpowOperatorConcaveAux` section activate the linfty operator-norm tower -- on `Matrix _ _ ℂ`. We additionally need to pin a few non-instance @@ -734,42 +686,36 @@ private lemma rpow_operator_concave_le {m : Type*} [Fintype m] [DecidableEq m] have hC_spec : quasispectrum ℝ C ⊆ Ici 0 := by intro x hx exact (StarOrderedRing.nonneg_iff_quasispectrum_nonneg (A := Matrix m m ℂ) C).1 hC0 x hx + have hcont_res : ContinuousOn (fun x : ℝ => 1 - u * (x + u)⁻¹) (Ici 0) := by + have hcont_add : ContinuousOn (fun x : ℝ => x + u) (Ici 0) := by fun_prop + have hne : ∀ x ∈ Ici (0 : ℝ), x + u ≠ 0 := by + intro x hx; have hx' : 0 ≤ x := hx; linarith + exact continuousOn_const.sub + (continuousOn_const.mul (ContinuousOn.inv₀ hcont_add hne)) + have hAspec' : spectrum ℝ A ⊆ Ici 0 := by + rw [hA.1.spectrum_real_eq_range_eigenvalues] + rintro _ ⟨i, rfl⟩; exact hA.eigenvalues_nonneg i + have hBspec' : spectrum ℝ B ⊆ Ici 0 := by + rw [hB.1.spectrum_real_eq_range_eigenvalues] + rintro _ ⟨i, rfl⟩; exact hB.eigenvalues_nonneg i + have hCspec' : spectrum ℝ C ⊆ Ici 0 := by + rw [hCpsd.1.spectrum_real_eq_range_eigenvalues] + rintro _ ⟨i, rfl⟩; exact hCpsd.eigenvalues_nonneg i have hA_eq : - cfcₙ (rpowIntegrand₀₁ q u) A = - matrixFunction (fun x => ((rpowIntegrand₀₁ (q : ℝ) u x : ℝ) : ℂ)) A hA.1 := by - calc - cfcₙ (rpowIntegrand₀₁ q u) A = - cfc (rpowIntegrand₀₁ (q : ℝ) u) A := by - simpa [Real.rpowIntegrand₀₁_zero_right] using - (cfcₙ_eq_cfc (a := A) (f := fun x => rpowIntegrand₀₁ (q : ℝ) u x) - (hf := hcont_Ici.mono hA_spec) (hf0 := Real.rpowIntegrand₀₁_zero_right)) - _ = _ := by - symm - exact matrixFunction_eq_cfc hA.1 (fun x => rpowIntegrand₀₁ (q : ℝ) u x) + cfcₙ (rpowIntegrand₀₁ q u) A = cfc (rpowIntegrand₀₁ (q : ℝ) u) A := by + simpa [Real.rpowIntegrand₀₁_zero_right] using + (cfcₙ_eq_cfc (a := A) (f := fun x => rpowIntegrand₀₁ (q : ℝ) u x) + (hf := hcont_Ici.mono hA_spec) (hf0 := Real.rpowIntegrand₀₁_zero_right)) have hB_eq : - cfcₙ (rpowIntegrand₀₁ q u) B = - matrixFunction (fun x => ((rpowIntegrand₀₁ (q : ℝ) u x : ℝ) : ℂ)) B hB.1 := by - calc - cfcₙ (rpowIntegrand₀₁ q u) B = - cfc (rpowIntegrand₀₁ (q : ℝ) u) B := by - simpa [Real.rpowIntegrand₀₁_zero_right] using - (cfcₙ_eq_cfc (a := B) (f := fun x => rpowIntegrand₀₁ (q : ℝ) u x) - (hf := hcont_Ici.mono hB_spec) (hf0 := Real.rpowIntegrand₀₁_zero_right)) - _ = _ := by - symm - exact matrixFunction_eq_cfc hB.1 (fun x => rpowIntegrand₀₁ (q : ℝ) u x) + cfcₙ (rpowIntegrand₀₁ q u) B = cfc (rpowIntegrand₀₁ (q : ℝ) u) B := by + simpa [Real.rpowIntegrand₀₁_zero_right] using + (cfcₙ_eq_cfc (a := B) (f := fun x => rpowIntegrand₀₁ (q : ℝ) u x) + (hf := hcont_Ici.mono hB_spec) (hf0 := Real.rpowIntegrand₀₁_zero_right)) have hC_eq : - cfcₙ (rpowIntegrand₀₁ q u) C = - matrixFunction (fun x => ((rpowIntegrand₀₁ (q : ℝ) u x : ℝ) : ℂ)) C hCpsd.1 := by - calc - cfcₙ (rpowIntegrand₀₁ q u) C = - cfc (rpowIntegrand₀₁ (q : ℝ) u) C := by - simpa [Real.rpowIntegrand₀₁_zero_right] using - (cfcₙ_eq_cfc (a := C) (f := fun x => rpowIntegrand₀₁ (q : ℝ) u x) - (hf := hcont_Ici.mono hC_spec) (hf0 := Real.rpowIntegrand₀₁_zero_right)) - _ = _ := by - symm - exact matrixFunction_eq_cfc hCpsd.1 (fun x => rpowIntegrand₀₁ (q : ℝ) u x) + cfcₙ (rpowIntegrand₀₁ q u) C = cfc (rpowIntegrand₀₁ (q : ℝ) u) C := by + simpa [Real.rpowIntegrand₀₁_zero_right] using + (cfcₙ_eq_cfc (a := C) (f := fun x => rpowIntegrand₀₁ (q : ℝ) u x) + (hf := hcont_Ici.mono hC_spec) (hf0 := Real.rpowIntegrand₀₁_zero_right)) have hfun : (fun x : ℝ => rpowIntegrand₀₁ (q : ℝ) u x) = fun x => u ^ (s - 1) * (1 - u * (x + u)⁻¹) := by @@ -792,54 +738,32 @@ private lemma rpow_operator_concave_le {m : Type*} [Fintype m] [DecidableEq m] simp [hu0, hx] simp [hmul] have hA_res : - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) A hA.1 = + cfc (fun x => 1 - u * (x + u)⁻¹) A = (1 : Matrix m m ℂ) - (u : ℂ) • (A + (u : ℂ) • 1)⁻¹ := - matrixFunction_resolvent (m := m) hA (r := u) hu' + cfc_resolvent (m := m) hA hu' have hB_res : - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) B hB.1 = + cfc (fun x => 1 - u * (x + u)⁻¹) B = (1 : Matrix m m ℂ) - (u : ℂ) • (B + (u : ℂ) • 1)⁻¹ := - matrixFunction_resolvent (m := m) hB (r := u) hu' + cfc_resolvent (m := m) hB hu' have hC_res : - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) C hCpsd.1 = + cfc (fun x => 1 - u * (x + u)⁻¹) C = (1 : Matrix m m ℂ) - (u : ℂ) • (C + (u : ℂ) • 1)⁻¹ := - matrixFunction_resolvent (m := m) hCpsd (r := u) hu' + cfc_resolvent (m := m) hCpsd hu' have hA_int' : - matrixFunction (fun x => ((rpowIntegrand₀₁ (q : ℝ) u x : ℝ) : ℂ)) A hA.1 = - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) A hA.1 := by - have hsmul : - matrixFunction (fun x => (((u ^ (s - 1)) * (1 - u * (x + u)⁻¹) : ℝ) : ℂ)) A hA.1 = - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) A hA.1 := by - simpa using - (matrixFunction_smul hA.1 ((u ^ (s - 1) : ℝ) : ℂ) - (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ))) - simpa [hfun] using hsmul + cfc (fun x => rpowIntegrand₀₁ (q : ℝ) u x) A = + (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) A := by + rw [hfun, cfc_const_mul (R := ℝ) (u ^ (s - 1)) (fun x => 1 - u * (x + u)⁻¹) A + (hcont_res.mono hAspec')] have hB_int' : - matrixFunction (fun x => ((rpowIntegrand₀₁ (q : ℝ) u x : ℝ) : ℂ)) B hB.1 = - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) B hB.1 := by - have hsmul : - matrixFunction (fun x => (((u ^ (s - 1)) * (1 - u * (x + u)⁻¹) : ℝ) : ℂ)) B hB.1 = - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) B hB.1 := by - simpa - using - (matrixFunction_smul hB.1 ((u ^ (s - 1) : ℝ) : ℂ) - (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ))) - simpa [hfun] using hsmul + cfc (fun x => rpowIntegrand₀₁ (q : ℝ) u x) B = + (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) B := by + rw [hfun, cfc_const_mul (R := ℝ) (u ^ (s - 1)) (fun x => 1 - u * (x + u)⁻¹) B + (hcont_res.mono hBspec')] have hC_int' : - matrixFunction (fun x => ((rpowIntegrand₀₁ (q : ℝ) u x : ℝ) : ℂ)) C hCpsd.1 = - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) C hCpsd.1 := by - have hsmul : - matrixFunction (fun x => (((u ^ (s - 1)) * (1 - u * (x + u)⁻¹) : ℝ) : ℂ)) C hCpsd.1 = - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) C hCpsd.1 := by - simpa using - (matrixFunction_smul hCpsd.1 ((u ^ (s - 1) : ℝ) : ℂ) - (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ))) - simpa [hfun] using hsmul + cfc (fun x => rpowIntegrand₀₁ (q : ℝ) u x) C = + (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) C := by + rw [hfun, cfc_const_mul (R := ℝ) (u ^ (s - 1)) (fun x => 1 - u * (x + u)⁻¹) C + (hcont_res.mono hCspec')] have hres_le : t • ((1 : Matrix m m ℂ) - (u : ℂ) • (A + (u : ℂ) • 1)⁻¹) + (1 - t) • ((1 : Matrix m m ℂ) - (u : ℂ) • (B + (u : ℂ) • 1)⁻¹) @@ -848,45 +772,36 @@ private lemma rpow_operator_concave_le {m : Type*} [Fintype m] [DecidableEq m] (resolvent_lowner_concave_le (m := m) hA hB ht0 ht1 (r := u) hu') -- Scale the resolvent inequality by the positive factor u^(s-1). have hscale : - ((u ^ (s - 1) : ℝ) : ℂ) • + (u ^ (s - 1) : ℝ) • (t • ((1 : Matrix m m ℂ) - (u : ℂ) • (A + (u : ℂ) • 1)⁻¹) + (1 - t) • ((1 : Matrix m m ℂ) - (u : ℂ) • (B + (u : ℂ) • 1)⁻¹)) - ≤ ((u ^ (s - 1) : ℝ) : ℂ) • + ≤ (u ^ (s - 1) : ℝ) • ((1 : Matrix m m ℂ) - (u : ℂ) • (C + (u : ℂ) • 1)⁻¹) := by - have hnonneg : 0 ≤ u ^ (s - 1) := by - exact Real.rpow_nonneg (le_of_lt hu') _ - have hnonneg_C : (0 : ℂ) ≤ ((u ^ (s - 1) : ℝ) : ℂ) := by - rw [show (0 : ℂ) = ((0 : ℝ) : ℂ) from rfl, Complex.real_le_real] - exact hnonneg - rw [Matrix.le_iff] at hres_le ⊢ - have hpsd : - (((u ^ (s - 1) : ℝ) : ℂ) • - ((1 : Matrix m m ℂ) - (u : ℂ) • (C + (u : ℂ) • 1)⁻¹) - - ((u ^ (s - 1) : ℝ) : ℂ) • - (t • ((1 : Matrix m m ℂ) - (u : ℂ) • (A + (u : ℂ) • 1)⁻¹) + - (1 - t) • ((1 : Matrix m m ℂ) - (u : ℂ) • (B + (u : ℂ) • 1)⁻¹))).PosSemidef := by - simpa [smul_sub] using hres_le.smul hnonneg_C - simpa [smul_sub] using hpsd - -- Replace with the matrixFunction form. + have hnonneg : 0 ≤ u ^ (s - 1) := by positivity + rw [Matrix.le_iff] + have h := (Matrix.le_iff.mp hres_le).real_smul hnonneg + convert h using 1 + exact (smul_sub _ _ _).symm + -- Replace with the cfc resolvent form. have hscale' : - ((u ^ (s - 1) : ℝ) : ℂ) • - (t • matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) A hA.1 + - (1 - t) • matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) B hB.1) - ≤ ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) C hCpsd.1 := by + (u ^ (s - 1) : ℝ) • + (t • cfc (fun x => 1 - u * (x + u)⁻¹) A + + (1 - t) • cfc (fun x => 1 - u * (x + u)⁻¹) B) + ≤ (u ^ (s - 1) : ℝ) • + cfc (fun x => 1 - u * (x + u)⁻¹) C := by have hscale' := hscale rw [hA_res.symm, hB_res.symm, hC_res.symm] at hscale' exact hscale' have hscale'' : - t • ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) A hA.1 + - (1 - t) • ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) B hB.1 ≤ - ((u ^ (s - 1) : ℝ) : ℂ) • - matrixFunction (fun x => ((1 - u * (x + u)⁻¹ : ℝ) : ℂ)) C hCpsd.1 := by - rw [smul_comm t ((u ^ (s - 1) : ℝ) : ℂ), - smul_comm (1 - t) ((u ^ (s - 1) : ℝ) : ℂ), ← smul_add] - exact hscale' + t • (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) A + + (1 - t) • (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) B ≤ + (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) C := by + have e : (u ^ (s - 1) : ℝ) • (t • cfc (fun x => 1 - u * (x + u)⁻¹) A + + (1 - t) • cfc (fun x => 1 - u * (x + u)⁻¹) B) = + t • (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) A + + (1 - t) • (u ^ (s - 1) : ℝ) • cfc (fun x => 1 - u * (x + u)⁻¹) B := by + module + rw [← e]; exact hscale' simpa [hA_eq, hB_eq, hC_eq, hA_int', hB_int', hC_int'] using hscale'' have hle_integral : t • (∫ u in Ioi 0, cfcₙ (rpowIntegrand₀₁ q u) A ∂μ) + @@ -953,28 +868,10 @@ private lemma rpow_operator_concave_le {m : Type*} [Fintype m] [DecidableEq m] CFC.nnrpow_eq_rpow (A := Matrix m m ℂ) (a := C) (x := q) hq_pos have h2 : C ^ q = ∫ u in Ioi 0, cfcₙ (rpowIntegrand₀₁ q u) C ∂μ := (hμ C hC0).2 rw [← hqs, ← h1]; exact h2 - have hC_eq_mf : - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) C hC = C ^ s := by - have hC' : - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) C hC = - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) C hCpsd.1 := by - exact - (matrixFunction_congr (A := C) (B := C) - (f := fun x => ((x ^ s : ℝ) : ℂ)) (hA := hC) (hB := hCpsd.1) rfl) - calc - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) C hC = - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) C hCpsd.1 := hC' - _ = C ^ s := matrixFunction_rpow_eq hCpsd s - have hA_eq_mf : - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) A hA.1 = A ^ s := - matrixFunction_rpow_eq hA s - have hB_eq_mf : - matrixFunction (fun x => ((x ^ s : ℝ) : ℂ)) B hB.1 = B ^ s := - matrixFunction_rpow_eq hB s - -- Rewrite the integral inequality to the matrixFunction statement. + -- Conclude from the integral inequality. have hfinal : t • A ^ s + (1 - t) • B ^ s ≤ C ^ s := by simpa [hA_eq_int, hB_eq_int, hC_eq_int] using hle_integral - simpa [hA_eq_mf, hB_eq_mf, hC_eq_mf, C] using hfinal + exact hfinal end RpowOperatorConcaveAux @@ -984,31 +881,18 @@ private lemma rpow_concavity_quadform_nonneg {m : Type*} [Fintype m] [DecidableE (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef) (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) (hC : (t • A + (1 - t) • B).IsHermitian) (v : m → ℂ) : - 0 ≤ (star v ⬝ᵥ ( - matrixFunction (fun x => Complex.ofReal (x ^ s)) (t • A + (1 - t) • B) hC - - t • matrixFunction (fun x => Complex.ofReal (x ^ s)) A hA.1 - - (1 - t) • matrixFunction (fun x => Complex.ofReal (x ^ s)) B hB.1) *ᵥ v).re := by - have hle : - t • matrixFunction (fun x => Complex.ofReal (x ^ s)) A hA.1 + - (1 - t) • matrixFunction (fun x => Complex.ofReal (x ^ s)) B hB.1 ≤ - matrixFunction (fun x => Complex.ofReal (x ^ s)) (t • A + (1 - t) • B) hC := + 0 ≤ (star v ⬝ᵥ + ((t • A + (1 - t) • B) ^ s - t • A ^ s - (1 - t) • B ^ s) *ᵥ v).re := by + have hle : t • A ^ s + (1 - t) • B ^ s ≤ (t • A + (1 - t) • B) ^ s := rpow_operator_concave_le hs0 hs1 A B hA hB t ht0 ht1 hC have hpsd : - (matrixFunction (fun x => Complex.ofReal (x ^ s)) (t • A + (1 - t) • B) hC - - (t • matrixFunction (fun x => Complex.ofReal (x ^ s)) A hA.1 + - (1 - t) • matrixFunction (fun x => Complex.ofReal (x ^ s)) B hB.1)).PosSemidef := by + ((t • A + (1 - t) • B) ^ s - (t • A ^ s + (1 - t) • B ^ s)).PosSemidef := by simpa [Matrix.le_iff] using hle have hpsd' : - (matrixFunction (fun x => Complex.ofReal (x ^ s)) (t • A + (1 - t) • B) hC - - t • matrixFunction (fun x => Complex.ofReal (x ^ s)) A hA.1 - - (1 - t) • matrixFunction (fun x => Complex.ofReal (x ^ s)) B hB.1).PosSemidef := by + ((t • A + (1 - t) • B) ^ s - t • A ^ s - (1 - t) • B ^ s).PosSemidef := by have hcalc : - (matrixFunction (fun x => Complex.ofReal (x ^ s)) (t • A + (1 - t) • B) hC - - (t • matrixFunction (fun x => Complex.ofReal (x ^ s)) A hA.1 + - (1 - t) • matrixFunction (fun x => Complex.ofReal (x ^ s)) B hB.1)) = - (matrixFunction (fun x => Complex.ofReal (x ^ s)) (t • A + (1 - t) • B) hC - - t • matrixFunction (fun x => Complex.ofReal (x ^ s)) A hA.1 - - (1 - t) • matrixFunction (fun x => Complex.ofReal (x ^ s)) B hB.1) := by + ((t • A + (1 - t) • B) ^ s - (t • A ^ s + (1 - t) • B ^ s)) = + ((t • A + (1 - t) • B) ^ s - t • A ^ s - (1 - t) • B ^ s) := by module simpa [hcalc] using hpsd have hnonneg := hpsd'.dotProduct_mulVec_nonneg v @@ -1026,65 +910,23 @@ lemma rpow_isLownerConcave {s : ℝ} (hs0 : 0 < s) (hs1 : s ≤ 1) : IsLownerConcave (fun t => t ^ s) := by unfold IsLownerConcave intro m _ _ A B hA hB t ht0 ht1 hC - rw [Matrix.le_iff] - -- Define the power function - let f : ℝ → ℂ := fun x => Complex.ofReal (x ^ s) - let neg_f : ℝ → ℂ := fun x => Complex.ofReal (-(x ^ s)) - -- Relate neg_f to -f - have hfunc : neg_f = fun x => -f x := by - funext x; exact Complex.ofReal_neg (x ^ s) - -- The matrixFunction of neg_f equals -matrixFunction of f - have hA_mf : matrixFunction neg_f A hA.1 = -matrixFunction f A hA.1 := by - rw [hfunc]; exact matrixFunction_neg hA.1 f - have hB_mf : matrixFunction neg_f B hB.1 = -matrixFunction f B hB.1 := by - rw [hfunc]; exact matrixFunction_neg hB.1 f - have hC_mf : matrixFunction neg_f (t • A + (1 - t) • B) hC = - -matrixFunction f (t • A + (1 - t) • B) hC := by - rw [hfunc]; exact matrixFunction_neg hC f - -- The goal's function equals neg_f - have hgoal_A : matrixFunction (fun x : ℝ => (((fun y => -(y ^ s)) x : ℝ) : ℂ)) A hA.1 = - matrixFunction neg_f A hA.1 := rfl - have hgoal_B : matrixFunction (fun x : ℝ => (((fun y => -(y ^ s)) x : ℝ) : ℂ)) B hB.1 = - matrixFunction neg_f B hB.1 := rfl - have hgoal_C : matrixFunction (fun x : ℝ => (((fun y => -(y ^ s)) x : ℝ) : ℂ)) - (t • A + (1 - t) • B) hC = matrixFunction neg_f (t • A + (1 - t) • B) hC := rfl - simp only [hgoal_A, hgoal_B, hgoal_C, hA_mf, hB_mf, hC_mf] - -- Simplify: t•(-A^s) + (1-t)•(-B^s) - (-C^s) = C^s - t•A^s - (1-t)•B^s - have halg : t • -matrixFunction f A hA.1 + (1 - t) • -matrixFunction f B hB.1 - - -matrixFunction f (t • A + (1 - t) • B) hC = - matrixFunction f (t • A + (1 - t) • B) hC - - t • matrixFunction f A hA.1 - (1 - t) • matrixFunction f B hB.1 := by module - rw [halg] - -- Show PosSemidef via Hermitian and quadratic form characterization - -- Use PosSemidef.of_dotProduct_mulVec_nonneg which works with (n → R) instead of Finsupp - apply PosSemidef.of_dotProduct_mulVec_nonneg - -- First show Hermitian - · have hC_herm : (matrixFunction f (t • A + (1 - t) • B) hC).IsHermitian := by - simpa [f] using matrixFunction_isHermitian hC (fun x => x ^ s) - have hA_herm : (t • matrixFunction f A hA.1).IsHermitian := by - simpa [f] using IsHermitian.smul_real (matrixFunction_isHermitian hA.1 (fun x => x ^ s)) t - have hB_herm : ((1 - t) • matrixFunction f B hB.1).IsHermitian := by - simpa [f] using IsHermitian.smul_real (matrixFunction_isHermitian hB.1 (fun x => x ^ s)) (1 - t) - exact IsHermitian.sub (IsHermitian.sub hC_herm hA_herm) hB_herm - -- Then show the quadratic form is nonneg for all vectors - · intro v - -- The helper lemma gives us the real part is nonneg - have h_re : 0 ≤ (star v ⬝ᵥ (matrixFunction f (t • A + (1 - t) • B) hC - - t • matrixFunction f A hA.1 - (1 - t) • matrixFunction f B hB.1) *ᵥ v).re := - rpow_concavity_quadform_nonneg hs0 hs1 A B hA hB t ht0 ht1 hC v - -- The result is real (imaginary part is 0), so nonneg iff real part is nonneg - have hreal : (star v ⬝ᵥ (matrixFunction f (t • A + (1 - t) • B) hC - - t • matrixFunction f A hA.1 - (1 - t) • matrixFunction f B hB.1) *ᵥ v).im = 0 := by - apply IsHermitian.quadForm_im_eq_zero - have hC_herm : (matrixFunction f (t • A + (1 - t) • B) hC).IsHermitian := by - simpa [f] using matrixFunction_isHermitian hC (fun x => x ^ s) - have hA_herm : (t • matrixFunction f A hA.1).IsHermitian := by - simpa [f] using IsHermitian.smul_real (matrixFunction_isHermitian hA.1 (fun x => x ^ s)) t - have hB_herm : ((1 - t) • matrixFunction f B hB.1).IsHermitian := by - simpa [f] using IsHermitian.smul_real (matrixFunction_isHermitian hB.1 (fun x => x ^ s)) (1 - t) - exact IsHermitian.sub (IsHermitian.sub hC_herm hA_herm) hB_herm - rw [Complex.nonneg_iff] - exact ⟨h_re, hreal.symm⟩ + have hA0 : (0 : Matrix m m ℂ) ≤ A := by simpa [Matrix.le_iff] using hA + have hB0 : (0 : Matrix m m ℂ) ≤ B := by simpa [Matrix.le_iff] using hB + have hC0 : (0 : Matrix m m ℂ) ≤ t • A + (1 - t) • B := by + simpa [Matrix.le_iff] using (hA.real_smul ht0).add (hB.real_smul (by linarith)) + change cfc (fun x : ℝ => -(x ^ s)) (t • A + (1 - t) • B) ≤ + t • cfc (fun x : ℝ => -(x ^ s)) A + (1 - t) • cfc (fun x : ℝ => -(x ^ s)) B + have eA : cfc (fun x : ℝ => -(x ^ s)) A = -(A ^ s) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := A) (ha := hA0)] + have eB : cfc (fun x : ℝ => -(x ^ s)) B = -(B ^ s) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := B) (ha := hB0)] + have eC : cfc (fun x : ℝ => -(x ^ s)) (t • A + (1 - t) • B) = -((t • A + (1 - t) • B) ^ s) := by + rw [cfc_neg, ← CFC.rpow_eq_cfc_real (a := t • A + (1 - t) • B) (ha := hC0)] + rw [eA, eB, eC] + have key := rpow_operator_concave_le hs0 hs1 A B hA hB t ht0 ht1 hC + rw [Matrix.le_iff] at key ⊢ + convert key using 1 + module /-- The negated power function -t^s (0 < s ≤ 1) is Löwner convex. This is the dual statement of rpow_isLownerConcave. -/ @@ -1111,9 +953,9 @@ lemma hpj_subhomogeneous.{v} {f : ℝ → ℝ} (hT₁ : T₁.PosSemidef) (hT₂ : T₂.PosSemidef) (hAB : Aᴴ * A + Bᴴ * B ≤ (1 : Matrix m m ℂ)) (hC : (Aᴴ * T₁ * A + Bᴴ * T₂ * B).IsHermitian) : - let fT₁ := matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 - let fT₂ := matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 - let fC := matrixFunction (fun x => (f x : ℂ)) (Aᴴ * T₁ * A + Bᴴ * T₂ * B) hC + let fT₁ := cfc f T₁ + let fT₂ := cfc f T₂ + let fC := cfc f (Aᴴ * T₁ * A + Bᴴ * T₂ * B) fC ≤ Aᴴ * fT₁ * A + Bᴴ * fT₂ * B := by have _ := hf0 exact hconv m A B T₁ T₂ hT₁ hT₂ hAB hC @@ -1126,9 +968,9 @@ lemma hpj_affine.{v} {f : ℝ → ℝ} (hT₁ : T₁.PosSemidef) (hT₂ : T₂.PosSemidef) (hAB : Aᴴ * A + Bᴴ * B = (1 : Matrix m m ℂ)) (hC : (Aᴴ * T₁ * A + Bᴴ * T₂ * B).IsHermitian) : - let fT₁ := matrixFunction (fun x => (f x : ℂ)) T₁ hT₁.1 - let fT₂ := matrixFunction (fun x => (f x : ℂ)) T₂ hT₂.1 - let fC := matrixFunction (fun x => (f x : ℂ)) (Aᴴ * T₁ * A + Bᴴ * T₂ * B) hC + let fT₁ := cfc f T₁ + let fT₂ := cfc f T₂ + let fC := cfc f (Aᴴ * T₁ * A + Bᴴ * T₂ * B) fC ≤ Aᴴ * fT₁ * A + Bᴴ * fT₂ * B := by have hAB' : Aᴴ * A + Bᴴ * B ≤ (1 : Matrix m m ℂ) := by simp [hAB] diff --git a/QuantumSystem/Analysis/Matrix/PartialTrace.lean b/QuantumSystem/Analysis/Matrix/PartialTrace.lean index 0498a0b..3236955 100644 --- a/QuantumSystem/Analysis/Matrix/PartialTrace.lean +++ b/QuantumSystem/Analysis/Matrix/PartialTrace.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace /-! # Partial trace as restriction (matrix-level) @@ -69,6 +70,17 @@ noncomputable def restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) ∑ b : L.regionIdx (Λ_total \ Λ), M (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) := rfl +/-- **`restrict` is a partial trace over the right tensor factor.** Transporting the matrix +along the factorisation `combineIdx h : regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ regionIdx Λ_total` +turns the region restriction into `Matrix.traceRight`, which traces out the complement factor. +This bridges the region-parameterised partial trace to the positional `traceLeft`/`traceRight` +form. -/ +theorem restrict_eq_traceRight_reindex {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) + (M : L.localAlgebra Λ_total) : + restrict h M = (M.reindex (L.combineIdx h).symm (L.combineIdx h).symm).traceRight := by + ext a a' + simp [restrict_apply, Matrix.traceRight_apply, Matrix.reindex_apply] + /-! ### Trace preservation -/ /-- `Tr(restrict h M) = Tr M`: the restriction preserves the global trace. -/ diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean new file mode 100644 index 0000000..2843e63 --- /dev/null +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean @@ -0,0 +1,98 @@ +module + +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.LinearAlgebra.Matrix.Trace + +/-! +# Partial trace of a matrix over a tensor factor + +For a matrix whose row/column indices are product types sharing one factor, the **partial +traces** over that common factor: + +* `Matrix.traceRight (M : Matrix (l × n) (c × n) R) : Matrix l c R` — trace out the **right** + factor `n`, entry-wise `traceRight M i j = ∑ k, M (i, k) (j, k)`; +* `Matrix.traceLeft (M : Matrix (n × l) (n × c) R) : Matrix l c R` — trace out the **left** + factor `n`, entry-wise `traceLeft M i j = ∑ k, M (k, i) (k, j)`. + +These are the concrete matrix-entry forms of the basis-free operator partial trace +`TensorProduct.partialTraceRight` (`QuantumSystem.ForMathlib.LinearAlgebra.Trace`). The row and +column "kept" indices `l`, `c` are allowed to differ, so the operations apply to rectangular +blocks; they are stated over an arbitrary `AddCommMonoid` so they specialise to scalars in any +finite-dimensional quantum system. + +## Main results + +* `Matrix.traceLeft_eq_traceRight_prodComm` — tracing out the left factor equals tracing out + the right factor after swapping the two factors with `Equiv.prodComm`. +-/ + +@[expose] public section + +namespace Matrix + +variable {R : Type*} [AddCommMonoid R] + +/-- **Partial trace over the right factor**: trace out the common right factor `n` of a matrix +with rows indexed by `l × n` and columns by `c × n`, leaving a matrix on `l × c`. Entry-wise +`traceRight M i j = ∑ k, M (i, k) (j, k)`. -/ +def traceRight {l c n : Type*} [Fintype n] (M : Matrix (l × n) (c × n) R) : Matrix l c R := + Matrix.of fun i j => ∑ k, M (i, k) (j, k) + +/-- **Partial trace over the left factor**: trace out the common left factor `n` of a matrix +with rows indexed by `n × l` and columns by `n × c`, leaving a matrix on `l × c`. Entry-wise +`traceLeft M i j = ∑ k, M (k, i) (k, j)`. -/ +def traceLeft {l c n : Type*} [Fintype n] (M : Matrix (n × l) (n × c) R) : Matrix l c R := + Matrix.of fun i j => ∑ k, M (k, i) (k, j) + +@[simp] lemma traceRight_apply {l c n : Type*} [Fintype n] (M : Matrix (l × n) (c × n) R) + (i : l) (j : c) : + traceRight M i j = ∑ k, M (i, k) (j, k) := rfl + +@[simp] lemma traceLeft_apply {l c n : Type*} [Fintype n] (M : Matrix (n × l) (n × c) R) + (i : l) (j : c) : + traceLeft M i j = ∑ k, M (k, i) (k, j) := rfl + +/-- The right partial trace of the zero matrix is zero. -/ +@[simp] lemma traceRight_zero {l c n : Type*} [Fintype n] : + traceRight (0 : Matrix (l × n) (c × n) ℂ) = 0 := by + ext i j; simp [traceRight_apply] + +/-- The left partial trace of the zero matrix is zero. -/ +@[simp] lemma traceLeft_zero {l c n : Type*} [Fintype n] : + traceLeft (0 : Matrix (n × l) (n × c) ℂ) = 0 := by + ext i j; simp [traceLeft_apply] + +/-- The right partial trace is `ℝ`-linear in the matrix. -/ +@[simp] lemma traceRight_smul {l n : Type*} [Fintype n] (c : ℝ) (M : Matrix (l × n) (l × n) ℂ) : + traceRight (c • M) = c • traceRight M := by + ext i j; simp only [traceRight_apply, Matrix.smul_apply]; exact Finset.smul_sum.symm + +/-- The left partial trace is `ℝ`-linear in the matrix. -/ +@[simp] lemma traceLeft_smul {l n : Type*} [Fintype n] (c : ℝ) (M : Matrix (n × l) (n × l) ℂ) : + traceLeft (c • M) = c • traceLeft M := by + ext i j; simp only [traceLeft_apply, Matrix.smul_apply]; exact Finset.smul_sum.symm + +/-- Tracing out the **left** factor equals tracing out the **right** factor after swapping the +two factors with `Equiv.prodComm`. -/ +theorem traceLeft_eq_traceRight_prodComm {l c n : Type*} [Fintype n] + (M : Matrix (n × l) (n × c) R) : + traceLeft M = traceRight (M.reindex (Equiv.prodComm n l) (Equiv.prodComm n c)) := by + ext i j + simp [Matrix.reindex_apply] + +/-- The right partial trace preserves the full trace: `Tr (traceRight M) = Tr M`. -/ +@[simp] theorem trace_traceRight {l n : Type*} [Fintype l] [Fintype n] + (M : Matrix (l × n) (l × n) R) : + (traceRight M).trace = M.trace := by + simp only [Matrix.trace, Matrix.diag_apply, traceRight_apply] + exact (Fintype.sum_prod_type fun p : l × n => M p p).symm + +/-- The left partial trace preserves the full trace: `Tr (traceLeft M) = Tr M`. -/ +@[simp] theorem trace_traceLeft {l n : Type*} [Fintype l] [Fintype n] + (M : Matrix (n × l) (n × l) R) : + (traceLeft M).trace = M.trace := by + simp only [Matrix.trace, Matrix.diag_apply, traceLeft_apply] + rw [Finset.sum_comm] + exact (Fintype.sum_prod_type fun p : n × l => M p p).symm + +end Matrix diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PosDef.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PosDef.lean new file mode 100644 index 0000000..672cbb2 --- /dev/null +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PosDef.lean @@ -0,0 +1,32 @@ +module + +public import Mathlib.Analysis.Complex.Basic +public import Mathlib.LinearAlgebra.Matrix.PosDef + +/-! +# Positive semidefinite matrix lemmas + +This file collects small positive-semidefinite matrix lemmas that are candidates for Mathlib. +-/ + +@[expose] public section + +namespace Matrix + +open scoped ComplexOrder + +/-- A nonnegative real multiple of a positive semidefinite matrix is positive semidefinite. -/ +lemma posSemidef_smul_nonneg {n : Type*} [Finite n] {c : ℝ} (hc : 0 ≤ c) + {M : Matrix n n ℂ} (hM : M.PosSemidef) : (c • M).PosSemidef := by + classical + have : Fintype n := Fintype.ofFinite n + suffices h' : (((c : ℝ) : ℂ) • M).PosSemidef by rwa [Complex.coe_smul] at h' + have key : ((c : ℝ) : ℂ) • M = (((Real.sqrt c : ℝ) : ℂ) • (1 : Matrix n n ℂ)) * M + * (((Real.sqrt c : ℝ) : ℂ) • (1 : Matrix n n ℂ))ᴴ := by + rw [Matrix.conjTranspose_smul, Matrix.conjTranspose_one, Complex.star_def, Complex.conj_ofReal, + smul_mul_assoc, Matrix.one_mul, smul_mul_assoc, mul_smul_comm, Matrix.mul_one, smul_smul, + ← Complex.ofReal_mul, Real.mul_self_sqrt hc] + rw [key] + exact hM.mul_mul_conjTranspose_same _ + +end Matrix diff --git a/QuantumSystem/State.lean b/QuantumSystem/State.lean index 5a34182..0aa175c 100644 --- a/QuantumSystem/State.lean +++ b/QuantumSystem/State.lean @@ -112,18 +112,18 @@ noncomputable instance : HPow (DensityMatrix n) ℝ (Matrix n n ℂ) where theorem densityMatrix_hpow_eq (ρ : DensityMatrix n) (s : ℝ) : ρ ^ s = ρ.toMatrix ^ s := rfl -/-- Matrix logarithm of a density matrix: `log ρ = U diag(log λᵢ) U*`. - Computed via the spectral decomposition of `ρ`. -/ +/-- Matrix logarithm of a density matrix: `log ρ = U diag(log λᵢ) U*`, +Mathlib's continuous functional calculus applied to `Real.log`. -/ noncomputable def log (ρ : DensityMatrix n) : Matrix n n ℂ := - matrixLog ↑ρ ρ.isHermitian + cfc Real.log ↑ρ /-- The product `ρ * log ρ` is Hermitian. Both factors are Hermitian and commute because `log ρ` is a matrix function of `ρ`. -/ lemma mul_log_isHermitian (ρ : DensityMatrix n) : (ρ.toMatrix * log ρ).IsHermitian := by - simpa [DensityMatrix.log] using - (mul_matrixFunction_isHermitian ρ.isHermitian Real.log) + unfold log + exact mul_cfc_isHermitian ρ.isHermitian Real.log /-- Convex combination of two density matrices is a density matrix. -/ noncomputable def mix (ρ₁ ρ₂ : DensityMatrix n) From 110cd4cd11d6145c3b6b0b504fa7c42fe416318c Mon Sep 17 00:00:00 2001 From: suzuki Date: Wed, 24 Jun 2026 15:10:54 +0000 Subject: [PATCH 016/113] refactor: regroup strong subadditivity modules Rename the two strong-subadditivity files into a self-describing family so the two settings of the same theorem are clear at a glance, and drop the removed lean-eval layer: - SSA.lean -> StrongSubadditivityLocalNet.lean - SSAProduct.lean -> StrongSubadditivityProduct.lean - remove StrongSubadditivityEval.lean (and its aggregate import) The LocalNet theorem gains a symmetric setting suffix (vonNeumannEntropy_SSA -> vonNeumannEntropy_SSA_localNet), matching the existing _product suffix, and each module docstring now cross-references its companion. Aggregate regenerated via scripts/mk_all.lean. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 5 +- .../Entropy/StrongSubadditivityEval.lean | 252 ------------------ ....lean => StrongSubadditivityLocalNet.lean} | 28 +- ...t.lean => StrongSubadditivityProduct.lean} | 10 +- 4 files changed, 21 insertions(+), 274 deletions(-) delete mode 100644 QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean rename QuantumSystem/Analysis/Entropy/{SSA.lean => StrongSubadditivityLocalNet.lean} (96%) rename QuantumSystem/Analysis/Entropy/{SSAProduct.lean => StrongSubadditivityProduct.lean} (98%) diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 219b006..eba3de8 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -31,9 +31,8 @@ public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.MutualInfoProduct public import QuantumSystem.Analysis.Entropy.Regularize public import QuantumSystem.Analysis.Entropy.RelativeEntropy -public import QuantumSystem.Analysis.Entropy.SSA -public import QuantumSystem.Analysis.Entropy.SSAProduct -public import QuantumSystem.Analysis.Entropy.StrongSubadditivityEval +public import QuantumSystem.Analysis.Entropy.StrongSubadditivityLocalNet +public import QuantumSystem.Analysis.Entropy.StrongSubadditivityProduct public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy public import QuantumSystem.Analysis.Matrix.Effros public import QuantumSystem.Analysis.Matrix.HermitianFunctionalCalculus diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean deleted file mode 100644 index 900ab9a..0000000 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityEval.lean +++ /dev/null @@ -1,252 +0,0 @@ -module - -public import QuantumSystem.Analysis.Entropy.SSAProduct -public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PosDef - -/-! -# Strong subadditivity in the `lean-eval` formulation - -This file reproduces the statement of strong subadditivity of the von Neumann entropy as posed in -[`lean-eval`](https://github.com/leanprover/lean-eval) (`LeanEval/Physics/StrongSubadditivity.lean`) -and proves it by reducing to the project's `DensityMatrix.vonNeumannEntropy_SSA`. - -The `lean-eval` problem states, for a tripartite **positive semidefinite** matrix `M_ABC` -(deliberately *not* normalised — normalisation is a positive affine transformation on the entropy): - - `entropy M_ABC + entropy M_B ≤ entropy M_AB + entropy M_BC`, - -where `entropy M = -Re (Tr (M * cfc Real.log M))` and the marginals are the positional partial -traces `Matrix.traceLeft`/`Matrix.traceRight`. - -## Bridge to the project's entropy - -The project's `Matrix.vonNeumannEntropy` is defined for a `DensityMatrix` via `DensityMatrix.log`, -i.e. Mathlib's `cfc Real.log`. The lemma -`LeanEval.Physics.entropy_toMatrix_eq_vonNeumannEntropy` records that the two notions of -entropy coincide on a density matrix. --/ - -@[expose] public section - -open Matrix -open scoped Matrix.QuantumInfo ComplexOrder MatrixOrder - -namespace LeanEval - -namespace Physics - -variable {n : Type*} [Fintype n] [DecidableEq n] - -/-- Von Neumann entropy of a quantum state (the `lean-eval` definition, via Mathlib's continuous -functional calculus). -/ -noncomputable def entropy (M : Matrix n n ℂ) : ℝ := - -Complex.re (Matrix.trace (M * cfc Real.log M)) - -/-- On a density matrix the `lean-eval` `entropy` coincides with the project's -`Matrix.vonNeumannEntropy`. -/ -theorem entropy_toMatrix_eq_vonNeumannEntropy (ρ : DensityMatrix n) : - entropy ρ.toMatrix = S(ρ) := by - rw [entropy, Matrix.vonNeumannEntropy, DensityMatrix.log] - rfl - -/-- The `lean-eval` `entropy` of a positive semidefinite matrix equals the spectral sum -`∑ᵢ negMulLog λᵢ`, with `Real.negMulLog 0 = 0` accounting for the kernel. Valid for any PSD -matrix (not necessarily normalised). -/ -theorem entropy_eq_negMulLog_sum (M : Matrix n n ℂ) (hM : M.PosSemidef) : - entropy M = ∑ i, Real.negMulLog (hM.1.eigenvalues i) := by - rw [entropy, trace_mul_cfc hM.1, - Complex.re_sum, ← Finset.sum_neg_distrib] - refine Finset.sum_congr rfl (fun i _ => ?_) - rw [← Complex.ofReal_mul, Complex.ofReal_re, Real.negMulLog] - ring - -/-- The entropy of the zero matrix is `0`. -/ -@[simp] theorem entropy_zero : entropy (0 : Matrix n n ℂ) = 0 := by - rw [entropy] - simp - -/-- A real-valued function is continuous on any finite set (the subspace topology is discrete). -/ -private lemma continuousOn_of_finite {s : Set ℝ} (hs : s.Finite) (g : ℝ → ℝ) : - ContinuousOn g s := by - rw [continuousOn_iff_continuous_restrict] - have : Finite s := hs.to_subtype - exact continuous_of_discreteTopology - -/-- The real spectrum of a Hermitian matrix is finite. -/ -private lemma spectrum_real_finite {N : Matrix n n ℂ} (hN : N.IsHermitian) : - (spectrum ℝ N).Finite := by - rw [hN.spectrum_real_eq_range_eigenvalues] - exact Set.finite_range _ - -/-- The real part of the trace of a Hermitian matrix is the sum of its eigenvalues. -/ -private lemma trace_re_eq_sum_eigenvalues {N : Matrix n n ℂ} (hN : N.IsHermitian) : - (N.trace).re = ∑ i, hN.eigenvalues i := by - have h : N.trace = ∑ i, ((hN.eigenvalues i : ℝ) : ℂ) := by - have hsa : IsSelfAdjoint N := hN - conv_lhs => rw [← cfc_id' (R := ℝ) (a := N) hsa] - rw [trace_cfc hN] - rw [h, Complex.re_sum] - simp - -/-- **Scale law for the entropy.** For `c > 0` and a positive semidefinite matrix `N`, -`entropy (c • N) = c · entropy N − c · log c · Tr N`. With `c = Tr N` this expresses the -normalisation of an unnormalised state as a positive affine transformation on the entropy. -/ -theorem entropy_smul {c : ℝ} (hc : 0 < c) {N : Matrix n n ℂ} (hN : N.PosSemidef) : - entropy (c • N) = c * entropy N - c * Real.log c * (N.trace).re := by - have hsa : IsSelfAdjoint N := hN.1 - have hf_cont : ContinuousOn (fun x => c * x) (spectrum ℝ N) := - (continuous_const.mul continuous_id).continuousOn - have hlog_cont : ContinuousOn Real.log ((fun x => c * x) '' spectrum ℝ N) := - continuousOn_of_finite ((spectrum_real_finite hN.1).image _) _ - have hgc_cont : ContinuousOn (fun x => Real.log (c * x)) (spectrum ℝ N) := - continuousOn_of_finite (spectrum_real_finite hN.1) _ - have hCN : (c • N : Matrix n n ℂ) = cfc (fun x => c * x) N := by - rw [cfc_const_mul (R := ℝ) c (fun x => x) N, cfc_id' (R := ℝ) (a := N) hsa] - have hlogCN : cfc Real.log (c • N) = cfc (fun x => Real.log (c * x)) N := by - conv_lhs => rw [hCN] - rw [← cfc_comp Real.log (fun x => c * x) N hsa hlog_cont hf_cont] - rfl - have hprod : (c • N) * cfc Real.log (c • N) = - cfc (fun x => (c * x) * Real.log (c * x)) N := by - rw [hlogCN, hCN, ← cfc_mul (fun x => c * x) (fun x => Real.log (c * x)) N hf_cont hgc_cont] - rw [entropy, hprod, trace_cfc hN.1, - Complex.re_sum, entropy_eq_negMulLog_sum N hN, - trace_re_eq_sum_eigenvalues hN.1, Finset.mul_sum, Finset.mul_sum, - ← Finset.sum_sub_distrib, ← Finset.sum_neg_distrib] - refine Finset.sum_congr rfl (fun i _ => ?_) - simp only [Complex.ofReal_re] - rw [Real.negMulLog] - rcases eq_or_lt_of_le (hN.1.posSemidef_iff_eigenvalues_nonneg.mp hN i) with h0 | hpos - · rw [← h0]; simp - · rw [Real.log_mul (ne_of_gt hc) (ne_of_gt hpos)]; ring - - -/-! ### Reduction to independent universes and to positive semidefinite matrices - -The `lean-eval` statement allows the three factors `A`, `B`, `C` to live in independent universes, -and works with an arbitrary positive semidefinite matrix (not necessarily a normalised state). -We reduce it to `strong_subadditivity_density` (same universe, normalised) in two steps: -`ULift`-reindexing into a common universe, then normalisation via the entropy scale law. -/ - -section Independent - -universe uA uB uC - -variable {A : Type uA} {B : Type uB} {C : Type uC} - [Fintype A] [DecidableEq A] [Nonempty A] - [Fintype B] [DecidableEq B] [Nonempty B] - [Fintype C] [DecidableEq C] [Nonempty C] - -/-- **Strong subadditivity of the von Neumann entropy** (the `lean-eval` statement). For any -positive semidefinite `M_ABC` on `A × B × C`, -`S(M_ABC) + S(M_B) ≤ S(M_AB) + S(M_BC)`, where the marginals are obtained by partial traces. -The proof normalises `M_ABC` to a state via the entropy scale law and invokes the -`LocalNet`-free product-form core `DensityMatrix.vonNeumannEntropy_SSA_product`. -/ -theorem strong_subadditivity (M_ABC : Matrix (A × B × C) (A × B × C) ℂ) (h : M_ABC.PosSemidef) : - let M_AB : Matrix (A × B) (A × B) ℂ := - Matrix.traceRight (M_ABC.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) - let M_BC : Matrix (B × C) (B × C) ℂ := M_ABC.traceLeft - let M_B : Matrix B B ℂ := M_BC.traceRight - entropy M_ABC + entropy M_B ≤ entropy M_AB + entropy M_BC := by - intro M_AB M_BC M_B - have htr_nn : (0 : ℂ) ≤ M_ABC.trace := h.trace_nonneg - have ht_re : (0 : ℝ) ≤ (M_ABC.trace).re := (Complex.nonneg_iff.mp htr_nn).1 - have ht_im : (M_ABC.trace).im = 0 := (Complex.nonneg_iff.mp htr_nn).2.symm - have htrace_real : M_ABC.trace = (((M_ABC.trace).re : ℝ) : ℂ) := by - apply Complex.ext <;> simp [ht_im] - rcases eq_or_lt_of_le ht_re with ht0 | ht_pos - · -- `Tr M_ABC = 0` forces `M_ABC = 0`; all marginals and entropies vanish. - have hM0 : M_ABC = 0 := by rw [← h.trace_eq_zero_iff, htrace_real, ← ht0]; simp - simp [M_AB, M_BC, M_B, hM0, Matrix.reindex_apply, entropy_zero] - · -- Normalise `M_ABC = t • ρ` with `ρ` a state, then apply the density-matrix version. - set t : ℝ := (M_ABC.trace).re with ht_def - have htr_smul : Tr ((t⁻¹ : ℝ) • M_ABC) = (t⁻¹ : ℝ) • Tr M_ABC := by - simp only [Matrix.trace, Matrix.diag_apply, Matrix.smul_apply] - exact Finset.smul_sum.symm - have ρtrace : Tr ((t⁻¹ : ℝ) • M_ABC) = 1 := by - rw [htr_smul, htrace_real, Complex.real_smul, ← Complex.ofReal_mul, - inv_mul_cancel₀ (ne_of_gt ht_pos), Complex.ofReal_one] - let ρ : DensityMatrix (A × B × C) := - ⟨(t⁻¹ : ℝ) • M_ABC, Matrix.posSemidef_smul_nonneg (inv_nonneg.mpr ht_re) h, ρtrace⟩ - have hMeq : M_ABC = t • ρ.toMatrix := (smul_inv_smul₀ (ne_of_gt ht_pos) M_ABC).symm - have hρ_tr : (ρ.toMatrix.trace).re = 1 := by rw [ρ.trace_eq_one]; simp - -- Each marginal of `M_ABC` is `t` times the corresponding marginal of `ρ`. - have hM_B : M_B = t • Matrix.traceRight (Matrix.traceLeft ρ.toMatrix) := by - calc - Matrix.traceRight (Matrix.traceLeft M_ABC) - = Matrix.traceRight (Matrix.traceLeft (t • ρ.toMatrix)) := by rw [hMeq] - _ = Matrix.traceRight (t • Matrix.traceLeft ρ.toMatrix) := by - rw [show Matrix.traceLeft (t • ρ.toMatrix) = t • Matrix.traceLeft ρ.toMatrix from by - exact Matrix.traceLeft_smul (l := B × C) (n := A) t ρ.toMatrix] - _ = t • Matrix.traceRight (Matrix.traceLeft ρ.toMatrix) := by - exact Matrix.traceRight_smul (l := B) (n := C) t (Matrix.traceLeft ρ.toMatrix) - have hM_BC : M_BC = t • Matrix.traceLeft ρ.toMatrix := by - calc - Matrix.traceLeft M_ABC = Matrix.traceLeft (t • ρ.toMatrix) := by rw [hMeq] - _ = t • Matrix.traceLeft ρ.toMatrix := by - exact Matrix.traceLeft_smul (l := B × C) (n := A) t ρ.toMatrix - have hM_AB : M_AB = t • Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm) := by - have hrs : (t • ρ.toMatrix).reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm - = t • ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm := by - ext p q; simp [Matrix.reindex_apply, Matrix.submatrix_apply] - calc - Matrix.traceRight (M_ABC.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) - = Matrix.traceRight ((t • ρ.toMatrix).reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm) := by rw [hMeq] - _ = Matrix.traceRight (t • ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm) := by rw [hrs] - _ = t • Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm) := by - exact Matrix.traceRight_smul (l := A × B) (n := C) t - (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) - -- Positive semidefiniteness and unit trace of the `ρ`-marginals (for the scale law). - have hρB : (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)).PosSemidef := - Matrix.traceRight_posSemidef (Matrix.traceLeft_posSemidef ρ.posSemidef) - have hρB_tr : (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)).trace.re = 1 := by - rw [Matrix.trace_traceRight, Matrix.trace_traceLeft, ρ.trace_eq_one]; simp - have hρBC : (Matrix.traceLeft ρ.toMatrix).PosSemidef := Matrix.traceLeft_posSemidef ρ.posSemidef - have hρBC_tr : (Matrix.traceLeft ρ.toMatrix).trace.re = 1 := by - rw [Matrix.trace_traceLeft, ρ.trace_eq_one]; simp - have hρAB : (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm)).PosSemidef := - Matrix.traceRight_posSemidef ((Matrix.posSemidef_submatrix_equiv _).mpr ρ.posSemidef) - have hρAB_tr : (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm)).trace.re = 1 := by - rw [Matrix.trace_traceRight, Matrix.trace_reindex_self, ρ.trace_eq_one]; simp - -- Scale law on each entropy. - have key_ABC : entropy M_ABC = t * entropy ρ.toMatrix - t * Real.log t := by - rw [congrArg entropy hMeq, entropy_smul ht_pos ρ.posSemidef, hρ_tr]; ring - have key_B : entropy M_B - = t * entropy (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)) - t * Real.log t := by - rw [hM_B, entropy_smul ht_pos hρB, hρB_tr]; ring - have key_BC : entropy M_BC - = t * entropy (Matrix.traceLeft ρ.toMatrix) - t * Real.log t := by - rw [hM_BC, entropy_smul ht_pos hρBC, hρBC_tr]; ring - have key_AB : entropy M_AB - = t * entropy (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm)) - t * Real.log t := by - rw [hM_AB, entropy_smul ht_pos hρAB, hρAB_tr]; ring - rw [key_ABC, key_B, key_AB, key_BC] - -- The density-matrix SSA in `entropy` form, obtained directly from the product-form core. - have hSSA : entropy ρ.toMatrix + entropy (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)) - ≤ entropy (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm)) + entropy (Matrix.traceLeft ρ.toMatrix) := by - have e_full : entropy ρ.toMatrix = S(ρ) := entropy_toMatrix_eq_vonNeumannEntropy ρ - have e_B : entropy (Matrix.traceRight (Matrix.traceLeft ρ.toMatrix)) - = S(ρ.ptLeft.ptRight) := entropy_toMatrix_eq_vonNeumannEntropy ρ.ptLeft.ptRight - have e_BC : entropy (Matrix.traceLeft ρ.toMatrix) = S(ρ.ptLeft) := - entropy_toMatrix_eq_vonNeumannEntropy ρ.ptLeft - have e_AB : entropy (Matrix.traceRight (ρ.toMatrix.reindex (Equiv.prodAssoc A B C).symm - (Equiv.prodAssoc A B C).symm)) = S((ρ.mapEquiv (Equiv.prodAssoc A B C)).ptRight) := by - simp only [Matrix.reindex_apply, Equiv.symm_symm] - exact entropy_toMatrix_eq_vonNeumannEntropy ((ρ.mapEquiv (Equiv.prodAssoc A B C)).ptRight) - rw [e_full, e_B, e_AB, e_BC] - exact DensityMatrix.vonNeumannEntropy_SSA_product ρ _ _ _ rfl rfl rfl - nlinarith [mul_le_mul_of_nonneg_left hSSA ht_pos.le] - -end Independent - -end Physics - -end LeanEval diff --git a/QuantumSystem/Analysis/Entropy/SSA.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean similarity index 96% rename from QuantumSystem/Analysis/Entropy/SSA.lean rename to QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean index 7266842..ac2406c 100644 --- a/QuantumSystem/Analysis/Entropy/SSA.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean @@ -1,11 +1,8 @@ module -public import QuantumSystem.Analysis.Entropy.KroneckerProduct -public import QuantumSystem.Analysis.Entropy.RelativeEntropy +public import QuantumSystem.Analysis.Entropy.MutualInfoProduct public import QuantumSystem.Analysis.Entropy.Regularize -public import QuantumSystem.Analysis.Matrix.PartialTrace public import QuantumSystem.Analysis.Matrix.KroneckerPartialTraceBridge -public import QuantumSystem.Analysis.Entropy.MutualInfoProduct /-! # Strong subadditivity of the von Neumann entropy (LocalNet form) @@ -57,9 +54,12 @@ AQFT-natural form: * `Matrix.relativeEntropy_kronecker_marginals_product` — product-type mutual-information identity. -* `DensityMatrix.vonNeumannEntropy_SSA` — SSA for arbitrary states on a +* `DensityMatrix.vonNeumannEntropy_SSA_localNet` — SSA for arbitrary states on a `LocalNet`, with the common region and split equalities explicit. +The same inequality on a plain tensor product `A × B × C` is the companion +`DensityMatrix.vonNeumannEntropy_SSA_product` (`StrongSubadditivityProduct.lean`). + ## References * Nielsen, Chuang, *Quantum Computation and Quantum Information* §11.3 — quantum mutual @@ -100,7 +100,7 @@ Given nested regions `ΛA ⊆ ΛAB ⊆ ΛABC`, write the middle/common region as This statement contains the split subset in the hypotheses and does not rely on site names such as `a b c` or product-factor names such as `A/B`. -/ -private lemma vonNeumannEntropy_SSA_posDef_nested +private lemma vonNeumannEntropy_SSA_localNet_posDef_nested {L : LocalNet} {ΛA ΛAB ΛABC : Finset L.sites} (h_AB : ΛAB ⊆ ΛABC) (h_A : ΛA ⊆ ΛAB) (ρ_ABC : L.densityMatrix ΛABC) @@ -325,7 +325,7 @@ private lemma vonNeumannEntropy_SSA_posDef_nested For two `Λ ⊆ Λ_total` and `Λ' ⊆ Λ_total` Subset proofs whose Finsets are propositionally equal (`Λ = Λ'`), the partial-trace `restrict h ρ` and `restrict h' ρ` are essentially identical: their entropies and PosDef status agree. Discharged by `subst h_eq` plus -proof-irrelevance for `Subset`. Used in `vonNeumannEntropy_SSA_posDef` to bridge +proof-irrelevance for `Subset`. Used in `vonNeumannEntropy_SSA_localNet_posDef` to bridge user-facing `S(restrict h_BC ρ)` (with `{b,c}`) to the bipartite-natural form `S(restrict sdiff_subset ρ)` (with `{a,b,c} \ {a}`). -/ @@ -346,7 +346,7 @@ private lemma posDef_restrict_finset_eq /-- **Strong subadditivity (PosDef case, common-region-explicit form).** This is the public region-level wrapper around -`vonNeumannEntropy_SSA_posDef_nested`. The theorem does not infer the common region from +`vonNeumannEntropy_SSA_localNet_posDef_nested`. The theorem does not infer the common region from the names `a b c` or from a product-factor order. Instead it receives explicit data: * `ΛAB ⊆ ΛABC`, the first two-block marginal, @@ -358,7 +358,7 @@ the names `a b c` or from a product-factor order. Instead it receives explicit d Under PosDef hypotheses for the displayed marginals, the conclusion is exactly `S(ρ_ABC ↾ ΛAB) + S(ρ_ABC ↾ ΛBC) ≥ S(ρ_ABC) + S(ρ_ABC ↾ ΛB)`. -/ -private lemma vonNeumannEntropy_SSA_posDef +private lemma vonNeumannEntropy_SSA_localNet_posDef {L : LocalNet} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} (h_AB_total : ΛAB ⊆ ΛABC) (h_A_in_AB : ΛA ⊆ ΛAB) (h_BC_total : ΛBC ⊆ ΛABC) (h_B_total : ΛB ⊆ ΛABC) @@ -379,7 +379,7 @@ private lemma vonNeumannEntropy_SSA_posDef posDef_restrict_finset_eq h_BC_eq.symm h_BC_total Finset.sdiff_subset ρ_ABC |>.mp h_BC_pos have h_B_pos_nested : (ρ_ABC ↾[h_B_nested]).toMatrix.PosDef := posDef_restrict_finset_eq h_B_eq.symm h_B_total h_B_nested ρ_ABC |>.mp h_B_pos - have h_nested := vonNeumannEntropy_SSA_posDef_nested h_AB_total h_A_in_AB ρ_ABC h_ABC_pos + have h_nested := vonNeumannEntropy_SSA_localNet_posDef_nested h_AB_total h_A_in_AB ρ_ABC h_ABC_pos h_A_pos h_AB_pos h_BC_pos_nested h_B_pos_nested have h_S_BC : S(ρ_ABC ↾[h_BC_total]) = S(ρ_ABC ↾[(Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)]) := @@ -392,7 +392,7 @@ private lemma vonNeumannEntropy_SSA_posDef /-- **Strong subadditivity (common-region-explicit form, no PosDef hypothesis).** -PosDef-free version of `vonNeumannEntropy_SSA_posDef`. Given the geometric data of a +PosDef-free version of `vonNeumannEntropy_SSA_localNet_posDef`. Given the geometric data of a common-region split * `ΛAB ⊆ ΛABC`, `ΛA ⊆ ΛAB`, `ΛBC ⊆ ΛABC`, `ΛB ⊆ ΛABC`, @@ -405,9 +405,9 @@ and `[Nonempty (L.regionIdx ΛABC)]` (which propagates to every sub-region by `S(ρ_ABC ↾ ΛAB) + S(ρ_ABC ↾ ΛBC) ≥ S(ρ_ABC) + S(ρ_ABC ↾ ΛB)`. The proof regularises `ρ` to the PosDef state `(1 - ε) ρ + ε · π_ΛABC` for `ε ∈ (0, 1]`, -applies `vonNeumannEntropy_SSA_posDef`, and passes to the limit `ε → 0⁺` +applies `vonNeumannEntropy_SSA_localNet_posDef`, and passes to the limit `ε → 0⁺` via the eigenvalue continuity formulas in `Regularize.lean`. -/ -theorem vonNeumannEntropy_SSA +theorem vonNeumannEntropy_SSA_localNet {L : LocalNet} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} (h_AB : ΛAB ⊆ ΛABC) (h_A : ΛA ⊆ ΛAB) (h_BC : ΛBC ⊆ ΛABC) (h_B : ΛB ⊆ ΛABC) @@ -478,7 +478,7 @@ theorem vonNeumannEntropy_SSA change (Matrix.restrict h_B (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).toMatrix).PosDef rw [h_B_eq_reg]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le - have h_ssa := vonNeumannEntropy_SSA_posDef + have h_ssa := vonNeumannEntropy_SSA_localNet_posDef h_AB h_A h_BC h_B h_B_eq h_BC_eq (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) hρ_reg_pos hA_reg_pos hAB_reg_pos hBC_reg_pos hB_reg_pos diff --git a/QuantumSystem/Analysis/Entropy/SSAProduct.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean similarity index 98% rename from QuantumSystem/Analysis/Entropy/SSAProduct.lean rename to QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean index ee4a876..c2d4876 100644 --- a/QuantumSystem/Analysis/Entropy/SSAProduct.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean @@ -1,7 +1,7 @@ module -public import QuantumSystem.Analysis.Entropy.MutualInfoProduct public import QuantumSystem.Analysis.Channel.PartialTrace +public import QuantumSystem.Analysis.Entropy.MutualInfoProduct /-! # Strong subadditivity of the von Neumann entropy (product form, LocalNet-free) @@ -16,9 +16,9 @@ net: the proof is the bare finite-dimensional quantum-information argument 2. the data-processing inequality `Matrix.relativeEntropy_channel_le` for the trace-out-`C` channel `Matrix.QuantumChannel.traceOutC`. -The `lean-eval` density-matrix statement `LeanEval.Physics.strong_subadditivity_density` is then a -direct corollary (in `StrongSubadditivityEval.lean`), replacing the previous reduction through the -three-site `LocalNet`. +The `LocalNet`/AQFT companion — the same inequality stated over an abstract local net with +overlapping regions — is `DensityMatrix.vonNeumannEntropy_SSA_localNet` +(`StrongSubadditivityLocalNet.lean`). ## Main results @@ -120,7 +120,7 @@ variable {A B C : Type*} [Fintype A] [DecidableEq A] [Fintype B] [DecidableEq B] /-- **Strong subadditivity (product form, positive definite case).** For a positive definite density matrix `ρ` on `A × B × C`, with all four marginals positive definite, `S(ρ) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC)`. -/ -theorem vonNeumannEntropy_SSA_product_posDef +private lemma vonNeumannEntropy_SSA_product_posDef (ρ_ABC : DensityMatrix (A × B × C)) (ρ_A : DensityMatrix A) (ρ_AB : DensityMatrix (A × B)) (ρ_BC : DensityMatrix (B × C)) (ρ_B : DensityMatrix B) From e84c67529069bc3dcf77b877ff99451567ce4a1c Mon Sep 17 00:00:00 2001 From: suzuki Date: Wed, 24 Jun 2026 15:11:07 +0000 Subject: [PATCH 017/113] refactor: replace bespoke entropyFun with Mathlib Real.negMulLog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit entropyFun (= -x log x, guarded at x ≤ 0) duplicated Mathlib's Real.negMulLog, which the file already bridged. Drop entropyFun, entropyFun_nonneg, entropyFun_eq_negMulLog_of_nonneg and the entropyFun-sum form vonNeumannEntropy_eq_sum; route everything through vonNeumannEntropy_eq_negMulLog_sum (now proved directly from trace_mul_cfc) and the Mathlib lemma Real.negMulLog_nonneg. Also list the previously-undocumented fundamental results in the Main Results sections: von Neumann entropy eigenvalue-sum / nonneg / le_log_dim, and relative entropy Klein nonneg / faithfulness. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Analysis/Entropy/RelativeEntropy.lean | 3 + .../Analysis/Entropy/VonNeumannEntropy.lean | 91 +++++-------------- 2 files changed, 24 insertions(+), 70 deletions(-) diff --git a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean index 2cd1473..a28da44 100644 --- a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean @@ -13,6 +13,9 @@ This file collects fundamental entropy inequalities for quantum channels. ## Main Results +* `relativeEntropy_nonneg`: Klein's inequality — relative entropy is non-negative, + `0 ≤ D(ρ ‖ σ)`. +* `relativeEntropy_eq_zero_iff`: faithfulness — `D(ρ ‖ σ) = 0 ↔ ρ = σ`. * `relativeEntropy_channel_le`: Monotonicity of relative entropy — quantum channels do not increase relative entropy: S(Φ(ρ) ‖ Φ(σ)) ≤ S(ρ ‖ σ). * `relativeEntropy_channel_eq_iff_recoverable`: Equality in monotonicity holds when a Petz diff --git a/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean b/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean index a31dfc0..d0a4fcb 100644 --- a/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean @@ -12,6 +12,9 @@ This file contains definitions and core properties of von Neumann entropy. ## Main Results +* `vonNeumannEntropy_eq_negMulLog_sum`: eigenvalue-sum form `S(ρ) = ∑ᵢ negMulLog λᵢ`. +* `vonNeumannEntropy_nonneg`: Von Neumann entropy is non-negative, `0 ≤ S(ρ)`. +* `vonNeumannEntropy_le_log_dim`: Von Neumann entropy is bounded by `log (dim)`. * `vonNeumannEntropy_concave`: Von Neumann entropy is concave. -/ @@ -23,19 +26,6 @@ open scoped MatrixOrder ComplexOrder QuantumInfo variable {n : Type*} [Fintype n] [DecidableEq n] -/-- The entropy function η(x) = -x log x, extended by continuity to η(0) = 0. -This is concave on [0, ∞). -/ -noncomputable def entropyFun (x : ℝ) : ℝ := - if x ≤ 0 then 0 else -x * Real.log x - -theorem entropyFun_nonneg {x : ℝ} (hx : 0 ≤ x) (hx1 : x ≤ 1) : 0 ≤ entropyFun x := by - unfold entropyFun - split_ifs with hle - · exact le_refl 0 - · push Not at hle - have hlog : Real.log x ≤ 0 := Real.log_nonpos hx hx1 - nlinarith [hle, hlog] - /-- Von Neumann entropy of a density matrix: S(ρ) = −Tr (ρ log ρ). Since ρ log ρ is Hermitian (see `DensityMatrix.mul_log_isHermitian`), its trace is real, so `.re` is lossless (see `vonNeumannEntropy_ofReal`). -/ @@ -55,39 +45,18 @@ theorem vonNeumannEntropy_ofReal (ρ : DensityMatrix n) : congr 1 exact ρ.mul_log_isHermitian.trace_ofReal_re -/-- Von Neumann entropy equals the eigenvalue sum S(ρ) = ∑ᵢ (−λᵢ log λᵢ). -/ -theorem vonNeumannEntropy_eq_sum (ρ : DensityMatrix n) : - S(ρ) = ∑ i, entropyFun (ρ.isHermitian.eigenvalues i) := by +/-- `vonNeumannEntropy ρ = ∑ᵢ Real.negMulLog (ρ.eigenvalues i)`, the eigenvalue-sum form +in terms of Mathlib's `Real.negMulLog`. -/ +theorem vonNeumannEntropy_eq_negMulLog_sum (ρ : DensityMatrix n) : + vonNeumannEntropy ρ = ∑ i, Real.negMulLog (ρ.isHermitian.eigenvalues i) := by unfold vonNeumannEntropy DensityMatrix.log change -(Tr (ρ.toMatrix * cfc Real.log ρ.toMatrix)).re = _ rw [trace_mul_cfc ρ.isHermitian, Complex.re_sum] simp_rw [← Complex.ofReal_mul, Complex.ofReal_re, ← Finset.sum_neg_distrib] congr 1 ext i - unfold entropyFun - split_ifs with hle - · have h0 := le_antisymm hle (ρ.eigenvalues_nonneg i) - simp [h0] - · ring - -/-- For `x ≥ 0`, `entropyFun x = Real.negMulLog x`. -/ -theorem entropyFun_eq_negMulLog_of_nonneg {x : ℝ} (hx : 0 ≤ x) : - entropyFun x = Real.negMulLog x := by - unfold entropyFun Real.negMulLog - split_ifs with h - · have h0 : x = 0 := le_antisymm h hx - rw [h0]; ring - · rfl - -/-- `vonNeumannEntropy ρ = ∑ᵢ Real.negMulLog (ρ.eigenvalues i)`. - -Since `ρ` is PSD, its eigenvalues are non-negative, so `entropyFun = Real.negMulLog` -on the sum range. -/ -theorem vonNeumannEntropy_eq_negMulLog_sum (ρ : DensityMatrix n) : - vonNeumannEntropy ρ = ∑ i, Real.negMulLog (ρ.isHermitian.eigenvalues i) := by - rw [vonNeumannEntropy_eq_sum] - refine Finset.sum_congr rfl fun i _ => ?_ - exact entropyFun_eq_negMulLog_of_nonneg (ρ.eigenvalues_nonneg i) + simp only [Real.negMulLog] + ring /-- `vonNeumannEntropy` expressed via Mathlib's continuous functional calculus `cfc` applied to `Real.negMulLog`, enabling continuity arguments. -/ @@ -101,25 +70,16 @@ theorem vonNeumannEntropy_eq_cfc_re (ρ : DensityMatrix n) : /-- Von Neumann entropy is non-negative. -/ theorem vonNeumannEntropy_nonneg (ρ : DensityMatrix n) : 0 ≤ S(ρ) := by - rw [vonNeumannEntropy_eq_sum] + rw [vonNeumannEntropy_eq_negMulLog_sum] apply Finset.sum_nonneg intro i _ - exact entropyFun_nonneg (ρ.eigenvalues_nonneg i) (ρ.eigenvalue_le_one i) + exact Real.negMulLog_nonneg (ρ.eigenvalues_nonneg i) (ρ.eigenvalue_le_one i) /-- Von Neumann entropy is at most log(dim), achieved for the maximally mixed state. This follows from Jensen's inequality applied to the concave function -x log x. -/ theorem vonNeumannEntropy_le_log_dim [Nonempty n] (ρ : DensityMatrix n) : S(ρ) ≤ Real.log (Fintype.card n) := by - rw [vonNeumannEntropy_eq_sum] - have heq : ∀ i, entropyFun (ρ.isHermitian.eigenvalues i) = - Real.negMulLog (ρ.isHermitian.eigenvalues i) := by - intro i - unfold entropyFun Real.negMulLog - split_ifs with hle - · have h0 : ρ.isHermitian.eigenvalues i = 0 := le_antisymm hle (ρ.eigenvalues_nonneg i) - simp [h0] - · rfl - simp_rw [heq] + rw [vonNeumannEntropy_eq_negMulLog_sum] have hlog_inv : Real.log (1 / Fintype.card n) = -Real.log (Fintype.card n) := by rw [one_div, Real.log_inv] have hunif_pos : ∀ i : n, 0 < 1 / (Fintype.card n : ℝ) := fun _ => by positivity @@ -309,34 +269,25 @@ theorem vonNeumannEntropy_concave (ρ₁ ρ₂ : DensityMatrix n) (p : ℝ) (hp deriv_nonpos_of_forall_lt_min g _ 1 (1 / 2) (by norm_num) hderiv_g hmin have hmix_eq : ∑ i, ρ_mix.isHermitian.eigenvalues i * Real.log (ρ_mix.isHermitian.eigenvalues i) = -vonNeumannEntropy ρ_mix := by - rw [vonNeumannEntropy_eq_sum, ← Finset.sum_neg_distrib] + rw [vonNeumannEntropy_eq_negMulLog_sum, ← Finset.sum_neg_distrib] congr 1 ext i - unfold entropyFun - split_ifs with h - · simp [le_antisymm h (ρ_mix.eigenvalues_nonneg i)] - · push Not at h - ring + simp only [Real.negMulLog] + ring have h₁_eq : ∑ i, ρ₁.isHermitian.eigenvalues i * Real.log (ρ₁.isHermitian.eigenvalues i) = -vonNeumannEntropy ρ₁ := by - rw [vonNeumannEntropy_eq_sum, ← Finset.sum_neg_distrib] + rw [vonNeumannEntropy_eq_negMulLog_sum, ← Finset.sum_neg_distrib] congr 1 ext i - unfold entropyFun - split_ifs with h - · simp [le_antisymm h (ρ₁.eigenvalues_nonneg i)] - · push Not at h - ring + simp only [Real.negMulLog] + ring have h₂_eq : ∑ i, ρ₂.isHermitian.eigenvalues i * Real.log (ρ₂.isHermitian.eigenvalues i) = -vonNeumannEntropy ρ₂ := by - rw [vonNeumannEntropy_eq_sum, ← Finset.sum_neg_distrib] + rw [vonNeumannEntropy_eq_negMulLog_sum, ← Finset.sum_neg_distrib] congr 1 ext i - unfold entropyFun - split_ifs with h - · simp [le_antisymm h (ρ₂.eigenvalues_nonneg i)] - · push Not at h - ring + simp only [Real.negMulLog] + ring rw [hmix_eq, h₁_eq, h₂_eq] at hderiv_g_nonpos linarith From d0281a724d08785e26339058dd214652a6e92d58 Mon Sep 17 00:00:00 2001 From: suzuki Date: Thu, 25 Jun 2026 12:47:31 +0000 Subject: [PATCH 018/113] refactor(localnet): split abstract LocalNet from SiteIndexSystem model Reify the Haag-Kastler net as a first-class abstract structure `LocalNet` (Net.lean): the region assignment with isotony embeddings, functoriality and locality, on which the directed system, the quasi-local algebra, the C-star completion for faithful nets, and the covariance symmetry group are built once and for all. The former concrete carrier (sites + finite local dimensions) is renamed `SiteIndexSystem` and becomes one instance via `SiteIndexSystem.toLocalNet`; its quasi-local algebra and cocone are now thin wrappers over the abstract net. Covariance is lifted to the abstract net: `LocalNet.Symmetry` forms a `Group` under composition with a monoid-homomorphic action `quasiLocalRelabel` on the local observables. Locality and faithfulness docstrings were refined (microcausality; injective inclusions as the standard non-degeneracy condition). Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 1 + QuantumSystem/Algebra/LocalNet/Basic.lean | 21 +- .../Algebra/LocalNet/Covariance.lean | 42 +- QuantumSystem/Algebra/LocalNet/Isotony.lean | 10 +- QuantumSystem/Algebra/LocalNet/Locality.lean | 10 +- QuantumSystem/Algebra/LocalNet/Net.lean | 458 ++++++++++++++++++ .../Algebra/LocalNet/QuasiLocal.lean | 251 ++++------ .../Algebra/LocalNet/TensorDecomposition.lean | 6 +- 8 files changed, 597 insertions(+), 202 deletions(-) create mode 100644 QuantumSystem/Algebra/LocalNet/Net.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index eba3de8..11c2530 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -21,6 +21,7 @@ public import QuantumSystem.Algebra.LocalNet.Basic public import QuantumSystem.Algebra.LocalNet.Covariance public import QuantumSystem.Algebra.LocalNet.Isotony public import QuantumSystem.Algebra.LocalNet.Locality +public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocal public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra diff --git a/QuantumSystem/Algebra/LocalNet/Basic.lean b/QuantumSystem/Algebra/LocalNet/Basic.lean index b0af94e..c0d98d5 100644 --- a/QuantumSystem/Algebra/LocalNet/Basic.lean +++ b/QuantumSystem/Algebra/LocalNet/Basic.lean @@ -7,10 +7,10 @@ public import QuantumSystem.Channel This file carries the **data** of a local net of matrix algebras and the region-index combinatorics on which the AQFT net properties are built. An AQFT system assigns to each -lattice region `Λ` an algebra `𝔄(Λ)` of observables; for finite-dimensional quantum spin +region `Λ` an algebra `𝔄(Λ)` of observables; for finite-dimensional site-index systems this specialises to: -- a lattice of **sites** `L` (an arbitrary type with `DecidableEq`), +- a **set of sites** `L` (an arbitrary type with `DecidableEq`; no order/geometric structure), - a finite local index type `ℂ^{n_x}` at each site `x`, - regions `Λ : Finset L.sites`, - local algebra `𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` realised as @@ -34,7 +34,8 @@ The net **properties** built on this data live in sibling modules: @[expose] public section -/-- Data for a **local net of matrix algebras** on a (possibly infinite) lattice of sites. +/-- Data for a **local net of matrix algebras** over a (possibly infinite) **set of sites** — an + arbitrary index type with no order or geometric lattice structure assumed. Each site `s : sites` carries a finite index type `localIdx s` whose cardinality is the local Hilbert-space dimension. The local algebra at a *finite* region `Λ : Finset sites` is then the matrix algebra on the dependent product `Π s ∈ Λ, localIdx s` — finite even @@ -42,8 +43,8 @@ The net **properties** built on this data live in sibling modules: (only `DecidableEq`) is what allows the quasi-local algebra to be a genuine inductive limit over the directed set of finite regions, as in Naaijkens 2012 §1.3 and Bratteli–Robinson Vol.2 §6.2. -/ -structure LocalNet where - /-- Lattice of sites — an arbitrary type; regions are its finite subsets. -/ +structure SiteIndexSystem where + /-- The set of sites — an arbitrary index type; regions are its finite subsets. -/ sites : Type* [sitesDecEq : DecidableEq sites] /-- Local Hilbert-space index type at each site. -/ @@ -51,11 +52,11 @@ structure LocalNet where [localFintype : ∀ s, Fintype (localIdx s)] [localDecEq : ∀ s, DecidableEq (localIdx s)] -namespace LocalNet +namespace SiteIndexSystem attribute [instance] sitesDecEq localFintype localDecEq -variable (L : LocalNet) +variable (L : SiteIndexSystem) /-- Index type of a region: dependent product of local indices over the sites in `Λ`. -/ abbrev regionIdx (Λ : Finset L.sites) : Type _ := ∀ s : Λ, L.localIdx s.val @@ -79,7 +80,7 @@ abbrev densityMatrix (Λ : Finset L.sites) : Type _ := /-- For `Λ ⊆ Λ_total`, the index type of the larger region splits as a product: `regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ regionIdx Λ_total`. This realises the tensor factorisation `ℋ_Λ_total = ℋ_Λ ⊗ ℋ_{Λ_total \ Λ}` underlying isotony and partial trace. - The factorisation is made formal at the operator level by `LocalNet.tensorEquiv` + The factorisation is made formal at the operator level by `SiteIndexSystem.tensorEquiv` (`TensorDecomposition`), an algebra isomorphism of the corresponding operator algebras. -/ def combineIdx {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : (L.regionIdx Λ × L.regionIdx (Λ_total \ Λ)) ≃ L.regionIdx Λ_total where @@ -149,7 +150,7 @@ Bipartite and tripartite factorisations of a region's index type over arbitrary `regionIdx {a, b} ≃ localIdx a × localIdx b` and the right-associated three-element analogue. Both are direct definitions with concrete `toFun`, so every projection evaluates by `rfl`. -/ -variable (L : LocalNet) +variable (L : SiteIndexSystem) /-- **1-element factorisation**: `regionIdx {a} ≃ localIdx a`. Evaluation at the single site `a`. -/ def regionIdxSingletonEquiv (a : L.sites) : @@ -326,4 +327,4 @@ theorem regionIdxPairEquiv_combineIdx {a b : L.sites} (hab : a ≠ b) have hba : b ∉ ({a} : Finset L.sites) := (Finset.mem_sdiff.mp hb).2 refine Prod.ext ?_ ?_ <;> simp [hba] -end LocalNet +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 74b7790..faefc16 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -5,7 +5,7 @@ public import QuantumSystem.Algebra.LocalNet.QuasiLocal /-! # Covariance of the local net -A **symmetry** of a `LocalNet` is a permutation `σ` of the sites together with, for each site, +A **symmetry** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each site, an equivalence `localIdx s ≃ localIdx (σ s)` matching the local dimensions. Such data induces a `*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` between the local algebras of a region and its image, realising the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σ Λ)` (Naaijkens 2012 §3.2, Verch 2025 §1.2). @@ -18,16 +18,16 @@ natural with respect to isotony (`relabelAlgebra_includeAlgebra`), so they assem @[expose] public section -namespace LocalNet +namespace SiteIndexSystem /-- Pointwise value of the complement projection of `combineIdx.symm` (holds by `rfl`). -/ -@[simp] theorem combineIdx_symm_snd_apply {L : LocalNet} {Λ Λ_total : Finset L.sites} +@[simp] theorem combineIdx_symm_snd_apply {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) (f : L.regionIdx Λ_total) (w : ↥(Λ_total \ Λ)) : ((L.combineIdx h).symm f).2 w = f ⟨w.val, (Finset.mem_sdiff.mp w.property).1⟩ := rfl /-- A symmetry of a local net: a site permutation together with dimension-matching equivalences on the local index types. A group acting on the net is a homomorphism into these. -/ -structure Symmetry (L : LocalNet) where +structure Symmetry (L : SiteIndexSystem) where /-- The underlying permutation of the sites. -/ σ : L.sites ≃ L.sites /-- Dimension matching: relabel the local index type at each site. -/ @@ -35,7 +35,7 @@ structure Symmetry (L : LocalNet) where namespace Symmetry -variable {L : LocalNet} (a : L.Symmetry) +variable {L : SiteIndexSystem} (a : L.Symmetry) /-- The image of a region under a symmetry. -/ def region (Λ : Finset L.sites) : Finset L.sites := Λ.map a.σ.toEmbedding @@ -135,23 +135,25 @@ theorem relabelAlgebra_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') /-! ### Covariance action on the quasi-local algebra -The per-region symmetry `*`-isomorphisms, being natural with respect to isotony, assemble into -a `*`-endomorphism of the algebra of local observables `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧`. -Well-definedness is exactly `relabelAlgebra_includeAlgebra`. This is the AQFT covariance action -on the (pre-completion) quasi-local algebra. -/ +The per-region symmetry `*`-isomorphisms, being natural with respect to isotony +(`relabelAlgebra_includeAlgebra`), assemble a symmetry `toLocalNetSymmetry` of the abstract net +`toLocalNet`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local +observables is therefore inherited from the net-level `LocalNet.Symmetry.quasiLocalRelabel`. -/ + +/-- The symmetry of the generated local net `toLocalNet` induced by a lattice symmetry: the same + site permutation, with the reindexing `*`-isomorphisms `relabelAlgebra` as its covariance maps + and `relabelAlgebra_includeAlgebra` as the isotony naturality. This exhibits the concrete + covariance as an instance of the abstract `LocalNet.Symmetry`. -/ +noncomputable def toLocalNetSymmetry : L.toLocalNet.Symmetry where + σ := a.σ + β := a.relabelAlgebra + β_incl h x := a.relabelAlgebra_includeAlgebra h x /-- The action of a symmetry on the algebra of local observables, as a ring homomorphism: - `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, relabel X⟩⟧`. Well-defined by net-covariance - (`relabelAlgebra_includeAlgebra`). -/ + `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, relabel X⟩⟧`. Inherited from the abstract net-level covariance action + `LocalNet.Symmetry.quasiLocalRelabel` on `toLocalNet`. -/ noncomputable def quasiLocalRelabel : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := - DirectLimit.Ring.lift (fun Λ : Finset L.sites => L.localAlgebra Λ) - (fun _ _ h => L.includeAlgebra h) L.quasiLocalAlgebra - (fun Λ => (L.ιLocal (a.region Λ)).comp - ((a.relabelAlgebra Λ).toAlgEquiv.toAlgHom.toRingHom)) - (fun Λ Λ' h X => by - simp only [RingHom.comp_apply, AlgHom.toRingHom_eq_coe, RingHom.coe_coe, - AlgEquiv.coe_algHom, StarAlgEquiv.coe_toAlgEquiv, a.relabelAlgebra_includeAlgebra h] - exact L.ιLocal_includeAlgebra _ _) + a.toLocalNetSymmetry.quasiLocalRelabel @[simp] theorem quasiLocalRelabel_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.relabelAlgebra Λ X⟩⟧ := @@ -159,4 +161,4 @@ noncomputable def quasiLocalRelabel : L.quasiLocalAlgebra →+* L.quasiLocalAlge end Symmetry -end LocalNet +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Isotony.lean b/QuantumSystem/Algebra/LocalNet/Isotony.lean index 8ddb87d..8368052 100644 --- a/QuantumSystem/Algebra/LocalNet/Isotony.lean +++ b/QuantumSystem/Algebra/LocalNet/Isotony.lean @@ -18,9 +18,9 @@ Pipeline: entry-wise underlying function `includeAlgebraFun` → algebraic ident @[expose] public section -namespace LocalNet +namespace SiteIndexSystem -variable (L : LocalNet) +variable (L : SiteIndexSystem) /-! ### Isotony embedding (algebra inclusion) -/ @@ -156,8 +156,8 @@ lemma includeAlgebraFun_algebraMap {Λ Λ_total : Finset L.sites} the complementary region. Realises the inclusion `A ↦ A ⊗ I_{Λ_total \ Λ}` from Naaijkens 2012 §1.3 line 211, Verch 2025 §1.2 axiom (i), Bratteli–Robinson Vol.2 §6.2. That this embedding is literally `A ↦ A ⊗ 1` of operators on Hilbert spaces is proved in - `LocalNet.opEquiv_includeAlgebra` (`TensorDecomposition`); the dual marginal is the partial - trace `LocalNet.opEquiv_restrict` (`PartialTraceOperator`). + `SiteIndexSystem.opEquiv_includeAlgebra` (`TensorDecomposition`); the dual marginal is the partial + trace `SiteIndexSystem.opEquiv_restrict` (`PartialTraceOperator`). Bundled as a unital `*`-algebra homomorphism so that `map_one`, `map_mul`, `map_star` are available via the `StarAlgHom` API. Entry-wise: `(includeAlgebra h X) s s' = X (combineIdx⁻¹ s).1 (combineIdx⁻¹ s').1` when the @@ -284,4 +284,4 @@ theorem includeAlgebra_refl_apply {Λ : Finset L.sites} (X : L.localAlgebra Λ) rw [includeAlgebra_apply, if_pos hc] rfl -end LocalNet +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Locality.lean b/QuantumSystem/Algebra/LocalNet/Locality.lean index e46d305..c973627 100644 --- a/QuantumSystem/Algebra/LocalNet/Locality.lean +++ b/QuantumSystem/Algebra/LocalNet/Locality.lean @@ -5,7 +5,7 @@ public import QuantumSystem.Algebra.LocalNet.Isotony /-! # Locality (Einstein causality) of the local net -Observables localised in **disjoint** regions commute. For finite-dimensional spin systems this +Observables localised in **disjoint** regions commute. For finite-dimensional lattice systems this is the concrete realisation of the AQFT locality axiom (Naaijkens 2012 §3.2: spacelike-separated — here disjoint — regions commute; Verch 2025 §1.2). The proof reduces to the union region `Λ₁ ∪ Λ₂`, where the two embeddings act on complementary tensor factors, and ultimately to @@ -14,9 +14,9 @@ commutativity of the scalar matrix entries in `ℂ`. @[expose] public section -namespace LocalNet +namespace SiteIndexSystem -variable (L : LocalNet) +variable (L : SiteIndexSystem) /-- The right-region embedding `𝔄(Λ₂) ↪ 𝔄(Λ₁ ∪ Λ₂)` evaluated at indices factored through the *left* split `combineIdx (Λ₁ ⊆ Λ₁ ∪ Λ₂)`: since `Λ₁` and `Λ₂` are disjoint, the @@ -105,7 +105,7 @@ private lemma includeAlgebra_commute_union {Λ₁ Λ₂ : Finset L.sites} (hd : Finset.sum_ite_eq, Finset.sum_ite_eq', Finset.mem_univ, if_true] ring -/-- **Locality / Einstein causality (spin systems)**: observables localised in disjoint +/-- **Locality / Einstein causality (lattice systems)**: observables localised in disjoint regions commute inside any common total region. The finite-dimensional concrete form of the AQFT locality axiom (Naaijkens 2012 §3.2; Verch 2025 §1.2). Reduces to the bipartite case via functoriality (`includeAlgebra_trans_apply`) and the ring-hom property of the @@ -124,4 +124,4 @@ theorem includeAlgebra_commute_of_disjoint {Λ₁ Λ₂ Λ_total : Finset L.site rw [e1, e2] exact (L.includeAlgebra_commute_union hd X Y).map (L.includeAlgebra hU) -end LocalNet +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean new file mode 100644 index 0000000..34b2199 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -0,0 +1,458 @@ +module + +public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar +public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit +public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion + +/-! +# Local nets of C⋆-algebras + +This file reifies the **net** of an AQFT system as a first-class object: a *local net of +C⋆-algebras* over the finite regions of a site set is the assignment `Λ ↦ 𝔄(Λ)` of a +C⋆-algebra to each finite region `Λ : Finset sites`, together with the **isotony embeddings** +`𝔄(Λ) ↪ 𝔄(Λ')` for `Λ ⊆ Λ'`, which are *functorial* (compose, and the identity inclusion is +the identity) and satisfy **locality** (observables in disjoint regions commute). This is the +data of a Haag–Kastler net specialised to a lattice of sites (Naaijkens 2012 §1.3, Verch 2025 +§1.2, Bratteli–Robinson Vol.2 §6.2). + +The structure is genuinely abstract: it does not commit to any concrete realisation of the +local algebras. The finite-dimensional matrix net `𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` is one +instance, built from a `SiteIndexSystem` via `SiteIndexSystem.toLocalNet` +(`LocalNet.QuasiLocal`). + +On any local net this file builds, once and for all: + +* the **directed system** of `*`-algebras (`directedSystem`), via functoriality; +* the **algebra of local observables** `quasiLocalAlgebra` (the algebraic inductive limit) with + cocone `ιLocal`, exhaustion `exists_ιLocal`, and locality `ιLocal_commute_of_disjoint`; +* for a **faithful** net (`Faithful`: all inclusions injective — the standard AQFT + non-degeneracy condition), the C⋆-norm and the **quasi-local C⋆-algebra** + `quasiLocalCStarAlgebra` (its completion), with dense embeddings `ιLocalCStar`; +* the **covariance** of the net: `Symmetry` (the AQFT covariance datum `β(𝔄(Λ)) = 𝔄(σΛ)`, natural + with respect to isotony), which form a **group** under composition (`Group N.Symmetry`, with + `Symmetry.id`/`Symmetry.comp`/`Symmetry.inv`), and the purely algebraic action + `Symmetry.quasiLocalRelabel` on the algebra of local observables, which is a monoid homomorphism + out of that group (`quasiLocalRelabel_one`/`quasiLocalRelabel_mul`) — so a group `G` acting on + the net (a hom `G →* N.Symmetry`) acts on the local observables by `*`-endomorphisms. + +The injectivity needed for the C⋆-norm is carried by the separate `Faithful` typeclass rather +than a structure field, so that the purely algebraic constructions (`quasiLocalAlgebra`, +`ιLocal`, and the covariance action `Symmetry.quasiLocalRelabel`) need no non-degeneracy hypothesis. +-/ + +@[expose] public section + +/-- A **local net of C⋆-algebras** over the finite regions of a site set `sites`: the assignment + `Λ ↦ 𝔄(Λ)` together with isotony embeddings `incl : 𝔄(Λ) →⋆ₐ[ℂ] 𝔄(Λ')` for `Λ ⊆ Λ'`, + functorial (`incl_refl`/`incl_trans`) and local (`locality`). This is the Haag–Kastler net + structure for a lattice of sites; the matrix lattice net is one instance via + `SiteIndexSystem.toLocalNet`. -/ +structure LocalNet (sites : Type*) [DecidableEq sites] where + /-- The local C⋆-algebra `𝔄(Λ)` assigned to a finite region. -/ + algebra : Finset sites → Type* + /-- Each local algebra is a (complex) C⋆-algebra. -/ + [algebraCStar : ∀ Λ, CStarAlgebra (algebra Λ)] + /-- **Isotony**: for `Λ ⊆ Λ'` an inclusion of local algebras as a unital `*`-homomorphism. -/ + incl : ∀ {Λ Λ' : Finset sites}, Λ ⊆ Λ' → (algebra Λ →⋆ₐ[ℂ] algebra Λ') + /-- The identity inclusion `Λ ⊆ Λ` acts as the identity. -/ + incl_refl : ∀ {Λ : Finset sites} (x : algebra Λ), incl (Finset.Subset.refl Λ) x = x + /-- **Functoriality**: the inclusions compose, so the net is a directed system. -/ + incl_trans : ∀ {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (x : algebra Λ₁), + incl h₂₃ (incl h₁₂ x) = incl (h₁₂.trans h₂₃) x + /-- **Locality** (microcausality): observables localised in *disjoint* regions commute inside + any common larger region. For a lattice net this is locality *in space* — the kinematical + (equal-time) analogue of relativistic Einstein causality, with spatial disjointness in place + of spacelike separation (Naaijkens 2012 §3.4). -/ + locality : ∀ {Λ₁ Λ₂ Λ : Finset sites} (h₁ : Λ₁ ⊆ Λ) (h₂ : Λ₂ ⊆ Λ), + Disjoint Λ₁ Λ₂ → ∀ (x : algebra Λ₁) (y : algebra Λ₂), + Commute (incl h₁ x) (incl h₂ y) + +namespace LocalNet + +attribute [instance] algebraCStar + +variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) + +/-- The net forms a directed system of `*`-algebras: the isotony embeddings compose and the + identity inclusion is the identity. -/ +instance directedSystem : + DirectedSystem N.algebra (fun _ _ h => ⇑(N.incl h)) where + map_self _ x := N.incl_refl x + map_map _ _ _ hij hjk x := N.incl_trans hij hjk x + +/-- The **algebra of local observables** of the net: the algebraic inductive limit of the local + algebras along the isotony embeddings. Its C⋆-completion is the quasi-local algebra. -/ +noncomputable abbrev quasiLocalAlgebra : Type _ := + DirectLimit N.algebra (fun _ _ h => N.incl h) + +/-- Componentwise behaviour of the involution on the algebra of local observables. The + `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general + direct-limit constructions, since each `algebra Λ` is a `ℂ`-`*`-algebra and `incl` is a + `*`-algebra homomorphism. -/ +@[simp] theorem star_mk {Λ : Finset sites} (X : N.algebra Λ) : + star (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl + +/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local + observables, as a unital ring homomorphism (the cocone of the inductive limit). -/ +noncomputable def ιLocal (Λ : Finset sites) : + N.algebra Λ →+* N.quasiLocalAlgebra := + DirectLimit.Ring.of N.algebra (fun _ _ h => N.incl h) Λ + +/-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the + larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ +@[simp] theorem ιLocal_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (X : N.algebra Λ) : + N.ιLocal Λ' (N.incl h X) = N.ιLocal Λ X := + DirectLimit.Ring.of_f (G := N.algebra) (f := fun _ _ h => N.incl h) h X + +/-- The cocone is a `*`-homomorphism: it intertwines the local and quasi-local involutions. -/ +@[simp] theorem ιLocal_star {Λ : Finset sites} (X : N.algebra Λ) : + N.ιLocal Λ (star X) = star (N.ιLocal Λ X) := + (star_mk (N := N) X).symm + +/-- **Exhaustion**: every element of the algebra of local observables is the image of a local + observable from some finite region — the union of the local algebras is the whole limit. -/ +theorem exists_ιLocal (z : N.quasiLocalAlgebra) : + ∃ (Λ : Finset sites) (X : N.algebra Λ), z = N.ιLocal Λ X := by + induction z using DirectLimit.induction with + | _ Λ X => exact ⟨Λ, X, rfl⟩ + +/-- **Locality in the algebra of local observables**: observables localised in disjoint regions + commute inside `𝔄_loc`. Lifts the net's `locality` along the ring-hom cocone. -/ +theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset sites} (hd : Disjoint Λ₁ Λ₂) + (X : N.algebra Λ₁) (Y : N.algebra Λ₂) : + Commute (N.ιLocal Λ₁ X) (N.ιLocal Λ₂ Y) := by + have h1 : N.ιLocal Λ₁ X + = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_left X) := + (N.ιLocal_incl Finset.subset_union_left X).symm + have h2 : N.ιLocal Λ₂ Y + = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_right Y) := + (N.ιLocal_incl Finset.subset_union_right Y).symm + rw [h1, h2] + exact (N.locality Finset.subset_union_left Finset.subset_union_right hd X Y).map + (N.ιLocal (Λ₁ ∪ Λ₂)) + +/-! ### Faithful nets and the quasi-local C⋆-algebra + +A net is *faithful* when its isotony embeddings are injective (the standard AQFT non-degeneracy +condition). For a faithful net the connecting maps are isometric, so the algebra of local +observables carries a C⋆-norm whose completion is the quasi-local C⋆-algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` +(Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2). -/ + +/-- A local net is **faithful** when all its isotony embeddings are injective. In the standard + AQFT definition the isotony embeddings are *injective* unital `*`-homomorphisms (Naaijkens 2012 + §3.4), so a faithful local net — `LocalNet` together with `Faithful` — is the literature's net; + this is the non-degeneracy condition that makes the inclusions genuine and the C⋆-norm on the + algebra of local observables well defined. Carried as a typeclass (rather than a structure + field) so the purely algebraic constructions stay free of any non-degeneracy hypothesis. -/ +class Faithful {sites : Type*} [DecidableEq sites] (N : LocalNet sites) : Prop where + /-- Every isotony embedding of the net is injective. -/ + incl_injective : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ'), Function.Injective (N.incl h) + +section CStar + +variable [N.Faithful] + +/-- The algebra of local observables is a normed ring under the C⋆-norm of the inductive limit + (the inclusions are injective, hence isometric). -/ +noncomputable instance : NormedRing N.quasiLocalAlgebra := + DirectLimit.cstarNormedRing (fun _ _ h => Faithful.incl_injective h) + +@[simp] theorem norm_mk {Λ : Finset sites} (X : N.algebra Λ) : + ‖(⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl + +/-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ +noncomputable instance : NormedAlgebra ℂ N.quasiLocalAlgebra where + norm_smul_le c x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X + +/-- `star` is isometric on the algebra of local observables. -/ +instance : NormedStarGroup N.quasiLocalAlgebra where + norm_star_le x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le + +/-- The C⋆-identity holds on the algebra of local observables. -/ +instance : CStarRing N.quasiLocalAlgebra where + norm_mul_self_le x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] + exact CStarRing.norm_mul_self_le X + +/-- The **quasi-local C⋆-algebra** of a faithful net: the completion of the algebra of local + observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, + Bratteli–Robinson Vol.2 §6.2). -/ +noncomputable abbrev quasiLocalCStarAlgebra : Type _ := + UniformSpace.Completion N.quasiLocalAlgebra + +noncomputable example : CStarAlgebra N.quasiLocalCStarAlgebra := inferInstance + +/-- The canonical embedding `𝔄(Λ) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, + as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ +noncomputable def ιLocalCStar (Λ : Finset sites) : + N.algebra Λ → N.quasiLocalCStarAlgebra := + (↑) ∘ N.ιLocal Λ + +/-- The local algebras are dense in the quasi-local C⋆-algebra: every element is a norm-limit of + local observables. -/ +theorem denseRange_iUnion_ιLocalCStar : + Dense (⋃ Λ : Finset sites, Set.range (N.ιLocalCStar Λ)) := by + refine UniformSpace.Completion.denseRange_coe.mono ?_ + rintro _ ⟨z, rfl⟩ + obtain ⟨Λ, X, rfl⟩ := N.exists_ιLocal z + exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ + +end CStar + +/-! ### Covariance: symmetries of the net + +A **symmetry** of a local net is a site permutation `σ` together with, for each finite region, a +`*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the +isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)` at the abstract net +level (Naaijkens 2012 §3.2, Verch 2025 §1.2). Being purely algebraic, the induced action on the +algebra of local observables needs no faithfulness hypothesis. -/ + +/-- Transport a local algebra along an equality of regions, as a `*`-isomorphism. Used to identify + `𝔄(σ₁σ₂Λ)` along the functoriality of the region map when composing symmetries. -/ +def algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') : N.algebra Λ ≃⋆ₐ[ℂ] N.algebra Λ' := by + subst h; exact StarAlgEquiv.refl + +@[simp] theorem algebraCongr_apply {Λ : Finset sites} (x : N.algebra Λ) : + N.algebraCongr (rfl : Λ = Λ) x = x := rfl + +/-- The cocone of the inductive limit absorbs the region-equality transport. -/ +@[simp] theorem ιLocal_algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) : + N.ιLocal Λ' (N.algebraCongr h x) = N.ιLocal Λ x := by + subst h; rfl + +/-- The isotony embeddings are natural with respect to the region-equality transport. -/ +theorem incl_algebraCongr {Λ₁ Λ₂ Λ₁' Λ₂' : Finset sites} (e₁ : Λ₁ = Λ₁') (e₂ : Λ₂ = Λ₂') + (h : Λ₁ ⊆ Λ₂) (h' : Λ₁' ⊆ Λ₂') (x : N.algebra Λ₁) : + N.algebraCongr e₂ (N.incl h x) = N.incl h' (N.algebraCongr e₁ x) := by + subst e₁; subst e₂; rfl + +/-- Transports along composable region equalities compose. -/ +@[simp] theorem algebraCongr_trans {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁ : Λ₁ = Λ₂) (h₂ : Λ₂ = Λ₃) + (x : N.algebra Λ₁) : + N.algebraCongr h₂ (N.algebraCongr h₁ x) = N.algebraCongr (h₁.trans h₂) x := by + subst h₁; subst h₂; rfl + +/-- A transport along a reflexive region equality is the identity. -/ +@[simp] theorem algebraCongr_self {Λ : Finset sites} (h : Λ = Λ) (x : N.algebra Λ) : + N.algebraCongr h x = x := by + rw [Subsingleton.elim h rfl]; rfl + +/-- Cancelling a transport against a target value moves it to the other side. -/ +theorem algebraCongr_eq_iff {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) + (y : N.algebra Λ') : N.algebraCongr h x = y ↔ x = N.algebraCongr h.symm y := by + subst h; simp + +/-- A **symmetry** of a local net `N`: a site permutation `σ` together with, for every finite + region `Λ`, a `*`-isomorphism `β Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)`, natural with respect to the isotony + embeddings (`β_incl`). This is the AQFT covariance datum at the abstract net level — one element + of a covariant group action (Naaijkens 2012 §3.2, Verch 2025 §1.2). -/ +structure Symmetry where + /-- The underlying site permutation; its image map `Λ ↦ σΛ` carries the region map. -/ + σ : sites ≃ sites + /-- The covariance `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` on each region. -/ + β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding) + /-- **Naturality / covariance**: `β` intertwines the isotony embeddings, so it maps the net to + itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)`. -/ + β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), + β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x) + +namespace Symmetry + +variable {N} (a : N.Symmetry) + +/-- The image `σΛ` of a region under the symmetry. -/ +def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding + +/-- **Extensionality** for symmetries: two symmetries with the same site permutation and the same + local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality + field `β_incl` is a proposition, hence irrelevant. -/ +@[ext (iff := false)] theorem ext {s t : N.Symmetry} (hσ : s.σ = t.σ) + (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), + N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by + revert hσ hβ + obtain ⟨sσ, sβ, -⟩ := s + obtain ⟨tσ, tβ, -⟩ := t + rintro rfl hβ + have hβ' : sβ = tβ := by + funext Λ + ext x + simpa using hβ Λ x rfl + subst hβ' + rfl + +/-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ +theorem β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : + (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by + have key := a.β_incl h ((a.β Λ).symm y) + rw [StarAlgEquiv.apply_symm_apply] at key + rw [← key, StarAlgEquiv.symm_apply_apply] + +/-- The local `*`-isomorphisms commute with the region-equality transport. -/ +theorem β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : + a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by + subst e; simp + +/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a symmetry on the algebra of local + observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ +noncomputable def quasiLocalRelabel : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := + DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra + (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) + (fun Λ Λ' h X => by + change N.ιLocal (a.region Λ') (a.β Λ' (N.incl h X)) = N.ιLocal (a.region Λ) (a.β Λ X) + rw [a.β_incl h] + exact N.ιLocal_incl _ _) + +@[simp] theorem quasiLocalRelabel_mk {Λ : Finset sites} (X : N.algebra Λ) : + a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := + rfl + +variable (N) in +/-- The **identity symmetry**: the identity site permutation with the identity local + `*`-isomorphisms (transported along `Λ = σ_id Λ`). -/ +def id : N.Symmetry where + σ := Equiv.refl sites + β Λ := N.algebraCongr (by simp) + β_incl h x := N.incl_algebraCongr _ _ h _ x + +/-- **Composition of symmetries**: apply `b`, then `a`. The site permutations compose; the local + `*`-isomorphisms compose and are transported along the region-map functoriality + `(σ_a ∘ σ_b) Λ = σ_a (σ_b Λ)`. -/ +def comp (a b : N.Symmetry) : N.Symmetry where + σ := b.σ.trans a.σ + β Λ := ((b.β Λ).trans (a.β (Λ.map b.σ.toEmbedding))).trans + (N.algebraCongr (by simp [Finset.map_map, Equiv.trans_toEmbedding])) + β_incl h x := by + simp only [StarAlgEquiv.trans_apply] + rw [b.β_incl h, a.β_incl (Finset.map_subset_map.mpr h)] + exact N.incl_algebraCongr _ _ _ _ _ + +/-- The **inverse symmetry**: the inverse site permutation with the inverse local + `*`-isomorphisms, transported along the region-map functoriality `σ⁻¹σ Λ = Λ`. -/ +def inv (a : N.Symmetry) : N.Symmetry where + σ := a.σ.symm + β Λ := (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by + simp [Finset.map_map]).symm).trans + (a.β (Λ.map a.σ.symm.toEmbedding)).symm + β_incl h x := by + simp only [StarAlgEquiv.trans_apply] + rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), + a.β_symm_incl] + +@[simp] theorem id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : + (Symmetry.id N).β Λ x = + N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := + rfl + +@[simp] theorem comp_β_apply (a b : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : + (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding + = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) + (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := + rfl + +@[simp] theorem inv_β_apply (a : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : + (Symmetry.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm + (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by + simp [Finset.map_map]).symm x) := + rfl + +@[simp] theorem region_id (Λ : Finset sites) : (Symmetry.id N).region Λ = Λ := by + simp [region, Symmetry.id] + +@[simp] theorem region_comp (a b : N.Symmetry) (Λ : Finset sites) : + (a.comp b).region Λ = a.region (b.region Λ) := by + simp [region, Symmetry.comp, Finset.map_map, Equiv.trans_toEmbedding] + +/-- The covariance action of the identity symmetry is the identity: `β_{id} = id`. -/ +@[simp] theorem quasiLocalRelabel_id : + (Symmetry.id N).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by + refine RingHom.ext fun z => ?_ + induction z using DirectLimit.induction with + | _ Λ X => rw [quasiLocalRelabel_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X + +/-- **Functoriality of the covariance action**: composing symmetries composes their actions, + `β_{a∘b} = β_a ∘ β_b`. With `quasiLocalRelabel_id` this exhibits `a ↦ β_a` as a functorial + (monoid-homomorphic) assignment, so a group acting on the net acts on the algebra of local + observables by `*`-endomorphisms. -/ +@[simp] theorem quasiLocalRelabel_comp (a b : N.Symmetry) : + (a.comp b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by + refine RingHom.ext fun z => ?_ + induction z using DirectLimit.induction with + | _ Λ X => + simp only [RingHom.comp_apply, quasiLocalRelabel_mk] + exact N.ιLocal_algebraCongr _ _ + +theorem id_comp (a : N.Symmetry) : (Symmetry.id N).comp a = a := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Symmetry.id] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, id_β_apply] + erw [algebraCongr_trans] + rfl + +theorem comp_id (a : N.Symmetry) : a.comp (Symmetry.id N) = a := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Symmetry.id] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, id_β_apply] + erw [a.β_algebraCongr, algebraCongr_trans] + rfl + +theorem comp_assoc (a b c : N.Symmetry) : (a.comp b).comp c = a.comp (b.comp c) := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Equiv.trans_assoc] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply] + erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] + rfl + +theorem inv_comp (a : N.Symmetry) : (Symmetry.inv a).comp a = Symmetry.id N := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Symmetry.inv, Symmetry.id, Equiv.self_trans_symm] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, inv_β_apply, id_β_apply] + erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply, algebraCongr_trans, + algebraCongr_trans] + · rfl + · simp [Finset.map_map] + +/-- The symmetries of a local net form a **group** under composition, with `Symmetry.id` the unit + and `Symmetry.inv` the inverse. A covariant action of a group `G` on the net is then a + homomorphism `G →* N.Symmetry`. -/ +noncomputable instance : Group N.Symmetry where + mul a b := a.comp b + one := Symmetry.id N + inv a := a.inv + mul_assoc := Symmetry.comp_assoc + one_mul := Symmetry.id_comp + mul_one := Symmetry.comp_id + inv_mul_cancel := Symmetry.inv_comp + +/-- The group multiplication is composition of symmetries. -/ +theorem mul_def (a b : N.Symmetry) : a * b = a.comp b := rfl + +/-- The group unit is the identity symmetry. -/ +theorem one_def : (1 : N.Symmetry) = Symmetry.id N := rfl + +/-- The group inverse is the inverse symmetry. -/ +theorem inv_def (a : N.Symmetry) : a⁻¹ = a.inv := rfl + +/-- The covariance action sends the unit symmetry to the identity: `β_1 = id`. -/ +@[simp] theorem quasiLocalRelabel_one : + (1 : N.Symmetry).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by + rw [one_def, quasiLocalRelabel_id] + +/-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. With `quasiLocalRelabel_one` + this exhibits `a ↦ β_a` as a monoid homomorphism from the symmetry group into the + `*`-endomorphisms of the algebra of local observables. -/ +theorem quasiLocalRelabel_mul (a b : N.Symmetry) : + (a * b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by + rw [mul_def, quasiLocalRelabel_comp] + +end Symmetry + +end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean index e755173..4e42808 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean @@ -1,171 +1,104 @@ module -public import QuantumSystem.Algebra.LocalNet.Locality -public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar -public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit -public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion public import Mathlib.Analysis.CStarAlgebra.Matrix +public import QuantumSystem.Algebra.LocalNet.Locality +public import QuantumSystem.Algebra.LocalNet.Net /-! -# Quasi-local algebra of the local net - -For a `LocalNet` on a (possibly infinite) lattice of sites, the **algebra of local observables** -is the algebraic inductive limit of the directed system of finite-region matrix algebras -`{𝔄(Λ) : Λ : Finset sites}` with the isotony embeddings `includeAlgebra (h : Λ ⊆ Λ')` as -connecting maps, and the **quasi-local C⋆-algebra** is its norm completion (Naaijkens 2012 §1.3, -Bratteli–Robinson Vol.2 §6.2). - -* The directed system is genuine: the connecting maps compose (`includeAlgebra_trans_apply`) - and the identity inclusion is the identity (`includeAlgebra_refl_apply`). -* `quasiLocalAlgebra` (the algebraic inductive limit) is a `ℂ`-`*`-algebra with cocone `ιLocal`, - exhaustion `exists_ιLocal`, and locality `ιLocal_commute_of_disjoint`. -* In `section CStar` (assuming each site has a non-empty local index type, so the embeddings are - injective hence isometric), the C⋆-norm makes it a pre-C⋆-algebra and `quasiLocalCStarAlgebra` - (its completion) is a `CStarAlgebra`, with dense embeddings `ιLocalCStar`. +# The local net generated by a lattice system + +A `SiteIndexSystem` on a (possibly infinite) lattice of sites — the data of a finite local +index type at each site — generates a genuine **local net of C⋆-algebras** (`LocalNet`): the +assignment `Λ ↦ 𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` to each finite region, with the isotony embeddings +`includeAlgebra (h : Λ ⊆ Λ')` (the inclusion `A ↦ A ⊗ I` of `LocalNet.Isotony`), functorial +(`includeAlgebra_trans_apply`, `includeAlgebra_refl_apply`) and local +(`includeAlgebra_commute_of_disjoint`). + +* `instCStarAlgebraLocal` makes each finite-region matrix algebra a C⋆-algebra under the + `L2Operator` norm; this discharges the C⋆-structure required by `LocalNet`. +* `SiteIndexSystem.toLocalNet` packages the matrix algebras and isotony embeddings into a + `LocalNet`. The **algebra of local observables** and the **quasi-local C⋆-algebra** are then + inherited from the abstract net (`LocalNet.quasiLocalAlgebra`, `LocalNet.quasiLocalCStarAlgebra`). +* When each site has a non-empty local index type the embeddings are injective, so the generated + net is `LocalNet.Faithful` and its quasi-local C⋆-algebra is the AQFT quasi-local algebra + `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2). + +The lattice-system-level abbreviations `quasiLocalAlgebra` / `ιLocal` / `quasiLocalCStarAlgebra` +below are thin wrappers around the corresponding `LocalNet` constructions on `toLocalNet`. -/ @[expose] public section -namespace LocalNet - -variable (L : LocalNet) - -/-- The local net forms a directed system of `*`-algebras: the isotony embeddings compose - and the identity inclusion is the identity (Phase 1 functoriality). -/ -instance directedSystem : - DirectedSystem (fun Λ : Finset L.sites => L.localAlgebra Λ) - (fun _ _ h => ⇑(L.includeAlgebra h)) where - map_self _ x := L.includeAlgebra_refl_apply x - map_map _ _ _ hij hjk x := L.includeAlgebra_trans_apply hij hjk x - -/-- The **algebra of local observables**: the algebraic inductive limit of the finite-region - matrix algebras along the isotony embeddings. Its C*-completion is the quasi-local - algebra of AQFT. -/ -noncomputable abbrev quasiLocalAlgebra : Type _ := - DirectLimit (fun Λ : Finset L.sites => L.localAlgebra Λ) - (fun _ _ h => L.includeAlgebra h) - -/-- Componentwise behaviour of the involution (from the general `DirectLimit` `*`-ring - instance in `ForMathlib`). The quasi-local algebra is a `*`-algebra over `ℂ`: its - `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general - direct-limit constructions, since `localAlgebra` is a `ℂ`-`*`-algebra and `includeAlgebra` - is a `*`-algebra homomorphism. -/ -@[simp] theorem star_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - star (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl - -/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the quasi-local algebra, - as a unital ring homomorphism (the cocone of the inductive limit). -/ -noncomputable def ιLocal (Λ : Finset L.sites) : - L.localAlgebra Λ →+* L.quasiLocalAlgebra := - DirectLimit.Ring.of (fun Λ : Finset L.sites => L.localAlgebra Λ) - (fun _ _ h => L.includeAlgebra h) Λ - -/-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the - larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ -@[simp] theorem ιLocal_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') (X : L.localAlgebra Λ) : - L.ιLocal Λ' (L.includeAlgebra h X) = L.ιLocal Λ X := - DirectLimit.Ring.of_f (G := fun Λ : Finset L.sites => L.localAlgebra Λ) - (f := fun _ _ h => L.includeAlgebra h) h X - -/-- The cocone is a `*`-homomorphism: it intertwines the local adjoint with the quasi-local - adjoint. -/ -@[simp] theorem ιLocal_star {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - L.ιLocal Λ (star X) = star (L.ιLocal Λ X) := - (star_mk (L := L) X).symm - -/-- **Exhaustion**: every element of the quasi-local algebra is the image of a local - observable from some finite region — the union of the local algebras is the whole limit. -/ -theorem exists_ιLocal (z : L.quasiLocalAlgebra) : ∃ (Λ : Finset L.sites) (X : L.localAlgebra Λ), - z = L.ιLocal Λ X := by - induction z using DirectLimit.induction with - | _ Λ X => exact ⟨Λ, X, rfl⟩ - -/-- **Locality in the quasi-local algebra**: observables localised in disjoint regions commute - inside `𝔄_loc`. Lifts the bipartite locality (`includeAlgebra_commute_union`) along the - ring-hom cocone. -/ -theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset L.sites} (hd : Disjoint Λ₁ Λ₂) - (X : L.localAlgebra Λ₁) (Y : L.localAlgebra Λ₂) : - Commute (L.ιLocal Λ₁ X) (L.ιLocal Λ₂ Y) := by - have h1 : L.ιLocal Λ₁ X - = L.ιLocal (Λ₁ ∪ Λ₂) (L.includeAlgebra Finset.subset_union_left X) := - (L.ιLocal_includeAlgebra Finset.subset_union_left X).symm - have h2 : L.ιLocal Λ₂ Y - = L.ιLocal (Λ₁ ∪ Λ₂) (L.includeAlgebra Finset.subset_union_right Y) := - (L.ιLocal_includeAlgebra Finset.subset_union_right Y).symm - rw [h1, h2] - exact (L.includeAlgebra_commute_of_disjoint Finset.subset_union_left - Finset.subset_union_right hd X Y).map (L.ιLocal (Λ₁ ∪ Λ₂)) - -/-! ### Quasi-local C⋆-algebra - -Equipping the algebra of local observables with the C⋆-norm of the inductive limit (the isotony -embeddings are injective — using non-empty local dimensions — hence isometric) and completing -yields the quasi-local C⋆-algebra. The general construction lives in `ForMathlib` -(`DirectLimit.cstarNormedRing`, `UniformSpace.Completion.instCStarAlgebra`); here we supply the -net-specific inputs (matrix C⋆-algebras + injectivity). -/ - -section CStar +namespace SiteIndexSystem open scoped Matrix.Norms.L2Operator -variable [∀ s, Nonempty (L.localIdx s)] - -/-- Each finite-region matrix algebra is a (complex) C⋆-algebra under the `L2Operator` norm. - Stated for `localAlgebra` so the choice of the `L2Operator` norm does not leak to arbitrary - matrices. -/ -noncomputable instance instCStarAlgebraLocal (Λ : Finset L.sites) : - CStarAlgebra (L.localAlgebra Λ) where - -/-- The algebra of local observables is a normed ring under the C⋆-norm of the inductive limit. -/ -noncomputable instance : NormedRing (L.quasiLocalAlgebra) := - DirectLimit.cstarNormedRing (fun _ _ h => L.includeAlgebra_injective h) - -@[simp] theorem norm_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - ‖(⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra)‖ = ‖X‖ := rfl - -/-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ -noncomputable instance : NormedAlgebra ℂ (L.quasiLocalAlgebra) where - norm_smul_le c x := by - induction x using DirectLimit.induction with - | _ Λ X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X - -/-- `star` is isometric on the algebra of local observables. -/ -instance : NormedStarGroup (L.quasiLocalAlgebra) where - norm_star_le x := by - induction x using DirectLimit.induction with - | _ Λ X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le - -/-- The C⋆-identity holds on the algebra of local observables. -/ -instance : CStarRing (L.quasiLocalAlgebra) where - norm_mul_self_le x := by - induction x using DirectLimit.induction with - | _ Λ X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] - exact CStarRing.norm_mul_self_le X - -/-- The **quasi-local C⋆-algebra** of the net: the completion of the algebra of local - observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, - Bratteli–Robinson Vol.2 §6.2), obtained as the C⋆-inductive limit of the finite-region - matrix algebras. -/ -noncomputable abbrev quasiLocalCStarAlgebra : Type _ := - UniformSpace.Completion L.quasiLocalAlgebra - -noncomputable example : CStarAlgebra L.quasiLocalCStarAlgebra := inferInstance - -/-- The canonical embedding `𝔄(Λ) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, - as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ -noncomputable def ιLocalCStar (Λ : Finset L.sites) : - L.localAlgebra Λ → L.quasiLocalCStarAlgebra := - (↑) ∘ L.ιLocal Λ - -/-- The local algebras are dense in the quasi-local C⋆-algebra: the union of the images of the - `ιLocalCStar Λ` is dense (every element is a norm-limit of local observables). -/ -theorem denseRange_iUnion_ιLocalCStar : - Dense (⋃ Λ : Finset L.sites, Set.range (L.ιLocalCStar Λ)) := by - refine UniformSpace.Completion.denseRange_coe.mono ?_ - rintro _ ⟨z, rfl⟩ - obtain ⟨Λ, X, rfl⟩ := L.exists_ιLocal z - exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ - -end CStar - -end LocalNet +variable (S : SiteIndexSystem) + +/-- Each finite-region matrix algebra `𝔄(Λ) = Matrix (regionIdx Λ) (regionIdx Λ) ℂ` is a + (complex) C⋆-algebra under the `L2Operator` norm. Stated for `localAlgebra` so the choice of + the `L2Operator` norm does not leak to arbitrary matrices. -/ +noncomputable instance instCStarAlgebraLocal (Λ : Finset S.sites) : + CStarAlgebra (S.localAlgebra Λ) where + +/-- The **local net generated by the lattice system**: the assignment of matrix algebras to + finite regions, with the isotony embeddings as connecting maps. This realises the abstract + Haag–Kastler net `LocalNet` for the finite-dimensional matrix model. -/ +noncomputable def toLocalNet : LocalNet S.sites where + algebra := S.localAlgebra + incl h := S.includeAlgebra h + incl_refl x := S.includeAlgebra_refl_apply x + incl_trans h₁₂ h₂₃ x := S.includeAlgebra_trans_apply h₁₂ h₂₃ x + locality h₁ h₂ hd x y := S.includeAlgebra_commute_of_disjoint h₁ h₂ hd x y + +@[simp] theorem toLocalNet_algebra (Λ : Finset S.sites) : + S.toLocalNet.algebra Λ = S.localAlgebra Λ := rfl + +@[simp] theorem toLocalNet_incl {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') : + S.toLocalNet.incl h = S.includeAlgebra h := rfl + +/-- The generated net is **faithful**: if each site has a non-empty local index type, the complementary + region indices are non-empty, so the isotony embeddings are injective. -/ +instance toLocalNet_faithful [∀ s, Nonempty (S.localIdx s)] : S.toLocalNet.Faithful where + incl_injective h := S.includeAlgebra_injective h + +/-! ### Lattice-system-level quasi-local algebra + +Thin wrappers exposing the `LocalNet` constructions on `toLocalNet` directly on the lattice system. -/ + +/-- The **algebra of local observables** of the lattice system: the algebraic inductive limit of the + finite-region matrix algebras (inherited from `LocalNet.quasiLocalAlgebra` on `toLocalNet`). -/ +noncomputable abbrev quasiLocalAlgebra : Type _ := S.toLocalNet.quasiLocalAlgebra + +/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local + observables (the cocone of the inductive limit). -/ +noncomputable def ιLocal (Λ : Finset S.sites) : + S.localAlgebra Λ →+* S.quasiLocalAlgebra := + S.toLocalNet.ιLocal Λ + +/-- Compatibility of the cocone with the isotony embeddings. -/ +@[simp] theorem ιLocal_includeAlgebra {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') + (X : S.localAlgebra Λ) : + S.ιLocal Λ' (S.includeAlgebra h X) = S.ιLocal Λ X := + S.toLocalNet.ιLocal_incl h X + +/-- **Exhaustion**: every element of the algebra of local observables comes from some finite + region. -/ +theorem exists_ιLocal (z : S.quasiLocalAlgebra) : + ∃ (Λ : Finset S.sites) (X : S.localAlgebra Λ), z = S.ιLocal Λ X := + S.toLocalNet.exists_ιLocal z + +/-- **Locality**: observables localised in disjoint regions commute inside the algebra of local + observables. -/ +theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset S.sites} (hd : Disjoint Λ₁ Λ₂) + (X : S.localAlgebra Λ₁) (Y : S.localAlgebra Λ₂) : + Commute (S.ιLocal Λ₁ X) (S.ιLocal Λ₂ Y) := + S.toLocalNet.ιLocal_commute_of_disjoint hd X Y + +/-- The **quasi-local C⋆-algebra** of the lattice system (assuming non-empty local dimensions): the + completion of the algebra of local observables, i.e. the AQFT quasi-local algebra + `𝔄 = ‾⋃_Λ 𝔄(Λ)`. -/ +noncomputable abbrev quasiLocalCStarAlgebra [∀ s, Nonempty (S.localIdx s)] : Type _ := + S.toLocalNet.quasiLocalCStarAlgebra + +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean index 5bd1282..4342206 100644 --- a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean +++ b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean @@ -28,9 +28,9 @@ The isotony embedding is then literally "tensoring with the identity on the comp open WithLp open scoped TensorProduct Matrix -namespace LocalNet +namespace SiteIndexSystem -variable (L : LocalNet) +variable (L : SiteIndexSystem) /-- The Hilbert space of a region: the Euclidean space on its index type. -/ abbrev ℋ (Λ : Finset L.sites) : Type _ := EuclideanSpace ℂ (L.regionIdx Λ) @@ -115,4 +115,4 @@ theorem opEquiv_includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_tot TensorProduct.endTensorEndAlgEquiv_tmul, regionBipartition, LinearEquiv.symm_conjAlgEquiv, LinearEquiv.symm_symm] -end LocalNet +end SiteIndexSystem From c410f5f54568ccc6e06ce64abf55d1acca8f3666 Mon Sep 17 00:00:00 2001 From: suzuki Date: Thu, 25 Jun 2026 12:48:04 +0000 Subject: [PATCH 019/113] refactor: propagate SiteIndexSystem rename to analysis and notation modules Mechanical rename of the generating-data structure (former `LocalNet`, now `SiteIndexSystem`) across the entropy, partial-trace, channel and notation modules that consume it, with minor accompanying docstring touch-ups. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Analysis/Channel/PartialTrace.lean | 4 +-- .../Analysis/Entropy/KroneckerProduct.lean | 6 ++-- .../Analysis/Entropy/MutualInfoProduct.lean | 2 +- .../Analysis/Entropy/Regularize.lean | 12 +++---- .../Entropy/StrongSubadditivityLocalNet.lean | 32 +++++++++---------- .../Entropy/StrongSubadditivityProduct.lean | 10 +++--- .../Matrix/KroneckerPartialTraceBridge.lean | 26 +++++++-------- .../Analysis/Matrix/PartialTrace.lean | 28 ++++++++-------- .../Analysis/Matrix/PartialTraceOperator.lean | 10 +++--- .../LinearAlgebra/Matrix/StarAlgEquiv.lean | 2 +- QuantumSystem/Notation.lean | 2 +- 11 files changed, 67 insertions(+), 67 deletions(-) diff --git a/QuantumSystem/Analysis/Channel/PartialTrace.lean b/QuantumSystem/Analysis/Channel/PartialTrace.lean index 89958ea..7010237 100644 --- a/QuantumSystem/Analysis/Channel/PartialTrace.lean +++ b/QuantumSystem/Analysis/Channel/PartialTrace.lean @@ -7,10 +7,10 @@ public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace # Partial trace as a quantum channel (product index types) The **partial trace** on plain product index types `X × Y`, packaged as a completely positive -trace-preserving map (`QuantumChannel`). This is the `LocalNet`-free analogue of +trace-preserving map (`QuantumChannel`). This is the `SiteIndexSystem`-free analogue of `Matrix.QuantumChannel.restrict` (`Analysis/Matrix/PartialTrace.lean`): it traces out the right factor `Y` of a matrix on `X × Y`, leaving a matrix on `X`. The construction mirrors the region -version with `LocalNet.combineIdx (a, b)` replaced by the plain pair `(x, y)`. +version with `SiteIndexSystem.combineIdx (a, b)` replaced by the plain pair `(x, y)`. We also package conjugation by an index equivalence (`reindexₗ`) as a channel, and compose the two into the trace-out-`C` channel `QuantumChannel.traceOutC : QuantumChannel (A × B × C) (A × B)`, diff --git a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean index 80caf52..0292aba 100644 --- a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean +++ b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean @@ -26,9 +26,9 @@ This file is the hub for **Kronecker-product calculus on bipartite matrices**: The retained subsystem is determined by the codomain of the chosen equivalence `e : X ≃ A × B`. For native product types, `partialTrace (Equiv.refl (n × m))` retains the `n` factor, while `partialTrace (Equiv.prodComm n m)` retains the -`m` factor. LocalNet-facing theorems should instead expose the split subset +`m` factor. SiteIndexSystem-facing theorems should instead expose the split subset `Λ ⊆ Λ_total` (and its complement) explicitly, and use these matrix-level lemmas -only after reindexing by `LocalNet.combineIdx`. +only after reindexing by `SiteIndexSystem.combineIdx`. The proof of the log-tensor identity uses the spectral decomposition of `A ⊗ B` constructed explicitly from spectral decompositions of `A` and `B`, combined @@ -49,7 +49,7 @@ a unitary). * `Matrix.cfc_log_kronecker_posDef` — the log-tensor identity. * `Matrix.partialTrace_apply` — entrywise unfolding of the equivalence-indexed partial trace. * `Matrix.restrict_eq_partialTrace_combineIdx` / - `Matrix.restrict_compl_eq_partialTrace_combineIdx` — LocalNet restriction as an + `Matrix.restrict_compl_eq_partialTrace_combineIdx` — SiteIndexSystem restriction as an equivalence-indexed partial trace. * `Matrix.trace_mul_kronecker_one_right` — `Tr(ρ · (X ⊗ 1)) = Tr((partialTrace (Equiv.refl (n × m)) ρ) · X)`. diff --git a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean b/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean index 19089e0..c115d7b 100644 --- a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean +++ b/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean @@ -12,7 +12,7 @@ product index type `n × m`: `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -This is `LocalNet`-free; it is the analytic core reused both by the AQFT strong-subadditivity proof +This is `SiteIndexSystem`-free; it is the analytic core reused both by the AQFT strong-subadditivity proof (`Analysis/Entropy/SSA.lean`) and by the product-form proof (`Analysis/Entropy/SSAProduct.lean`). -/ diff --git a/QuantumSystem/Analysis/Entropy/Regularize.lean b/QuantumSystem/Analysis/Entropy/Regularize.lean index c8bd037..c3ca5be 100644 --- a/QuantumSystem/Analysis/Entropy/Regularize.lean +++ b/QuantumSystem/Analysis/Entropy/Regularize.lean @@ -11,10 +11,10 @@ The structural definitions (`maximallyMixed`, `regularize`, `regularize_eq_cfc`, (`vonNeumannEntropy_regularize_eq_negMulLog_sum`, `tendsto_negMulLog_regularize_sum_zero`, `vonNeumannEntropy_mapEquiv`) live in `State.lean` and `VonNeumannEntropy.lean`. -This file specialises that infrastructure to a `LocalNet`. It proves compatibility of +This file specialises that infrastructure to a `SiteIndexSystem`. It proves compatibility of regularization with restriction (partial trace), which is the key fact behind extending PosDef-only theorems to PosSemidef. The cardinality factorisation for region indices now -lives next to `LocalNet.combineIdx` in `LocalNet/Basic.lean`. +lives next to `SiteIndexSystem.combineIdx` in `SiteIndexSystem/Basic.lean`. -/ @[expose] public section @@ -33,7 +33,7 @@ namespace Matrix /-- `Matrix.restrict h` of the maximally-mixed state at `Λ_total` equals the maximally-mixed state at `Λ`, after dimension cancellation. -/ -theorem restrict_maximallyMixed {L : LocalNet} {Λ Λ_total : Finset L.sites} +theorem restrict_maximallyMixed {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) [Nonempty (L.regionIdx Λ)] [Nonempty (L.regionIdx Λ_total)] : Matrix.restrict h (DensityMatrix.maximallyMixed (n := L.regionIdx Λ_total)).toMatrix = (DensityMatrix.maximallyMixed (n := L.regionIdx Λ)).toMatrix := by @@ -49,7 +49,7 @@ theorem restrict_maximallyMixed {L : LocalNet} {Λ Λ_total : Finset L.sites} exact_mod_cast (Fintype.card_pos (α := L.regionIdx Λ)).ne' have hdComp : (Fintype.card (L.regionIdx (Λ_total \ Λ)) : ℂ) ≠ 0 := by exact_mod_cast (Fintype.card_pos (α := L.regionIdx (Λ_total \ Λ))).ne' - rw [LocalNet.card_regionIdx_total (L := L) h] + rw [SiteIndexSystem.card_regionIdx_total (L := L) h] have h_inv_mul : ((((Fintype.card (L.regionIdx Λ) : ℂ) * (Fintype.card (L.regionIdx (Λ_total \ Λ)) : ℂ)))⁻¹) * @@ -64,7 +64,7 @@ namespace DensityMatrix /-- The regularization commutes with `restrict` (Matrix-level): `restrict h (regularize ρ ε).toMatrix = (regularize (restrict h ρ) ε).toMatrix`. -/ -theorem regularize_restrict_toMatrix {L : LocalNet} {Λ Λ_total : Finset L.sites} +theorem regularize_restrict_toMatrix {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) [Nonempty (L.regionIdx Λ)] [Nonempty (L.regionIdx Λ_total)] (ρ : L.densityMatrix Λ_total) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : Matrix.restrict h (regularize ρ hε hε').toMatrix = @@ -77,7 +77,7 @@ theorem regularize_restrict_toMatrix {L : LocalNet} {Λ Λ_total : Finset L.site /-- The regularization commutes with `restrict` (DensityMatrix-level): `(regularize ρ ε).restrict h = regularize (restrict h ρ) ε`. -/ -theorem regularize_restrict {L : LocalNet} {Λ Λ_total : Finset L.sites} +theorem regularize_restrict {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) [Nonempty (L.regionIdx Λ)] [Nonempty (L.regionIdx Λ_total)] (ρ : L.densityMatrix Λ_total) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : restrict h (regularize ρ hε hε') = diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean index ac2406c..f50f8cf 100644 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean @@ -5,9 +5,9 @@ public import QuantumSystem.Analysis.Entropy.Regularize public import QuantumSystem.Analysis.Matrix.KroneckerPartialTraceBridge /-! -# Strong subadditivity of the von Neumann entropy (LocalNet form) +# Strong subadditivity of the von Neumann entropy (SiteIndexSystem form) -For a quantum system on a `LocalNet L`, the public theorem in this file is stated +For a quantum system on a `SiteIndexSystem L`, the public theorem in this file is stated in a **common-region-explicit** form. Given regions - `ΛAB ⊆ ΛABC`, @@ -47,7 +47,7 @@ AQFT-natural form: applied twice — once for the `(ΛA vs ΛABC \ ΛA)` bipartition of the full system, once for the `(ΛA vs ΛAB \ ΛA)` bipartition of the `ΛAB`-marginal. 2. The **data-processing inequality** for relative entropy - (`Matrix.relativeEntropy_channel_le`) applied to the LocalNet + (`Matrix.relativeEntropy_channel_le`) applied to the SiteIndexSystem `Matrix.QuantumChannel.restrict` channel for the inclusion `ΛAB ⊆ ΛABC`. ## Main results @@ -55,7 +55,7 @@ AQFT-natural form: * `Matrix.relativeEntropy_kronecker_marginals_product` — product-type mutual-information identity. * `DensityMatrix.vonNeumannEntropy_SSA_localNet` — SSA for arbitrary states on a - `LocalNet`, with the common region and split equalities explicit. + `SiteIndexSystem`, with the common region and split equalities explicit. The same inequality on a plain tensor product `A × B × C` is the companion `DensityMatrix.vonNeumannEntropy_SSA_product` (`StrongSubadditivityProduct.lean`). @@ -69,19 +69,19 @@ The same inequality on a plain tensor product `A × B × C` is the companion @[expose] public section -/-! ### Strong subadditivity (LocalNet form, PosDef case) +/-! ### Strong subadditivity (SiteIndexSystem form, PosDef case) The main theorem. We use the bipartite mutual-information identity twice (for `(A vs BC)` and for `(A vs B)` within `ρ ↾ {A, B}`) and the data-processing -inequality on the LocalNet `restrict` channel for `{A, B} ⊆ univ`. -/ +inequality on the SiteIndexSystem `restrict` channel for `{A, B} ⊆ univ`. -/ namespace DensityMatrix open scoped Kronecker MatrixOrder ComplexOrder open scoped Matrix.QuantumInfo -open scoped LocalNet.QuantumInfo +open scoped SiteIndexSystem.QuantumInfo -variable {L : LocalNet} +variable {L : SiteIndexSystem} /-! #### Split-explicit nested-region SSA @@ -101,7 +101,7 @@ Given nested regions `ΛA ⊆ ΛAB ⊆ ΛABC`, write the middle/common region as This statement contains the split subset in the hypotheses and does not rely on site names such as `a b c` or product-factor names such as `A/B`. -/ private lemma vonNeumannEntropy_SSA_localNet_posDef_nested - {L : LocalNet} {ΛA ΛAB ΛABC : Finset L.sites} + {L : SiteIndexSystem} {ΛA ΛAB ΛABC : Finset L.sites} (h_AB : ΛAB ⊆ ΛABC) (h_A : ΛA ⊆ ΛAB) (ρ_ABC : L.densityMatrix ΛABC) (h_ABC_pos : ρ_ABC.toMatrix.PosDef) @@ -251,7 +251,7 @@ private lemma vonNeumannEntropy_SSA_localNet_posDef_nested by_cases hv_in_AB : v ∈ ΛAB · have hv_in_combine : v ∈ ΛAB \ ΛA := Finset.mem_sdiff.mpr ⟨hv_in_AB, (Finset.mem_sdiff.mp hv).2⟩ - rw [LocalNet.combineIdx_apply_mem h_B_in_BC _ _ ⟨v, hv⟩ hv_in_combine] + rw [SiteIndexSystem.combineIdx_apply_mem h_B_in_BC _ _ ⟨v, hv⟩ hv_in_combine] exact dif_pos hv_in_AB · have hv_not_in_combine : v ∉ ΛAB \ ΛA := fun h_in => hv_in_AB (Finset.mem_sdiff.mp h_in).1 @@ -259,9 +259,9 @@ private lemma vonNeumannEntropy_SSA_localNet_posDef_nested Finset.mem_sdiff.mpr ⟨(Finset.mem_sdiff.mp hv).1, hv_in_AB⟩ have hv_compl_compl : v ∈ (ΛABC \ ΛA) \ (ΛAB \ ΛA) := Finset.mem_sdiff.mpr ⟨hv, hv_not_in_combine⟩ - rw [LocalNet.combineIdx_apply_not_mem h_B_in_BC _ _ ⟨v, hv⟩ hv_not_in_combine, + rw [SiteIndexSystem.combineIdx_apply_not_mem h_B_in_BC _ _ ⟨v, hv⟩ hv_not_in_combine, show L.regionIdxCongr h_compl_eq.symm γ ⟨v, hv_compl_compl⟩ = γ ⟨v, hv_compl⟩ - from LocalNet.regionIdxCongr_apply (L := L) h_compl_eq.symm γ hv_compl hv_compl_compl] + from SiteIndexSystem.regionIdxCongr_apply (L := L) h_compl_eq.symm γ hv_compl hv_compl_compl] exact dif_neg hv_in_AB rw [hR_eq p.2, hR_eq p'.2] rfl @@ -330,14 +330,14 @@ user-facing `S(restrict h_BC ρ)` (with `{b,c}`) to the bipartite-natural form `S(restrict sdiff_subset ρ)` (with `{a,b,c} \ {a}`). -/ private lemma vonNeumannEntropy_restrict_finset_eq - {L : LocalNet} {Λ Λ' Λ_total : Finset L.sites} (h_eq : Λ = Λ') + {L : SiteIndexSystem} {Λ Λ' Λ_total : Finset L.sites} (h_eq : Λ = Λ') (h : Λ ⊆ Λ_total) (h' : Λ' ⊆ Λ_total) (ρ : L.densityMatrix Λ_total) : S(ρ ↾[h]) = S(ρ ↾[h']) := by subst h_eq rfl private lemma posDef_restrict_finset_eq - {L : LocalNet} {Λ Λ' Λ_total : Finset L.sites} (h_eq : Λ = Λ') + {L : SiteIndexSystem} {Λ Λ' Λ_total : Finset L.sites} (h_eq : Λ = Λ') (h : Λ ⊆ Λ_total) (h' : Λ' ⊆ Λ_total) (ρ : L.densityMatrix Λ_total) : (ρ ↾[h]).toMatrix.PosDef ↔ (ρ ↾[h']).toMatrix.PosDef := by subst h_eq @@ -359,7 +359,7 @@ the names `a b c` or from a product-factor order. Instead it receives explicit d Under PosDef hypotheses for the displayed marginals, the conclusion is exactly `S(ρ_ABC ↾ ΛAB) + S(ρ_ABC ↾ ΛBC) ≥ S(ρ_ABC) + S(ρ_ABC ↾ ΛB)`. -/ private lemma vonNeumannEntropy_SSA_localNet_posDef - {L : LocalNet} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} + {L : SiteIndexSystem} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} (h_AB_total : ΛAB ⊆ ΛABC) (h_A_in_AB : ΛA ⊆ ΛAB) (h_BC_total : ΛBC ⊆ ΛABC) (h_B_total : ΛB ⊆ ΛABC) (h_B_eq : ΛAB \ ΛA = ΛB) (h_BC_eq : ΛABC \ ΛA = ΛBC) @@ -408,7 +408,7 @@ The proof regularises `ρ` to the PosDef state `(1 - ε) ρ + ε · π_ΛABC` fo applies `vonNeumannEntropy_SSA_localNet_posDef`, and passes to the limit `ε → 0⁺` via the eigenvalue continuity formulas in `Regularize.lean`. -/ theorem vonNeumannEntropy_SSA_localNet - {L : LocalNet} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} + {L : SiteIndexSystem} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} (h_AB : ΛAB ⊆ ΛABC) (h_A : ΛA ⊆ ΛAB) (h_BC : ΛBC ⊆ ΛABC) (h_B : ΛB ⊆ ΛABC) (h_B_eq : ΛAB \ ΛA = ΛB) (h_BC_eq : ΛABC \ ΛA = ΛBC) diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean index c2d4876..8295b8f 100644 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean @@ -4,20 +4,20 @@ public import QuantumSystem.Analysis.Channel.PartialTrace public import QuantumSystem.Analysis.Entropy.MutualInfoProduct /-! -# Strong subadditivity of the von Neumann entropy (product form, LocalNet-free) +# Strong subadditivity of the von Neumann entropy (product form, `SiteIndexSystem`-free) This file proves strong subadditivity (SSA) directly on plain product index types `A × B × C`, with marginals taken by the positional partial traces `Matrix.traceLeft` / -`Matrix.traceRight`. It uses NO `LocalNet`, `regionIdx`, `combineIdx`, `restrict`, or three-site -net: the proof is the bare finite-dimensional quantum-information argument +`Matrix.traceRight`. It uses NO `SiteIndexSystem`, `regionIdx`, `combineIdx`, `restrict`, or +three-site net: the proof is the bare finite-dimensional quantum-information argument 1. the mutual-information identity `Matrix.relativeEntropy_kronecker_marginals_product` (applied to the `(A : B×C)` and `(A : B)` bipartitions), and 2. the data-processing inequality `Matrix.relativeEntropy_channel_le` for the trace-out-`C` channel `Matrix.QuantumChannel.traceOutC`. -The `LocalNet`/AQFT companion — the same inequality stated over an abstract local net with -overlapping regions — is `DensityMatrix.vonNeumannEntropy_SSA_localNet` +The `SiteIndexSystem`/AQFT companion — the same inequality stated over a lattice system +with overlapping regions — is `DensityMatrix.vonNeumannEntropy_SSA_localNet` (`StrongSubadditivityLocalNet.lean`). ## Main results diff --git a/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean b/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean index b4d8336..2d2d89e 100644 --- a/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean +++ b/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean @@ -4,12 +4,12 @@ public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Matrix.PartialTrace /-! -# LocalNet bridge: restriction as an equivalence-indexed partial trace +# SiteIndexSystem bridge: restriction as an equivalence-indexed partial trace -These lemmas identify the `LocalNet` restriction `Matrix.restrict` with the equivalence-indexed -partial trace `Matrix.partialTrace` of the reindexed matrix induced by `LocalNet.combineIdx`. +These lemmas identify the `SiteIndexSystem` restriction `Matrix.restrict` with the equivalence-indexed +partial trace `Matrix.partialTrace` of the reindexed matrix induced by `SiteIndexSystem.combineIdx`. They are factored out of `Analysis/Entropy/KroneckerProduct.lean` so that the Kronecker-product -and product-type partial-trace API there stays `LocalNet`-free. +and product-type partial-trace API there stays `SiteIndexSystem`-free. -/ @[expose] public section @@ -18,14 +18,14 @@ namespace Matrix open scoped Kronecker MatrixOrder ComplexOrder -/-! ### LocalNet bridge +/-! ### SiteIndexSystem bridge -These lemmas identify `Matrix.restrict` on a `LocalNet` with the equivalence-indexed -partial trace of the reindexed matrix induced by `LocalNet.combineIdx`. -/ +These lemmas identify `Matrix.restrict` on a `SiteIndexSystem` with the equivalence-indexed +partial trace of the reindexed matrix induced by `SiteIndexSystem.combineIdx`. -/ section LocalNetBridge -variable {L : LocalNet} +variable {L : SiteIndexSystem} /-- Combining via `h : Λ ⊆ Λ_total` agrees with combining via the complementary split, after transporting the remaining factor along `Λ_total \ (Λ_total \ Λ) = Λ`. -/ @@ -42,12 +42,12 @@ private lemma combineIdx_swap_apply have hs_recast : s ∈ Λ_total \ (Λ_total \ Λ) := by rw [h_eq] exact hsΛ - rw [LocalNet.combineIdx_apply_mem h _ _ ⟨s, hs⟩ hsΛ, - LocalNet.combineIdx_apply_not_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hns_compl, - LocalNet.regionIdxCongr_apply (L := L) h_eq.symm x hsΛ hs_recast] + rw [SiteIndexSystem.combineIdx_apply_mem h _ _ ⟨s, hs⟩ hsΛ, + SiteIndexSystem.combineIdx_apply_not_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hns_compl, + SiteIndexSystem.regionIdxCongr_apply (L := L) h_eq.symm x hsΛ hs_recast] · have hs_compl : s ∈ Λ_total \ Λ := Finset.mem_sdiff.mpr ⟨hs, hsΛ⟩ - rw [LocalNet.combineIdx_apply_not_mem h _ _ ⟨s, hs⟩ hsΛ, - LocalNet.combineIdx_apply_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hs_compl] + rw [SiteIndexSystem.combineIdx_apply_not_mem h _ _ ⟨s, hs⟩ hsΛ, + SiteIndexSystem.combineIdx_apply_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hs_compl] /-- Restriction to `Λ` equals the partial trace of the reindexed matrix induced by `combineIdx h`, retaining the `Λ` factor. -/ diff --git a/QuantumSystem/Analysis/Matrix/PartialTrace.lean b/QuantumSystem/Analysis/Matrix/PartialTrace.lean index 3236955..87b6aa4 100644 --- a/QuantumSystem/Analysis/Matrix/PartialTrace.lean +++ b/QuantumSystem/Analysis/Matrix/PartialTrace.lean @@ -7,14 +7,14 @@ public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace # Partial trace as restriction (matrix-level) The **restriction** (Schrödinger-picture partial trace) on the matrix algebra of a local -net. Given regions `Λ ⊆ Λ_total` of a `LocalNet`, the restriction of a matrix on +net. Given regions `Λ ⊆ Λ_total` of a `SiteIndexSystem`, the restriction of a matrix on `𝔄(Λ_total)` to `𝔄(Λ)` is defined as the partial trace over the complementary region `Λ_total \ Λ`. This is the Schrödinger-picture dual of the algebra inclusion `𝔄(Λ) ↪ 𝔄(Λ_total)`. There is no positional ("left/right") concept — the operation is parameterised by the region itself. The matrix-level operation `Matrix.restrict` is defined as a linear map factoring through -`LocalNet.combineIdx` (which factors `regionIdx Λ_total ≃ regionIdx Λ × regionIdx (Λ_total \ Λ)`). +`SiteIndexSystem.combineIdx` (which factors `regionIdx Λ_total ≃ regionIdx Λ × regionIdx (Λ_total \ Λ)`). The bundled quantum-channel structure, Kraus operators, trace preservation, and Heisenberg-picture duality are also provided. @@ -45,7 +45,7 @@ Heisenberg-picture duality are also provided. namespace Matrix -variable {L : LocalNet} +variable {L : SiteIndexSystem} /-! ### Linear restriction map -/ @@ -234,11 +234,11 @@ lemma combineIdx_assoc_aux else γ ⟨s.val, Finset.mem_sdiff.mpr ⟨hsΛ, hsΛ'⟩⟩ else β ⟨s.val, Finset.mem_sdiff.mpr ⟨s.property, hsΛ⟩⟩ := by by_cases hsΛ : s.val ∈ Λ - · rw [LocalNet.combineIdx_apply_mem h₁ _ _ s hsΛ, dif_pos hsΛ] + · rw [SiteIndexSystem.combineIdx_apply_mem h₁ _ _ s hsΛ, dif_pos hsΛ] by_cases hsΛ' : s.val ∈ Λ' - · rw [LocalNet.combineIdx_apply_mem h₂ _ _ ⟨s.val, hsΛ⟩ hsΛ', dif_pos hsΛ'] - · rw [LocalNet.combineIdx_apply_not_mem h₂ _ _ ⟨s.val, hsΛ⟩ hsΛ', dif_neg hsΛ'] - · rw [LocalNet.combineIdx_apply_not_mem h₁ _ _ s hsΛ, dif_neg hsΛ] + · rw [SiteIndexSystem.combineIdx_apply_mem h₂ _ _ ⟨s.val, hsΛ⟩ hsΛ', dif_pos hsΛ'] + · rw [SiteIndexSystem.combineIdx_apply_not_mem h₂ _ _ ⟨s.val, hsΛ⟩ hsΛ', dif_neg hsΛ'] + · rw [SiteIndexSystem.combineIdx_apply_not_mem h₁ _ _ s hsΛ, dif_neg hsΛ] /-- Splitting a `regionIdx (Λ_total \ Λ')` into its `(Λ \ Λ')` and `(Λ_total \ Λ)` parts. Used by `restrict_restrict` to convert iterated marginalisation into a single one, @@ -286,9 +286,9 @@ lemma combineIdx_assoc_eq {Λ' Λ Λ_total : Finset L.sites} rw [combineIdx_assoc_aux h₁ h₂] by_cases hsΛ' : s.val ∈ Λ' · have hsΛ : s.val ∈ Λ := h₂ hsΛ' - rw [LocalNet.combineIdx_apply_mem (h₂.trans h₁) _ _ s hsΛ', + rw [SiteIndexSystem.combineIdx_apply_mem (h₂.trans h₁) _ _ s hsΛ', dif_pos hsΛ, dif_pos hsΛ'] - · rw [LocalNet.combineIdx_apply_not_mem (h₂.trans h₁) _ _ s hsΛ'] + · rw [SiteIndexSystem.combineIdx_apply_not_mem (h₂.trans h₁) _ _ s hsΛ'] by_cases hsΛ : s.val ∈ Λ · rw [dif_pos hsΛ, dif_neg hsΛ'] simp [restrictAssocEquiv, hsΛ] @@ -372,9 +372,9 @@ theorem trace_mul_includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_t L.includeAlgebra h X (L.combineIdx h (a', b')) (L.combineIdx h (a, b))) = ρ (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) * X a' a from by rw [Finset.sum_eq_single b] - · rw [LocalNet.includeAlgebra_apply_combineIdx]; simp + · rw [SiteIndexSystem.includeAlgebra_apply_combineIdx]; simp · intro b' _ hb' - rw [LocalNet.includeAlgebra_apply_combineIdx, if_neg hb'] + rw [SiteIndexSystem.includeAlgebra_apply_combineIdx, if_neg hb'] ring · simp] -- Combine: LHS = ∑ a, ∑ b, ∑ a', ... = ∑ a, ∑ a', ∑ b, ... = RHS @@ -386,7 +386,7 @@ end Matrix namespace DensityMatrix -variable {L : LocalNet} +variable {L : SiteIndexSystem} /-- Restriction of a density matrix to a sub-region (= partial trace over the complement). -/ noncomputable def restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) @@ -421,7 +421,7 @@ The subset proof is auto-resolved by trying, in order: `Finset.subset_univ _` For raw `Matrix`-level work, use `Matrix.restrict h M` (no notation provided to keep `↾` unambiguous on the density-matrix surface). -/ -namespace LocalNet +namespace SiteIndexSystem namespace QuantumInfo scoped syntax:65 term:65 " ↾ " term:66 : term @@ -436,4 +436,4 @@ scoped macro_rules | `($ρ ↾[$h]) => `(DensityMatrix.restrict $h $ρ) end QuantumInfo -end LocalNet +end SiteIndexSystem diff --git a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean index 42af36d..a61d2eb 100644 --- a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean +++ b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean @@ -7,8 +7,8 @@ public import Mathlib.Analysis.InnerProductSpace.Trace /-! # The partial trace is the operator form of `restrict` -Completing the operator-level tensor decomposition (`LocalNet.tensorEquiv`, -`LocalNet.opEquiv_includeAlgebra`), this file shows that the marginal `Matrix.restrict` is, under +Completing the operator-level tensor decomposition (`SiteIndexSystem.tensorEquiv`, +`SiteIndexSystem.opEquiv_includeAlgebra`), this file shows that the marginal `Matrix.restrict` is, under the operator identifications, exactly the **partial trace** over the complementary Hilbert-space factor: tracing out `ℋ (Λ_total \ Λ)`. @@ -26,9 +26,9 @@ operators on Hilbert spaces. open WithLp open scoped TensorProduct Matrix -namespace LocalNet +namespace SiteIndexSystem -variable (L : LocalNet) +variable (L : SiteIndexSystem) /-- Matrix entries of `(opEquiv Λ).symm T`: the `(i, j)` entry is the `i`-coordinate of the image of the `j`-th standard basis vector under the operator `T`. (Internal helper.) -/ @@ -89,4 +89,4 @@ theorem opEquiv_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) rw [L.opEquiv_restrict_aux, LinearMap.partialTrace_apply] congr 1 -end LocalNet +end SiteIndexSystem diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean index d7efa2e..3718418 100644 --- a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean @@ -152,7 +152,7 @@ theorem PosDef.map_starAlgEquiv {M : Matrix m m ℂ} (hM : M.PosDef) `Equiv`-flavoured restatements derived from `PosSemidef.map_starAlgEquiv` and `PosDef.map_starAlgEquiv`, useful when an index-set bijection `e : n ≃ m` -is naturally available (e.g. from `LocalNet` region equivalences). -/ +is naturally available (e.g. from region index-set equivalences). -/ omit [Fintype m] [Fintype n] [DecidableEq m] [DecidableEq n] in /-- `Matrix.PosSemidef` is preserved by reindexing the index set via a bijection. diff --git a/QuantumSystem/Notation.lean b/QuantumSystem/Notation.lean index 776a3bb..852d7a8 100644 --- a/QuantumSystem/Notation.lean +++ b/QuantumSystem/Notation.lean @@ -17,7 +17,7 @@ Notations and abbreviations for quantum information theory. | `S(ρ)` | `Matrix.vonNeumannEntropy ρ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/VonNeumannEntropy.lean` | | `D(ρ ∥ σ)` | `Matrix.relativeEntropy ρ σ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/RelativeEntropy.lean` | | `⟪X, Y⟫_HS` | `Matrix.hsInnerProduct X Y` | `open scoped Matrix.QuantumInfo` | `Analysis/Matrix/LiebConcavity.lean` | -| `ρ ↾ Λ` | `DensityMatrix.restrict (by …) ρ` | `open scoped LocalNet.QuantumInfo` | `Algebra/LocalNet/Basic.lean` | +| `ρ ↾ Λ` | `DensityMatrix.restrict (by …) ρ` | `open scoped SiteIndexSystem.QuantumInfo` | `Analysis/Matrix/PartialTrace.lean` | `ρ ↾ Λ` is the AQFT-style **restriction of a density matrix to a sub-region** — equivalently, the partial trace over the complementary region. From 97edbe3a6aafe8c9d4c751a40b766d67a3aa1b54 Mon Sep 17 00:00:00 2001 From: suzuki Date: Thu, 25 Jun 2026 15:46:10 +0000 Subject: [PATCH 020/113] feat(formathlib): add completion functoriality for star-algebra equivalences Add `UniformSpace.Completion.mapStarAlgEquiv`: a uniformly continuous `*`-algebra equivalence whose inverse is also uniformly continuous extends, by continuity on the dense image, to a `*`-algebra equivalence of the completions. Mirrors Mathlib's `mapRingHom`/`coe_mapRingHom` for ring homs. This is the supporting infrastructure for extending the AQFT covariance action to the quasi-local C*-algebra. Candidate for upstreaming. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Topology/Algebra/CStarCompletion.lean | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean b/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean index d7fd0b2..f04d988 100644 --- a/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean +++ b/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean @@ -11,7 +11,9 @@ The completion of a normed `*`-algebra is again a normed `*`-algebra, and the co `NormedRing`, `NormedAlgebra` and `CompleteSpace` instances on `UniformSpace.Completion`; this file adds the missing `Star`, `StarRing`, `NormedStarGroup`, `CStarRing` and `StarModule` instances, obtained by extending the operations on the dense image by continuity, and assembles -them into a `CStarAlgebra` instance. +them into a `CStarAlgebra` instance. It also records the **functoriality** of the completion for +`*`-algebra equivalences (`mapStarAlgEquiv`): a uniformly continuous `*`-isomorphism with uniformly +continuous inverse extends to a `*`-isomorphism of the completions. These are general facts about completions and are candidates for upstreaming to Mathlib. -/ @@ -75,8 +77,8 @@ variable [NormedRing A] [StarRing A] [NormedStarGroup A] [CStarRing A] instance : CStarRing (Completion A) where norm_mul_self_le a := by refine induction_on a - (isClosed_le (continuous_norm.mul continuous_norm) (continuous_id.star.mul continuous_id).norm) - ?_ + (isClosed_le (continuous_norm.mul continuous_norm) + (continuous_id.star.mul continuous_id).norm) ?_ intro a rw [star_coe, ← coe_mul, norm_coe, norm_coe] exact CStarRing.norm_mul_self_le a @@ -114,4 +116,64 @@ noncomputable instance instNormedAlgebraOfNormedRing {𝕜 : Type*} [NormedField noncomputable instance instCStarAlgebra [NormedRing A] [StarRing A] [NormedStarGroup A] [CStarRing A] [NormedAlgebra ℂ A] [StarModule ℂ A] : CStarAlgebra (Completion A) where +section MapStarAlgEquiv + +variable {𝕜 A B : Type*} [NormedField 𝕜] + [NormedRing A] [NormedAlgebra 𝕜 A] [StarRing A] [NormedStarGroup A] + [NormedRing B] [NormedAlgebra 𝕜 B] [StarRing B] [NormedStarGroup B] + +/-- **Functoriality of the completion for star algebra equivalences**: a uniformly continuous +`*`-algebra equivalence whose inverse is also uniformly continuous extends, by continuity on the +dense image, to a `*`-algebra equivalence of the completions. (In particular every `*`-isomorphism +of C⋆-normed algebras, being isometric, extends to the completions.) -/ +noncomputable def mapStarAlgEquiv (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) + (he' : UniformContinuous e.symm) : Completion A ≃⋆ₐ[𝕜] Completion B where + toFun := Completion.map e + invFun := Completion.map e.symm + left_inv x := by + refine induction_on x (isClosed_eq (continuous_map.comp continuous_map) continuous_id) ?_ + intro a + rw [map_coe he, map_coe he', StarAlgEquiv.symm_apply_apply] + right_inv x := by + refine induction_on x (isClosed_eq (continuous_map.comp continuous_map) continuous_id) ?_ + intro a + rw [map_coe he', map_coe he, StarAlgEquiv.apply_symm_apply] + map_mul' x y := by + refine induction_on₂ x y + (isClosed_eq ((continuous_map (f := ⇑e)).comp continuous_mul) + (((continuous_map (f := ⇑e)).comp continuous_fst).mul + ((continuous_map (f := ⇑e)).comp continuous_snd))) ?_ + intro a b + rw [← coe_mul, map_coe he, map_coe he, map_coe he, ← coe_mul, map_mul] + map_add' x y := by + refine induction_on₂ x y + (isClosed_eq ((continuous_map (f := ⇑e)).comp continuous_add) + (((continuous_map (f := ⇑e)).comp continuous_fst).add + ((continuous_map (f := ⇑e)).comp continuous_snd))) ?_ + intro a b + rw [← coe_add, map_coe he, map_coe he, map_coe he, ← coe_add, map_add] + map_smul' c x := by + refine induction_on x + (isClosed_eq (continuous_map.comp (continuous_const_smul c)) + ((continuous_const_smul c).comp continuous_map)) ?_ + intro a + rw [← coe_smul, map_coe he, map_coe he, ← coe_smul, map_smul] + map_star' x := by + refine induction_on x + (isClosed_eq (continuous_map.comp continuous_star) (continuous_star.comp continuous_map)) ?_ + intro a + rw [star_coe, map_coe he, map_coe he, star_coe, map_star] + +@[simp] theorem mapStarAlgEquiv_coe (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) + (he' : UniformContinuous e.symm) (a : A) : + mapStarAlgEquiv e he he' (↑a : Completion A) = (↑(e a) : Completion B) := + map_coe he a + +theorem coe_mapStarAlgEquiv (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) + (he' : UniformContinuous e.symm) : + ⇑(mapStarAlgEquiv e he he') = Completion.map e := + rfl + +end MapStarAlgEquiv + end UniformSpace.Completion From e0e29c86bd229ec29b4a777f49392f7be04461ff Mon Sep 17 00:00:00 2001 From: suzuki Date: Thu, 25 Jun 2026 15:46:23 +0000 Subject: [PATCH 021/113] feat(localnet): act on the quasi-local C*-algebra by covariant star-automorphisms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each covariance isomorphism `β` is a `*`-isomorphism, so the action `quasiLocalRelabel` is C-linear and `*`-preserving. Package this as a `*`-algebra automorphism `quasiLocalRelabelStarEquiv : 𝔄_loc ≃⋆ₐ[C] 𝔄_loc` and a group homomorphism `quasiLocalRelabelStarHom` into its `*`-automorphism group. For a faithful net the action is isometric, so it extends along the completion to `quasiLocalCStarRelabel : 𝔄 ≃⋆ₐ[C] 𝔄` and a group homomorphism `quasiLocalCStarRelabelHom` — the genuine AQFT covariant automorphic action on the quasi-local C*-algebra. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem/Algebra/LocalNet/Net.lean | 163 +++++++++++++++++++++++- 1 file changed, 162 insertions(+), 1 deletion(-) diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 34b2199..d61ac25 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -33,7 +33,14 @@ On any local net this file builds, once and for all: `Symmetry.id`/`Symmetry.comp`/`Symmetry.inv`), and the purely algebraic action `Symmetry.quasiLocalRelabel` on the algebra of local observables, which is a monoid homomorphism out of that group (`quasiLocalRelabel_one`/`quasiLocalRelabel_mul`) — so a group `G` acting on - the net (a hom `G →* N.Symmetry`) acts on the local observables by `*`-endomorphisms. + the net (a hom `G →* N.Symmetry`) acts on the local observables by `*`-endomorphisms. Since each + `β` is a `*`-isomorphism this action is in fact by `*`-algebra automorphisms: + `Symmetry.quasiLocalRelabelStarEquiv` packages each symmetry as a `*`-algebra automorphism + `𝔄_loc ≃⋆ₐ[ℂ] 𝔄_loc` and `Symmetry.quasiLocalRelabelStarHom` bundles them into a group + homomorphism into its `*`-automorphism group. For a **faithful** net the action is isometric, so + `Symmetry.quasiLocalCStarRelabel` extends it to a `*`-automorphism `𝔄 ≃⋆ₐ[ℂ] 𝔄` of the quasi-local + C⋆-algebra and `Symmetry.quasiLocalCStarRelabelHom` to a group homomorphism — the genuine AQFT + covariant automorphic action. The injectivity needed for the C⋆-norm is carried by the separate `Faithful` typeclass rather than a structure field, so that the purely algebraic constructions (`quasiLocalAlgebra`, @@ -453,6 +460,160 @@ theorem quasiLocalRelabel_mul (a b : N.Symmetry) : (a * b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by rw [mul_def, quasiLocalRelabel_comp] +/-! #### The covariance action as a `*`-automorphism + +The ring endomorphism `quasiLocalRelabel` is in fact `ℂ`-linear and `*`-preserving, since each +covariance isomorphism `β` is a `*`-isomorphism. Recording this upgrades the action to a genuine +`*`-algebra automorphism `≃⋆ₐ[ℂ]` and the assignment to a group homomorphism into the +`*`-automorphism group — the AQFT covariance action on the algebra of local observables. -/ + +/-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ +theorem quasiLocalRelabel_smul (c : ℂ) (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabel (c • z) = c • a.quasiLocalRelabel z := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [DirectLimit.smul_def, quasiLocalRelabel_mk, quasiLocalRelabel_mk, DirectLimit.smul_def, + map_smul] + rfl + +/-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` + is a `*`-isomorphism. -/ +theorem quasiLocalRelabel_star (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabel (star z) = star (a.quasiLocalRelabel z) := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [star_mk, quasiLocalRelabel_mk, quasiLocalRelabel_mk, star_mk, map_star] + rfl + +/-- The **covariance action** of a symmetry as a `*`-algebra automorphism `𝔄_loc ≃⋆ₐ[ℂ] 𝔄_loc` of + the algebra of local observables, with the action of the inverse symmetry `a⁻¹` as its inverse. + This is the AQFT covariance automorphism at the level of the (incomplete) algebra of local + observables; its continuous extension to the quasi-local C⋆-algebra is `quasiLocalCStarRelabel` + (for a faithful net). -/ +noncomputable def quasiLocalRelabelStarEquiv : + N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where + toFun := a.quasiLocalRelabel + invFun := a⁻¹.quasiLocalRelabel + left_inv z := by + rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, inv_mul_cancel, quasiLocalRelabel_one, + RingHom.id_apply] + right_inv z := by + rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, mul_inv_cancel, quasiLocalRelabel_one, + RingHom.id_apply] + map_mul' := map_mul a.quasiLocalRelabel + map_add' := map_add a.quasiLocalRelabel + map_smul' := a.quasiLocalRelabel_smul + map_star' := a.quasiLocalRelabel_star + +@[simp] theorem quasiLocalRelabelStarEquiv_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabelStarEquiv z = a.quasiLocalRelabel z := rfl + +@[simp] theorem quasiLocalRelabelStarEquiv_symm_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabelStarEquiv.symm z = a⁻¹.quasiLocalRelabel z := rfl + +/-- A symmetry of the net acts on the algebra of local observables by `*`-algebra automorphisms, + assembled as a **group homomorphism** into the `*`-automorphism group `𝔄_loc ≃⋆ₐ[ℂ] 𝔄_loc`. + This is the covariance action of the symmetry group, upgrading the monoid-homomorphic + endomorphism action (`quasiLocalRelabel_one`/`quasiLocalRelabel_mul`) to a group action by + automorphisms that tracks the `ℂ`-linear and `*`-structure. -/ +noncomputable def quasiLocalRelabelStarHom : + N.Symmetry →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where + toFun a := a.quasiLocalRelabelStarEquiv + map_one' := by + ext z + simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_one, RingHom.id_apply, + StarAlgEquiv.one_apply] + map_mul' a b := by + ext z + simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_mul, RingHom.comp_apply, + StarAlgEquiv.mul_apply] + +@[simp] theorem quasiLocalRelabelStarHom_apply (z : N.quasiLocalAlgebra) : + quasiLocalRelabelStarHom a z = a.quasiLocalRelabel z := rfl + +/-! #### The covariance automorphism of the quasi-local C⋆-algebra + +For a **faithful** net the covariance action is *isometric* — each `β` is a `*`-isomorphism of +C⋆-algebras, hence norm-preserving (`StarAlgEquiv.norm_map`) — so `quasiLocalRelabelStarEquiv` is +uniformly continuous and extends, by the functoriality of completion (`mapStarAlgEquiv`), to a +`*`-automorphism of the quasi-local C⋆-algebra `𝔄`. This is the genuine AQFT covariance +automorphism on `𝔄`, and the assignment is a group homomorphism. -/ + +section CStarCovariance + +variable [N.Faithful] + +/-- The covariance action is **isometric** on the algebra of local observables: each `β` is a + `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ +theorem quasiLocalRelabel_norm (z : N.quasiLocalAlgebra) : + ‖a.quasiLocalRelabel z‖ = ‖z‖ := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [quasiLocalRelabel_mk, norm_mk, norm_mk] + exact StarAlgEquiv.norm_map _ X + +/-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is + an isometry), so it extends to the C⋆-completion. -/ +theorem quasiLocalRelabelStarEquiv_uniformContinuous : + UniformContinuous a.quasiLocalRelabelStarEquiv := + (AddMonoidHomClass.isometry_of_norm _ (fun z => by + rw [quasiLocalRelabelStarEquiv_apply]; exact a.quasiLocalRelabel_norm z)).uniformContinuous + +/-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is + also an isometry). -/ +theorem quasiLocalRelabelStarEquiv_symm_uniformContinuous : + UniformContinuous a.quasiLocalRelabelStarEquiv.symm := by + have h : ∀ z, ‖a.quasiLocalRelabelStarEquiv.symm z‖ = ‖z‖ := fun z => by + rw [quasiLocalRelabelStarEquiv_symm_apply]; exact a⁻¹.quasiLocalRelabel_norm z + exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous + +/-- The **covariance automorphism of the quasi-local C⋆-algebra** `𝔄 ≃⋆ₐ[ℂ] 𝔄`: the continuous + extension of `quasiLocalRelabelStarEquiv` to the completion. This is the AQFT covariant + `*`-automorphism on the quasi-local C⋆-algebra of a faithful net (Naaijkens 2012 §3.2, + Bratteli–Robinson Vol.2 §6.2). -/ +noncomputable def quasiLocalCStarRelabel : + N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := + UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalRelabelStarEquiv + a.quasiLocalRelabelStarEquiv_uniformContinuous + a.quasiLocalRelabelStarEquiv_symm_uniformContinuous + +@[simp] theorem quasiLocalCStarRelabel_coe (z : N.quasiLocalAlgebra) : + a.quasiLocalCStarRelabel (↑z : N.quasiLocalCStarAlgebra) = ↑(a.quasiLocalRelabel z) := + UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z + +theorem quasiLocalCStarRelabel_continuous : + Continuous (⇑a.quasiLocalCStarRelabel) := + UniformSpace.Completion.continuous_map + +/-- A symmetry of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, + assembled as a **group homomorphism** into the `*`-automorphism group `𝔄 ≃⋆ₐ[ℂ] 𝔄`. This is the + covariance action of the symmetry group on the quasi-local C⋆-algebra — the AQFT covariant + automorphic action. -/ +noncomputable def quasiLocalCStarRelabelHom : + N.Symmetry →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where + toFun a := a.quasiLocalCStarRelabel + map_one' := by + refine StarAlgEquiv.ext fun z => ?_ + rw [StarAlgEquiv.one_apply] + refine UniformSpace.Completion.induction_on z + (isClosed_eq (1 : N.Symmetry).quasiLocalCStarRelabel_continuous continuous_id) ?_ + intro w + simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_one, RingHom.id_apply] + map_mul' a b := by + refine StarAlgEquiv.ext fun z => ?_ + rw [StarAlgEquiv.mul_apply] + refine UniformSpace.Completion.induction_on z + (isClosed_eq (a * b).quasiLocalCStarRelabel_continuous + (a.quasiLocalCStarRelabel_continuous.comp b.quasiLocalCStarRelabel_continuous)) ?_ + intro w + simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_mul, RingHom.comp_apply] + +@[simp] theorem quasiLocalCStarRelabelHom_apply + (z : N.quasiLocalCStarAlgebra) : + quasiLocalCStarRelabelHom a z = a.quasiLocalCStarRelabel z := rfl + +end CStarCovariance + end Symmetry end LocalNet From 748e51dd4ac4641211dd651dc7fcbfbfe6abe4d9 Mon Sep 17 00:00:00 2001 From: suzuki Date: Thu, 25 Jun 2026 23:29:30 +0000 Subject: [PATCH 022/113] refactor(localnet): split net monolith into focused modules Break the monolithic LocalNet/Net.lean into single-concern files: Net keeps only the abstract net axioms (structure, Faithful, algebraCongr); QuasiLocal gains the abstract quasi-local algebra section; Covariance holds the symmetry covariance action; and the new Symmetry module carries the abstract symmetry group (structure + Group instance), leaving Covariance for the action layer. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 1 + .../Algebra/LocalNet/Covariance.lean | 209 ++++++- QuantumSystem/Algebra/LocalNet/Net.lean | 543 +----------------- .../Algebra/LocalNet/QuasiLocal.lean | 129 +++++ QuantumSystem/Algebra/LocalNet/Symmetry.lean | 194 +++++++ 5 files changed, 539 insertions(+), 537 deletions(-) create mode 100644 QuantumSystem/Algebra/LocalNet/Symmetry.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 11c2530..e3f5b10 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -23,6 +23,7 @@ public import QuantumSystem.Algebra.LocalNet.Isotony public import QuantumSystem.Algebra.LocalNet.Locality public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.Symmetry public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index faefc16..cff54b8 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -1,23 +1,214 @@ module public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.Symmetry /-! -# Covariance of the local net +# Covariance action of a local net symmetry -A **symmetry** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each site, -an equivalence `localIdx s ≃ localIdx (σ s)` matching the local dimensions. Such data induces a -`*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` between the local algebras of a region and its image, -realising the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σ Λ)` (Naaijkens 2012 §3.2, Verch 2025 §1.2). +A symmetry of a local net (`LocalNet.Symmetry`, defined in `LocalNet.Symmetry`) acts on the +**algebra of local observables** by `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧`. The per-region +`*`-isomorphisms are natural with respect to isotony (`β_incl`), so they assemble into a +`*`-endomorphism `quasiLocalRelabel` of the quasi-local algebra (the covariance action). This +action is functorial in the symmetry group, `ℂ`-linear and `*`-preserving, hence a +`*`-automorphism; for a `Faithful` net it is isometric and extends to a `*`-automorphism of the +quasi-local C⋆-algebra (Naaijkens 2012 §3.2, Verch 2025 §1.2). -Symmetries compose (identity and composition below), so any group acting on the sites with -matching local dimensions acts on the net by `*`-isomorphisms. The per-region isomorphisms are -natural with respect to isotony (`relabelAlgebra_includeAlgebra`), so they assemble into a -`*`-endomorphism `quasiLocalRelabel` of the quasi-local algebra (the covariance action). +A **symmetry** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each +site, an equivalence `localIdx s ≃ localIdx (σ s)` matching the local dimensions. Such data induces +a `*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` (`relabelAlgebra`), assembling into an abstract +`LocalNet.Symmetry` of the generated net (`toLocalNetSymmetry`) and hence inheriting the covariance +action above. -/ @[expose] public section +namespace LocalNet + +variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) + +namespace Symmetry + +variable {N} (a : N.Symmetry) + +/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a symmetry on the algebra of local + observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ +noncomputable def quasiLocalRelabel : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := + DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra + (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) + (fun Λ Λ' h X => by + change N.ιLocal (a.region Λ') (a.β Λ' (N.incl h X)) = N.ιLocal (a.region Λ) (a.β Λ X) + rw [a.β_incl h] + exact N.ιLocal_incl _ _) + +@[simp] theorem quasiLocalRelabel_mk {Λ : Finset sites} (X : N.algebra Λ) : + a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := + rfl + +/-- The covariance action of the identity symmetry is the identity: `β_{id} = id`. -/ +@[simp] theorem quasiLocalRelabel_id : + (Symmetry.id N).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by + refine RingHom.ext fun z => ?_ + induction z using DirectLimit.induction with + | _ Λ X => rw [quasiLocalRelabel_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X + +/-- **Functoriality of the covariance action**: composing symmetries composes their actions, + `β_{a∘b} = β_a ∘ β_b`. -/ +@[simp] theorem quasiLocalRelabel_comp (a b : N.Symmetry) : + (a.comp b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by + refine RingHom.ext fun z => ?_ + induction z using DirectLimit.induction with + | _ Λ X => + simp only [RingHom.comp_apply, quasiLocalRelabel_mk] + exact N.ιLocal_algebraCongr _ _ + +/-- The covariance action sends the unit symmetry to the identity: `β_1 = id`. -/ +@[simp] theorem quasiLocalRelabel_one : + (1 : N.Symmetry).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by + rw [one_def, quasiLocalRelabel_id] + +/-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. -/ +theorem quasiLocalRelabel_mul (a b : N.Symmetry) : + (a * b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by + rw [mul_def, quasiLocalRelabel_comp] + +/-! #### The covariance action as a `*`-automorphism -/ + +/-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ +theorem quasiLocalRelabel_smul (c : ℂ) (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabel (c • z) = c • a.quasiLocalRelabel z := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [DirectLimit.smul_def, quasiLocalRelabel_mk, quasiLocalRelabel_mk, DirectLimit.smul_def, + map_smul] + rfl + +/-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` + is a `*`-isomorphism. -/ +theorem quasiLocalRelabel_star (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabel (star z) = star (a.quasiLocalRelabel z) := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [star_mk, quasiLocalRelabel_mk, quasiLocalRelabel_mk, star_mk, map_star] + rfl + +/-- The covariance action of a symmetry as a `*`-algebra automorphism of the algebra of local + observables, with the action of the inverse symmetry `a⁻¹` as its inverse. -/ +noncomputable def quasiLocalRelabelStarEquiv : + N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where + toFun := a.quasiLocalRelabel + invFun := a⁻¹.quasiLocalRelabel + left_inv z := by + rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, inv_mul_cancel, quasiLocalRelabel_one, + RingHom.id_apply] + right_inv z := by + rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, mul_inv_cancel, quasiLocalRelabel_one, + RingHom.id_apply] + map_mul' := map_mul a.quasiLocalRelabel + map_add' := map_add a.quasiLocalRelabel + map_smul' := a.quasiLocalRelabel_smul + map_star' := a.quasiLocalRelabel_star + +@[simp] theorem quasiLocalRelabelStarEquiv_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabelStarEquiv z = a.quasiLocalRelabel z := rfl + +@[simp] theorem quasiLocalRelabelStarEquiv_symm_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalRelabelStarEquiv.symm z = a⁻¹.quasiLocalRelabel z := rfl + +/-- A symmetry of the net acts on the algebra of local observables by `*`-algebra automorphisms, + assembled as a group homomorphism into the `*`-automorphism group. -/ +noncomputable def quasiLocalRelabelStarHom : + N.Symmetry →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where + toFun a := a.quasiLocalRelabelStarEquiv + map_one' := by + ext z + simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_one, RingHom.id_apply, + StarAlgEquiv.one_apply] + map_mul' a b := by + ext z + simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_mul, RingHom.comp_apply, + StarAlgEquiv.mul_apply] + +@[simp] theorem quasiLocalRelabelStarHom_apply (z : N.quasiLocalAlgebra) : + quasiLocalRelabelStarHom a z = a.quasiLocalRelabel z := rfl + +/-! #### The covariance automorphism of the quasi-local C⋆-algebra -/ + +section CStarCovariance + +variable [N.Faithful] + +/-- The covariance action is **isometric** on the algebra of local observables: each `β` is a + `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ +theorem quasiLocalRelabel_norm (z : N.quasiLocalAlgebra) : + ‖a.quasiLocalRelabel z‖ = ‖z‖ := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [quasiLocalRelabel_mk, norm_mk, norm_mk] + exact StarAlgEquiv.norm_map _ X + +/-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is + an isometry), so it extends to the C⋆-completion. -/ +theorem quasiLocalRelabelStarEquiv_uniformContinuous : + UniformContinuous a.quasiLocalRelabelStarEquiv := + (AddMonoidHomClass.isometry_of_norm _ (fun z => by + rw [quasiLocalRelabelStarEquiv_apply]; exact a.quasiLocalRelabel_norm z)).uniformContinuous + +/-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is + also an isometry). -/ +theorem quasiLocalRelabelStarEquiv_symm_uniformContinuous : + UniformContinuous a.quasiLocalRelabelStarEquiv.symm := by + have h : ∀ z, ‖a.quasiLocalRelabelStarEquiv.symm z‖ = ‖z‖ := fun z => by + rw [quasiLocalRelabelStarEquiv_symm_apply]; exact a⁻¹.quasiLocalRelabel_norm z + exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous + +/-- The covariance automorphism of the quasi-local C⋆-algebra: the continuous extension of + `quasiLocalRelabelStarEquiv` to the completion. -/ +noncomputable def quasiLocalCStarRelabel : + N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := + UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalRelabelStarEquiv + a.quasiLocalRelabelStarEquiv_uniformContinuous + a.quasiLocalRelabelStarEquiv_symm_uniformContinuous + +@[simp] theorem quasiLocalCStarRelabel_coe (z : N.quasiLocalAlgebra) : + a.quasiLocalCStarRelabel (↑z : N.quasiLocalCStarAlgebra) = ↑(a.quasiLocalRelabel z) := + UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z + +theorem quasiLocalCStarRelabel_continuous : + Continuous (⇑a.quasiLocalCStarRelabel) := + UniformSpace.Completion.continuous_map + +/-- A symmetry of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, + assembled as a group homomorphism into the `*`-automorphism group. -/ +noncomputable def quasiLocalCStarRelabelHom : + N.Symmetry →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where + toFun a := a.quasiLocalCStarRelabel + map_one' := by + refine StarAlgEquiv.ext fun z => ?_ + rw [StarAlgEquiv.one_apply] + refine UniformSpace.Completion.induction_on z + (isClosed_eq (1 : N.Symmetry).quasiLocalCStarRelabel_continuous continuous_id) ?_ + intro w + simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_one, RingHom.id_apply] + map_mul' a b := by + refine StarAlgEquiv.ext fun z => ?_ + rw [StarAlgEquiv.mul_apply] + refine UniformSpace.Completion.induction_on z + (isClosed_eq (a * b).quasiLocalCStarRelabel_continuous + (a.quasiLocalCStarRelabel_continuous.comp b.quasiLocalCStarRelabel_continuous)) ?_ + intro w + simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_mul, RingHom.comp_apply] + +@[simp] theorem quasiLocalCStarRelabelHom_apply + (z : N.quasiLocalCStarAlgebra) : + quasiLocalCStarRelabelHom a z = a.quasiLocalCStarRelabel z := rfl + +end CStarCovariance + +end Symmetry + +end LocalNet + namespace SiteIndexSystem /-- Pointwise value of the complement projection of `combineIdx.symm` (holds by `rfl`). -/ diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index d61ac25..a3b3d9d 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -7,44 +7,12 @@ public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion /-! # Local nets of C⋆-algebras -This file reifies the **net** of an AQFT system as a first-class object: a *local net of -C⋆-algebras* over the finite regions of a site set is the assignment `Λ ↦ 𝔄(Λ)` of a -C⋆-algebra to each finite region `Λ : Finset sites`, together with the **isotony embeddings** -`𝔄(Λ) ↪ 𝔄(Λ')` for `Λ ⊆ Λ'`, which are *functorial* (compose, and the identity inclusion is -the identity) and satisfy **locality** (observables in disjoint regions commute). This is the -data of a Haag–Kastler net specialised to a lattice of sites (Naaijkens 2012 §1.3, Verch 2025 -§1.2, Bratteli–Robinson Vol.2 §6.2). +This file contains the abstract **local net** data: finite regions are assigned local C⋆-algebras, +with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms. -The structure is genuinely abstract: it does not commit to any concrete realisation of the -local algebras. The finite-dimensional matrix net `𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` is one -instance, built from a `SiteIndexSystem` via `SiteIndexSystem.toLocalNet` -(`LocalNet.QuasiLocal`). - -On any local net this file builds, once and for all: - -* the **directed system** of `*`-algebras (`directedSystem`), via functoriality; -* the **algebra of local observables** `quasiLocalAlgebra` (the algebraic inductive limit) with - cocone `ιLocal`, exhaustion `exists_ιLocal`, and locality `ιLocal_commute_of_disjoint`; -* for a **faithful** net (`Faithful`: all inclusions injective — the standard AQFT - non-degeneracy condition), the C⋆-norm and the **quasi-local C⋆-algebra** - `quasiLocalCStarAlgebra` (its completion), with dense embeddings `ιLocalCStar`; -* the **covariance** of the net: `Symmetry` (the AQFT covariance datum `β(𝔄(Λ)) = 𝔄(σΛ)`, natural - with respect to isotony), which form a **group** under composition (`Group N.Symmetry`, with - `Symmetry.id`/`Symmetry.comp`/`Symmetry.inv`), and the purely algebraic action - `Symmetry.quasiLocalRelabel` on the algebra of local observables, which is a monoid homomorphism - out of that group (`quasiLocalRelabel_one`/`quasiLocalRelabel_mul`) — so a group `G` acting on - the net (a hom `G →* N.Symmetry`) acts on the local observables by `*`-endomorphisms. Since each - `β` is a `*`-isomorphism this action is in fact by `*`-algebra automorphisms: - `Symmetry.quasiLocalRelabelStarEquiv` packages each symmetry as a `*`-algebra automorphism - `𝔄_loc ≃⋆ₐ[ℂ] 𝔄_loc` and `Symmetry.quasiLocalRelabelStarHom` bundles them into a group - homomorphism into its `*`-automorphism group. For a **faithful** net the action is isometric, so - `Symmetry.quasiLocalCStarRelabel` extends it to a `*`-automorphism `𝔄 ≃⋆ₐ[ℂ] 𝔄` of the quasi-local - C⋆-algebra and `Symmetry.quasiLocalCStarRelabelHom` to a group homomorphism — the genuine AQFT - covariant automorphic action. - -The injectivity needed for the C⋆-norm is carried by the separate `Faithful` typeclass rather -than a structure field, so that the purely algebraic constructions (`quasiLocalAlgebra`, -`ιLocal`, and the covariance action `Symmetry.quasiLocalRelabel`) need no non-degeneracy hypothesis. +The quasi-local algebra built from a net lives in `LocalNet.QuasiLocal`; covariance actions live in +`LocalNet.Covariance`. The finite-dimensional matrix net generated by a `SiteIndexSystem` is also +packaged in `LocalNet.QuasiLocal`. -/ @[expose] public section @@ -87,151 +55,32 @@ instance directedSystem : map_self _ x := N.incl_refl x map_map _ _ _ hij hjk x := N.incl_trans hij hjk x -/-- The **algebra of local observables** of the net: the algebraic inductive limit of the local - algebras along the isotony embeddings. Its C⋆-completion is the quasi-local algebra. -/ -noncomputable abbrev quasiLocalAlgebra : Type _ := - DirectLimit N.algebra (fun _ _ h => N.incl h) - -/-- Componentwise behaviour of the involution on the algebra of local observables. The - `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general - direct-limit constructions, since each `algebra Λ` is a `ℂ`-`*`-algebra and `incl` is a - `*`-algebra homomorphism. -/ -@[simp] theorem star_mk {Λ : Finset sites} (X : N.algebra Λ) : - star (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl - -/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local - observables, as a unital ring homomorphism (the cocone of the inductive limit). -/ -noncomputable def ιLocal (Λ : Finset sites) : - N.algebra Λ →+* N.quasiLocalAlgebra := - DirectLimit.Ring.of N.algebra (fun _ _ h => N.incl h) Λ - -/-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the - larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ -@[simp] theorem ιLocal_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (X : N.algebra Λ) : - N.ιLocal Λ' (N.incl h X) = N.ιLocal Λ X := - DirectLimit.Ring.of_f (G := N.algebra) (f := fun _ _ h => N.incl h) h X - -/-- The cocone is a `*`-homomorphism: it intertwines the local and quasi-local involutions. -/ -@[simp] theorem ιLocal_star {Λ : Finset sites} (X : N.algebra Λ) : - N.ιLocal Λ (star X) = star (N.ιLocal Λ X) := - (star_mk (N := N) X).symm - -/-- **Exhaustion**: every element of the algebra of local observables is the image of a local - observable from some finite region — the union of the local algebras is the whole limit. -/ -theorem exists_ιLocal (z : N.quasiLocalAlgebra) : - ∃ (Λ : Finset sites) (X : N.algebra Λ), z = N.ιLocal Λ X := by - induction z using DirectLimit.induction with - | _ Λ X => exact ⟨Λ, X, rfl⟩ - -/-- **Locality in the algebra of local observables**: observables localised in disjoint regions - commute inside `𝔄_loc`. Lifts the net's `locality` along the ring-hom cocone. -/ -theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset sites} (hd : Disjoint Λ₁ Λ₂) - (X : N.algebra Λ₁) (Y : N.algebra Λ₂) : - Commute (N.ιLocal Λ₁ X) (N.ιLocal Λ₂ Y) := by - have h1 : N.ιLocal Λ₁ X - = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_left X) := - (N.ιLocal_incl Finset.subset_union_left X).symm - have h2 : N.ιLocal Λ₂ Y - = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_right Y) := - (N.ιLocal_incl Finset.subset_union_right Y).symm - rw [h1, h2] - exact (N.locality Finset.subset_union_left Finset.subset_union_right hd X Y).map - (N.ιLocal (Λ₁ ∪ Λ₂)) - -/-! ### Faithful nets and the quasi-local C⋆-algebra +/-! ### Faithful nets -A net is *faithful* when its isotony embeddings are injective (the standard AQFT non-degeneracy -condition). For a faithful net the connecting maps are isometric, so the algebra of local -observables carries a C⋆-norm whose completion is the quasi-local C⋆-algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` -(Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2). -/ +A net is *faithful* when its isotony embeddings are injective (the standard AQFT +non-degeneracy condition). The quasi-local C⋆-norm built from this hypothesis lives in +`LocalNet.QuasiLocal`. +-/ /-- A local net is **faithful** when all its isotony embeddings are injective. In the standard AQFT definition the isotony embeddings are *injective* unital `*`-homomorphisms (Naaijkens 2012 - §3.4), so a faithful local net — `LocalNet` together with `Faithful` — is the literature's net; - this is the non-degeneracy condition that makes the inclusions genuine and the C⋆-norm on the - algebra of local observables well defined. Carried as a typeclass (rather than a structure - field) so the purely algebraic constructions stay free of any non-degeneracy hypothesis. -/ + §3.4), so a faithful local net — `LocalNet` together with `Faithful` — is the literature's net. + Carried as a typeclass rather than a structure field so algebraic constructions can state the + non-degeneracy hypothesis only where they need it. -/ class Faithful {sites : Type*} [DecidableEq sites] (N : LocalNet sites) : Prop where /-- Every isotony embedding of the net is injective. -/ incl_injective : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ'), Function.Injective (N.incl h) -section CStar - -variable [N.Faithful] - -/-- The algebra of local observables is a normed ring under the C⋆-norm of the inductive limit - (the inclusions are injective, hence isometric). -/ -noncomputable instance : NormedRing N.quasiLocalAlgebra := - DirectLimit.cstarNormedRing (fun _ _ h => Faithful.incl_injective h) - -@[simp] theorem norm_mk {Λ : Finset sites} (X : N.algebra Λ) : - ‖(⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl - -/-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ -noncomputable instance : NormedAlgebra ℂ N.quasiLocalAlgebra where - norm_smul_le c x := by - induction x using DirectLimit.induction with - | _ Λ X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X - -/-- `star` is isometric on the algebra of local observables. -/ -instance : NormedStarGroup N.quasiLocalAlgebra where - norm_star_le x := by - induction x using DirectLimit.induction with - | _ Λ X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le - -/-- The C⋆-identity holds on the algebra of local observables. -/ -instance : CStarRing N.quasiLocalAlgebra where - norm_mul_self_le x := by - induction x using DirectLimit.induction with - | _ Λ X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] - exact CStarRing.norm_mul_self_le X - -/-- The **quasi-local C⋆-algebra** of a faithful net: the completion of the algebra of local - observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, - Bratteli–Robinson Vol.2 §6.2). -/ -noncomputable abbrev quasiLocalCStarAlgebra : Type _ := - UniformSpace.Completion N.quasiLocalAlgebra - -noncomputable example : CStarAlgebra N.quasiLocalCStarAlgebra := inferInstance - -/-- The canonical embedding `𝔄(Λ) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, - as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ -noncomputable def ιLocalCStar (Λ : Finset sites) : - N.algebra Λ → N.quasiLocalCStarAlgebra := - (↑) ∘ N.ιLocal Λ - -/-- The local algebras are dense in the quasi-local C⋆-algebra: every element is a norm-limit of - local observables. -/ -theorem denseRange_iUnion_ιLocalCStar : - Dense (⋃ Λ : Finset sites, Set.range (N.ιLocalCStar Λ)) := by - refine UniformSpace.Completion.denseRange_coe.mono ?_ - rintro _ ⟨z, rfl⟩ - obtain ⟨Λ, X, rfl⟩ := N.exists_ιLocal z - exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ - -end CStar - -/-! ### Covariance: symmetries of the net - -A **symmetry** of a local net is a site permutation `σ` together with, for each finite region, a -`*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the -isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)` at the abstract net -level (Naaijkens 2012 §3.2, Verch 2025 §1.2). Being purely algebraic, the induced action on the -algebra of local observables needs no faithfulness hypothesis. -/ +/-! ### Region-equality transport -/ /-- Transport a local algebra along an equality of regions, as a `*`-isomorphism. Used to identify - `𝔄(σ₁σ₂Λ)` along the functoriality of the region map when composing symmetries. -/ + local algebras whose regions are propositionally equal. -/ def algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') : N.algebra Λ ≃⋆ₐ[ℂ] N.algebra Λ' := by subst h; exact StarAlgEquiv.refl @[simp] theorem algebraCongr_apply {Λ : Finset sites} (x : N.algebra Λ) : N.algebraCongr (rfl : Λ = Λ) x = x := rfl -/-- The cocone of the inductive limit absorbs the region-equality transport. -/ -@[simp] theorem ιLocal_algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) : - N.ιLocal Λ' (N.algebraCongr h x) = N.ιLocal Λ x := by - subst h; rfl - /-- The isotony embeddings are natural with respect to the region-equality transport. -/ theorem incl_algebraCongr {Λ₁ Λ₂ Λ₁' Λ₂' : Finset sites} (e₁ : Λ₁ = Λ₁') (e₂ : Λ₂ = Λ₂') (h : Λ₁ ⊆ Λ₂) (h' : Λ₁' ⊆ Λ₂') (x : N.algebra Λ₁) : @@ -254,366 +103,4 @@ theorem algebraCongr_eq_iff {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebr (y : N.algebra Λ') : N.algebraCongr h x = y ↔ x = N.algebraCongr h.symm y := by subst h; simp -/-- A **symmetry** of a local net `N`: a site permutation `σ` together with, for every finite - region `Λ`, a `*`-isomorphism `β Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)`, natural with respect to the isotony - embeddings (`β_incl`). This is the AQFT covariance datum at the abstract net level — one element - of a covariant group action (Naaijkens 2012 §3.2, Verch 2025 §1.2). -/ -structure Symmetry where - /-- The underlying site permutation; its image map `Λ ↦ σΛ` carries the region map. -/ - σ : sites ≃ sites - /-- The covariance `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` on each region. -/ - β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding) - /-- **Naturality / covariance**: `β` intertwines the isotony embeddings, so it maps the net to - itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)`. -/ - β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), - β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x) - -namespace Symmetry - -variable {N} (a : N.Symmetry) - -/-- The image `σΛ` of a region under the symmetry. -/ -def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding - -/-- **Extensionality** for symmetries: two symmetries with the same site permutation and the same - local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality - field `β_incl` is a proposition, hence irrelevant. -/ -@[ext (iff := false)] theorem ext {s t : N.Symmetry} (hσ : s.σ = t.σ) - (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), - N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by - revert hσ hβ - obtain ⟨sσ, sβ, -⟩ := s - obtain ⟨tσ, tβ, -⟩ := t - rintro rfl hβ - have hβ' : sβ = tβ := by - funext Λ - ext x - simpa using hβ Λ x rfl - subst hβ' - rfl - -/-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ -theorem β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : - (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by - have key := a.β_incl h ((a.β Λ).symm y) - rw [StarAlgEquiv.apply_symm_apply] at key - rw [← key, StarAlgEquiv.symm_apply_apply] - -/-- The local `*`-isomorphisms commute with the region-equality transport. -/ -theorem β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : - a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by - subst e; simp - -/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a symmetry on the algebra of local - observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ -noncomputable def quasiLocalRelabel : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := - DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra - (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) - (fun Λ Λ' h X => by - change N.ιLocal (a.region Λ') (a.β Λ' (N.incl h X)) = N.ιLocal (a.region Λ) (a.β Λ X) - rw [a.β_incl h] - exact N.ιLocal_incl _ _) - -@[simp] theorem quasiLocalRelabel_mk {Λ : Finset sites} (X : N.algebra Λ) : - a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := - rfl - -variable (N) in -/-- The **identity symmetry**: the identity site permutation with the identity local - `*`-isomorphisms (transported along `Λ = σ_id Λ`). -/ -def id : N.Symmetry where - σ := Equiv.refl sites - β Λ := N.algebraCongr (by simp) - β_incl h x := N.incl_algebraCongr _ _ h _ x - -/-- **Composition of symmetries**: apply `b`, then `a`. The site permutations compose; the local - `*`-isomorphisms compose and are transported along the region-map functoriality - `(σ_a ∘ σ_b) Λ = σ_a (σ_b Λ)`. -/ -def comp (a b : N.Symmetry) : N.Symmetry where - σ := b.σ.trans a.σ - β Λ := ((b.β Λ).trans (a.β (Λ.map b.σ.toEmbedding))).trans - (N.algebraCongr (by simp [Finset.map_map, Equiv.trans_toEmbedding])) - β_incl h x := by - simp only [StarAlgEquiv.trans_apply] - rw [b.β_incl h, a.β_incl (Finset.map_subset_map.mpr h)] - exact N.incl_algebraCongr _ _ _ _ _ - -/-- The **inverse symmetry**: the inverse site permutation with the inverse local - `*`-isomorphisms, transported along the region-map functoriality `σ⁻¹σ Λ = Λ`. -/ -def inv (a : N.Symmetry) : N.Symmetry where - σ := a.σ.symm - β Λ := (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by - simp [Finset.map_map]).symm).trans - (a.β (Λ.map a.σ.symm.toEmbedding)).symm - β_incl h x := by - simp only [StarAlgEquiv.trans_apply] - rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), - a.β_symm_incl] - -@[simp] theorem id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : - (Symmetry.id N).β Λ x = - N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := - rfl - -@[simp] theorem comp_β_apply (a b : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : - (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding - = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) - (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := - rfl - -@[simp] theorem inv_β_apply (a : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : - (Symmetry.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm - (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by - simp [Finset.map_map]).symm x) := - rfl - -@[simp] theorem region_id (Λ : Finset sites) : (Symmetry.id N).region Λ = Λ := by - simp [region, Symmetry.id] - -@[simp] theorem region_comp (a b : N.Symmetry) (Λ : Finset sites) : - (a.comp b).region Λ = a.region (b.region Λ) := by - simp [region, Symmetry.comp, Finset.map_map, Equiv.trans_toEmbedding] - -/-- The covariance action of the identity symmetry is the identity: `β_{id} = id`. -/ -@[simp] theorem quasiLocalRelabel_id : - (Symmetry.id N).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by - refine RingHom.ext fun z => ?_ - induction z using DirectLimit.induction with - | _ Λ X => rw [quasiLocalRelabel_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X - -/-- **Functoriality of the covariance action**: composing symmetries composes their actions, - `β_{a∘b} = β_a ∘ β_b`. With `quasiLocalRelabel_id` this exhibits `a ↦ β_a` as a functorial - (monoid-homomorphic) assignment, so a group acting on the net acts on the algebra of local - observables by `*`-endomorphisms. -/ -@[simp] theorem quasiLocalRelabel_comp (a b : N.Symmetry) : - (a.comp b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by - refine RingHom.ext fun z => ?_ - induction z using DirectLimit.induction with - | _ Λ X => - simp only [RingHom.comp_apply, quasiLocalRelabel_mk] - exact N.ιLocal_algebraCongr _ _ - -theorem id_comp (a : N.Symmetry) : (Symmetry.id N).comp a = a := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Symmetry.id] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, id_β_apply] - erw [algebraCongr_trans] - rfl - -theorem comp_id (a : N.Symmetry) : a.comp (Symmetry.id N) = a := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Symmetry.id] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, id_β_apply] - erw [a.β_algebraCongr, algebraCongr_trans] - rfl - -theorem comp_assoc (a b c : N.Symmetry) : (a.comp b).comp c = a.comp (b.comp c) := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Equiv.trans_assoc] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply] - erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] - rfl - -theorem inv_comp (a : N.Symmetry) : (Symmetry.inv a).comp a = Symmetry.id N := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Symmetry.inv, Symmetry.id, Equiv.self_trans_symm] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, inv_β_apply, id_β_apply] - erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply, algebraCongr_trans, - algebraCongr_trans] - · rfl - · simp [Finset.map_map] - -/-- The symmetries of a local net form a **group** under composition, with `Symmetry.id` the unit - and `Symmetry.inv` the inverse. A covariant action of a group `G` on the net is then a - homomorphism `G →* N.Symmetry`. -/ -noncomputable instance : Group N.Symmetry where - mul a b := a.comp b - one := Symmetry.id N - inv a := a.inv - mul_assoc := Symmetry.comp_assoc - one_mul := Symmetry.id_comp - mul_one := Symmetry.comp_id - inv_mul_cancel := Symmetry.inv_comp - -/-- The group multiplication is composition of symmetries. -/ -theorem mul_def (a b : N.Symmetry) : a * b = a.comp b := rfl - -/-- The group unit is the identity symmetry. -/ -theorem one_def : (1 : N.Symmetry) = Symmetry.id N := rfl - -/-- The group inverse is the inverse symmetry. -/ -theorem inv_def (a : N.Symmetry) : a⁻¹ = a.inv := rfl - -/-- The covariance action sends the unit symmetry to the identity: `β_1 = id`. -/ -@[simp] theorem quasiLocalRelabel_one : - (1 : N.Symmetry).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by - rw [one_def, quasiLocalRelabel_id] - -/-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. With `quasiLocalRelabel_one` - this exhibits `a ↦ β_a` as a monoid homomorphism from the symmetry group into the - `*`-endomorphisms of the algebra of local observables. -/ -theorem quasiLocalRelabel_mul (a b : N.Symmetry) : - (a * b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by - rw [mul_def, quasiLocalRelabel_comp] - -/-! #### The covariance action as a `*`-automorphism - -The ring endomorphism `quasiLocalRelabel` is in fact `ℂ`-linear and `*`-preserving, since each -covariance isomorphism `β` is a `*`-isomorphism. Recording this upgrades the action to a genuine -`*`-algebra automorphism `≃⋆ₐ[ℂ]` and the assignment to a group homomorphism into the -`*`-automorphism group — the AQFT covariance action on the algebra of local observables. -/ - -/-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ -theorem quasiLocalRelabel_smul (c : ℂ) (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabel (c • z) = c • a.quasiLocalRelabel z := by - induction z using DirectLimit.induction with - | _ Λ X => - rw [DirectLimit.smul_def, quasiLocalRelabel_mk, quasiLocalRelabel_mk, DirectLimit.smul_def, - map_smul] - rfl - -/-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` - is a `*`-isomorphism. -/ -theorem quasiLocalRelabel_star (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabel (star z) = star (a.quasiLocalRelabel z) := by - induction z using DirectLimit.induction with - | _ Λ X => - rw [star_mk, quasiLocalRelabel_mk, quasiLocalRelabel_mk, star_mk, map_star] - rfl - -/-- The **covariance action** of a symmetry as a `*`-algebra automorphism `𝔄_loc ≃⋆ₐ[ℂ] 𝔄_loc` of - the algebra of local observables, with the action of the inverse symmetry `a⁻¹` as its inverse. - This is the AQFT covariance automorphism at the level of the (incomplete) algebra of local - observables; its continuous extension to the quasi-local C⋆-algebra is `quasiLocalCStarRelabel` - (for a faithful net). -/ -noncomputable def quasiLocalRelabelStarEquiv : - N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where - toFun := a.quasiLocalRelabel - invFun := a⁻¹.quasiLocalRelabel - left_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, inv_mul_cancel, quasiLocalRelabel_one, - RingHom.id_apply] - right_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, mul_inv_cancel, quasiLocalRelabel_one, - RingHom.id_apply] - map_mul' := map_mul a.quasiLocalRelabel - map_add' := map_add a.quasiLocalRelabel - map_smul' := a.quasiLocalRelabel_smul - map_star' := a.quasiLocalRelabel_star - -@[simp] theorem quasiLocalRelabelStarEquiv_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabelStarEquiv z = a.quasiLocalRelabel z := rfl - -@[simp] theorem quasiLocalRelabelStarEquiv_symm_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabelStarEquiv.symm z = a⁻¹.quasiLocalRelabel z := rfl - -/-- A symmetry of the net acts on the algebra of local observables by `*`-algebra automorphisms, - assembled as a **group homomorphism** into the `*`-automorphism group `𝔄_loc ≃⋆ₐ[ℂ] 𝔄_loc`. - This is the covariance action of the symmetry group, upgrading the monoid-homomorphic - endomorphism action (`quasiLocalRelabel_one`/`quasiLocalRelabel_mul`) to a group action by - automorphisms that tracks the `ℂ`-linear and `*`-structure. -/ -noncomputable def quasiLocalRelabelStarHom : - N.Symmetry →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where - toFun a := a.quasiLocalRelabelStarEquiv - map_one' := by - ext z - simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_one, RingHom.id_apply, - StarAlgEquiv.one_apply] - map_mul' a b := by - ext z - simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_mul, RingHom.comp_apply, - StarAlgEquiv.mul_apply] - -@[simp] theorem quasiLocalRelabelStarHom_apply (z : N.quasiLocalAlgebra) : - quasiLocalRelabelStarHom a z = a.quasiLocalRelabel z := rfl - -/-! #### The covariance automorphism of the quasi-local C⋆-algebra - -For a **faithful** net the covariance action is *isometric* — each `β` is a `*`-isomorphism of -C⋆-algebras, hence norm-preserving (`StarAlgEquiv.norm_map`) — so `quasiLocalRelabelStarEquiv` is -uniformly continuous and extends, by the functoriality of completion (`mapStarAlgEquiv`), to a -`*`-automorphism of the quasi-local C⋆-algebra `𝔄`. This is the genuine AQFT covariance -automorphism on `𝔄`, and the assignment is a group homomorphism. -/ - -section CStarCovariance - -variable [N.Faithful] - -/-- The covariance action is **isometric** on the algebra of local observables: each `β` is a - `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ -theorem quasiLocalRelabel_norm (z : N.quasiLocalAlgebra) : - ‖a.quasiLocalRelabel z‖ = ‖z‖ := by - induction z using DirectLimit.induction with - | _ Λ X => - rw [quasiLocalRelabel_mk, norm_mk, norm_mk] - exact StarAlgEquiv.norm_map _ X - -/-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is - an isometry), so it extends to the C⋆-completion. -/ -theorem quasiLocalRelabelStarEquiv_uniformContinuous : - UniformContinuous a.quasiLocalRelabelStarEquiv := - (AddMonoidHomClass.isometry_of_norm _ (fun z => by - rw [quasiLocalRelabelStarEquiv_apply]; exact a.quasiLocalRelabel_norm z)).uniformContinuous - -/-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is - also an isometry). -/ -theorem quasiLocalRelabelStarEquiv_symm_uniformContinuous : - UniformContinuous a.quasiLocalRelabelStarEquiv.symm := by - have h : ∀ z, ‖a.quasiLocalRelabelStarEquiv.symm z‖ = ‖z‖ := fun z => by - rw [quasiLocalRelabelStarEquiv_symm_apply]; exact a⁻¹.quasiLocalRelabel_norm z - exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous - -/-- The **covariance automorphism of the quasi-local C⋆-algebra** `𝔄 ≃⋆ₐ[ℂ] 𝔄`: the continuous - extension of `quasiLocalRelabelStarEquiv` to the completion. This is the AQFT covariant - `*`-automorphism on the quasi-local C⋆-algebra of a faithful net (Naaijkens 2012 §3.2, - Bratteli–Robinson Vol.2 §6.2). -/ -noncomputable def quasiLocalCStarRelabel : - N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := - UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalRelabelStarEquiv - a.quasiLocalRelabelStarEquiv_uniformContinuous - a.quasiLocalRelabelStarEquiv_symm_uniformContinuous - -@[simp] theorem quasiLocalCStarRelabel_coe (z : N.quasiLocalAlgebra) : - a.quasiLocalCStarRelabel (↑z : N.quasiLocalCStarAlgebra) = ↑(a.quasiLocalRelabel z) := - UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z - -theorem quasiLocalCStarRelabel_continuous : - Continuous (⇑a.quasiLocalCStarRelabel) := - UniformSpace.Completion.continuous_map - -/-- A symmetry of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, - assembled as a **group homomorphism** into the `*`-automorphism group `𝔄 ≃⋆ₐ[ℂ] 𝔄`. This is the - covariance action of the symmetry group on the quasi-local C⋆-algebra — the AQFT covariant - automorphic action. -/ -noncomputable def quasiLocalCStarRelabelHom : - N.Symmetry →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where - toFun a := a.quasiLocalCStarRelabel - map_one' := by - refine StarAlgEquiv.ext fun z => ?_ - rw [StarAlgEquiv.one_apply] - refine UniformSpace.Completion.induction_on z - (isClosed_eq (1 : N.Symmetry).quasiLocalCStarRelabel_continuous continuous_id) ?_ - intro w - simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_one, RingHom.id_apply] - map_mul' a b := by - refine StarAlgEquiv.ext fun z => ?_ - rw [StarAlgEquiv.mul_apply] - refine UniformSpace.Completion.induction_on z - (isClosed_eq (a * b).quasiLocalCStarRelabel_continuous - (a.quasiLocalCStarRelabel_continuous.comp b.quasiLocalCStarRelabel_continuous)) ?_ - intro w - simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_mul, RingHom.comp_apply] - -@[simp] theorem quasiLocalCStarRelabelHom_apply - (z : N.quasiLocalCStarAlgebra) : - quasiLocalCStarRelabelHom a z = a.quasiLocalCStarRelabel z := rfl - -end CStarCovariance - -end Symmetry - end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean index 4e42808..434fb7a 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean @@ -29,6 +29,135 @@ below are thin wrappers around the corresponding `LocalNet` constructions on `to @[expose] public section +namespace LocalNet + +variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) + +/-! ### Abstract quasi-local algebra + +These constructions apply to any abstract local net. The concrete `SiteIndexSystem` wrappers are +provided later in this file after `SiteIndexSystem.toLocalNet` is built. +-/ + +/-- The **algebra of local observables** of the net: the algebraic inductive limit of the local + algebras along the isotony embeddings. Its C⋆-completion is the quasi-local algebra. -/ +noncomputable abbrev quasiLocalAlgebra : Type _ := + DirectLimit N.algebra (fun _ _ h => N.incl h) + +/-- Componentwise behaviour of the involution on the algebra of local observables. The + `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general + direct-limit constructions, since each `algebra Λ` is a `ℂ`-`*`-algebra and `incl` is a + `*`-algebra homomorphism. -/ +@[simp] theorem star_mk {Λ : Finset sites} (X : N.algebra Λ) : + star (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl + +/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local + observables, as a unital ring homomorphism (the cocone of the inductive limit). -/ +noncomputable def ιLocal (Λ : Finset sites) : + N.algebra Λ →+* N.quasiLocalAlgebra := + DirectLimit.Ring.of N.algebra (fun _ _ h => N.incl h) Λ + +/-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the + larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ +@[simp] theorem ιLocal_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (X : N.algebra Λ) : + N.ιLocal Λ' (N.incl h X) = N.ιLocal Λ X := + DirectLimit.Ring.of_f (G := N.algebra) (f := fun _ _ h => N.incl h) h X + +/-- The cocone is a `*`-homomorphism: it intertwines the local and quasi-local involutions. -/ +@[simp] theorem ιLocal_star {Λ : Finset sites} (X : N.algebra Λ) : + N.ιLocal Λ (star X) = star (N.ιLocal Λ X) := + (star_mk (N := N) X).symm + +/-- The cocone of the inductive limit absorbs the region-equality transport. -/ +@[simp] theorem ιLocal_algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) : + N.ιLocal Λ' (N.algebraCongr h x) = N.ιLocal Λ x := by + subst h; rfl + +/-- **Exhaustion**: every element of the algebra of local observables is the image of a local + observable from some finite region — the union of the local algebras is the whole limit. -/ +theorem exists_ιLocal (z : N.quasiLocalAlgebra) : + ∃ (Λ : Finset sites) (X : N.algebra Λ), z = N.ιLocal Λ X := by + induction z using DirectLimit.induction with + | _ Λ X => exact ⟨Λ, X, rfl⟩ + +/-- **Locality in the algebra of local observables**: observables localised in disjoint regions + commute inside `𝔄_loc`. Lifts the net's `locality` along the ring-hom cocone. -/ +theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset sites} (hd : Disjoint Λ₁ Λ₂) + (X : N.algebra Λ₁) (Y : N.algebra Λ₂) : + Commute (N.ιLocal Λ₁ X) (N.ιLocal Λ₂ Y) := by + have h1 : N.ιLocal Λ₁ X + = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_left X) := + (N.ιLocal_incl Finset.subset_union_left X).symm + have h2 : N.ιLocal Λ₂ Y + = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_right Y) := + (N.ιLocal_incl Finset.subset_union_right Y).symm + rw [h1, h2] + exact (N.locality Finset.subset_union_left Finset.subset_union_right hd X Y).map + (N.ιLocal (Λ₁ ∪ Λ₂)) + +/-! ### Faithful nets and the quasi-local C⋆-algebra + +For a faithful net the connecting maps are isometric, so the algebra of local observables carries +a C⋆-norm whose completion is the quasi-local C⋆-algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)`. +-/ + +section CStar + +variable [N.Faithful] + +/-- The algebra of local observables is a normed ring under the C⋆-norm of the inductive limit + (the inclusions are injective, hence isometric). -/ +noncomputable instance : NormedRing N.quasiLocalAlgebra := + DirectLimit.cstarNormedRing (fun _ _ h => Faithful.incl_injective h) + +@[simp] theorem norm_mk {Λ : Finset sites} (X : N.algebra Λ) : + ‖(⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl + +/-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ +noncomputable instance : NormedAlgebra ℂ N.quasiLocalAlgebra where + norm_smul_le c x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X + +/-- `star` is isometric on the algebra of local observables. -/ +instance : NormedStarGroup N.quasiLocalAlgebra where + norm_star_le x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le + +/-- The C⋆-identity holds on the algebra of local observables. -/ +instance : CStarRing N.quasiLocalAlgebra where + norm_mul_self_le x := by + induction x using DirectLimit.induction with + | _ Λ X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] + exact CStarRing.norm_mul_self_le X + +/-- The **quasi-local C⋆-algebra** of a faithful net: the completion of the algebra of local + observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)`. -/ +noncomputable abbrev quasiLocalCStarAlgebra : Type _ := + UniformSpace.Completion N.quasiLocalAlgebra + +noncomputable example : CStarAlgebra N.quasiLocalCStarAlgebra := inferInstance + +/-- The canonical embedding `𝔄(Λ) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, + as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ +noncomputable def ιLocalCStar (Λ : Finset sites) : + N.algebra Λ → N.quasiLocalCStarAlgebra := + (↑) ∘ N.ιLocal Λ + +/-- The local algebras are dense in the quasi-local C⋆-algebra: every element is a norm-limit of + local observables. -/ +theorem denseRange_iUnion_ιLocalCStar : + Dense (⋃ Λ : Finset sites, Set.range (N.ιLocalCStar Λ)) := by + refine UniformSpace.Completion.denseRange_coe.mono ?_ + rintro _ ⟨z, rfl⟩ + obtain ⟨Λ, X, rfl⟩ := N.exists_ιLocal z + exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ + +end CStar + +end LocalNet + namespace SiteIndexSystem open scoped Matrix.Norms.L2Operator diff --git a/QuantumSystem/Algebra/LocalNet/Symmetry.lean b/QuantumSystem/Algebra/LocalNet/Symmetry.lean new file mode 100644 index 0000000..46e0854 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/Symmetry.lean @@ -0,0 +1,194 @@ +module + +public import QuantumSystem.Algebra.LocalNet.Net + +/-! +# Symmetries of a local net + +A **symmetry** of a local net is a site permutation `σ` together with, for every finite region +`Λ`, a `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect +to the isotony embeddings. This realises the AQFT covariance datum `β(𝔄(Λ)) = 𝔄(σΛ)` at the +abstract net level (Naaijkens 2012 §3.2, Verch 2025 §1.2). + +Symmetries compose: the identity and composition below, together with the inverse, make the +symmetries of a net a `Group`. This file carries only the symmetry *group* — purely algebraic data +depending on the net axioms. The induced **covariance action** of a symmetry on the algebra of +local observables (and its C⋆-completion) lives in `LocalNet.Covariance`. +-/ + +@[expose] public section + +namespace LocalNet + +variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) + +/-! ### Symmetries of the net + +A **symmetry** of a local net is a site permutation `σ` together with, for each finite region, a +`*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the +isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)` at the abstract net +level. Being purely algebraic, the symmetry group needs no faithfulness hypothesis. +-/ + +/-- A **symmetry** of a local net `N`: a site permutation `σ` together with, for every finite + region `Λ`, a `*`-isomorphism `β Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)`, natural with respect to the isotony + embeddings (`β_incl`). This is the AQFT covariance datum at the abstract net level. -/ +structure Symmetry where + /-- The underlying site permutation; its image map `Λ ↦ σΛ` carries the region map. -/ + σ : sites ≃ sites + /-- The covariance `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` on each region. -/ + β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding) + /-- **Naturality / covariance**: `β` intertwines the isotony embeddings, so it maps the net to + itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)`. -/ + β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), + β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x) + +namespace Symmetry + +variable {N} (a : N.Symmetry) + +/-- The image `σΛ` of a region under the symmetry. -/ +def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding + +/-- **Extensionality** for symmetries: two symmetries with the same site permutation and the same + local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality + field `β_incl` is a proposition, hence irrelevant. -/ +@[ext (iff := false)] theorem ext {s t : N.Symmetry} (hσ : s.σ = t.σ) + (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), + N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by + revert hσ hβ + obtain ⟨sσ, sβ, -⟩ := s + obtain ⟨tσ, tβ, -⟩ := t + rintro rfl hβ + have hβ' : sβ = tβ := by + funext Λ + ext x + simpa using hβ Λ x rfl + subst hβ' + rfl + +/-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ +theorem β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : + (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by + have key := a.β_incl h ((a.β Λ).symm y) + rw [StarAlgEquiv.apply_symm_apply] at key + rw [← key, StarAlgEquiv.symm_apply_apply] + +/-- The local `*`-isomorphisms commute with the region-equality transport. -/ +theorem β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : + a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by + subst e; simp + +variable (N) in +/-- The **identity symmetry**: the identity site permutation with the identity local + `*`-isomorphisms (transported along `Λ = σ_id Λ`). -/ +def id : N.Symmetry where + σ := Equiv.refl sites + β Λ := N.algebraCongr (by simp) + β_incl h x := N.incl_algebraCongr _ _ h _ x + +/-- **Composition of symmetries**: apply `b`, then `a`. The site permutations compose; the local + `*`-isomorphisms compose and are transported along the region-map functoriality + `(σ_a ∘ σ_b) Λ = σ_a (σ_b Λ)`. -/ +def comp (a b : N.Symmetry) : N.Symmetry where + σ := b.σ.trans a.σ + β Λ := ((b.β Λ).trans (a.β (Λ.map b.σ.toEmbedding))).trans + (N.algebraCongr (by simp [Finset.map_map, Equiv.trans_toEmbedding])) + β_incl h x := by + simp only [StarAlgEquiv.trans_apply] + rw [b.β_incl h, a.β_incl (Finset.map_subset_map.mpr h)] + exact N.incl_algebraCongr _ _ _ _ _ + +/-- The **inverse symmetry**: the inverse site permutation with the inverse local + `*`-isomorphisms, transported along the region-map functoriality `σ⁻¹σ Λ = Λ`. -/ +def inv (a : N.Symmetry) : N.Symmetry where + σ := a.σ.symm + β Λ := (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by + simp [Finset.map_map]).symm).trans + (a.β (Λ.map a.σ.symm.toEmbedding)).symm + β_incl h x := by + simp only [StarAlgEquiv.trans_apply] + rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), + a.β_symm_incl] + +@[simp] theorem id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : + (Symmetry.id N).β Λ x = + N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := + rfl + +@[simp] theorem comp_β_apply (a b : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : + (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding + = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) + (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := + rfl + +@[simp] theorem inv_β_apply (a : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : + (Symmetry.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm + (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by + simp [Finset.map_map]).symm x) := + rfl + +@[simp] theorem region_id (Λ : Finset sites) : (Symmetry.id N).region Λ = Λ := by + simp [region, Symmetry.id] + +@[simp] theorem region_comp (a b : N.Symmetry) (Λ : Finset sites) : + (a.comp b).region Λ = a.region (b.region Λ) := by + simp [region, Symmetry.comp, Finset.map_map, Equiv.trans_toEmbedding] + +theorem id_comp (a : N.Symmetry) : (Symmetry.id N).comp a = a := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Symmetry.id] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, id_β_apply] + erw [algebraCongr_trans] + rfl + +theorem comp_id (a : N.Symmetry) : a.comp (Symmetry.id N) = a := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Symmetry.id] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, id_β_apply] + erw [a.β_algebraCongr, algebraCongr_trans] + rfl + +theorem comp_assoc (a b c : N.Symmetry) : (a.comp b).comp c = a.comp (b.comp c) := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Equiv.trans_assoc] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply] + erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] + rfl + +theorem inv_comp (a : N.Symmetry) : (Symmetry.inv a).comp a = Symmetry.id N := by + refine Symmetry.ext ?_ fun Λ x e => ?_ + · simp [Symmetry.comp, Symmetry.inv, Symmetry.id, Equiv.self_trans_symm] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, inv_β_apply, id_β_apply] + erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply, algebraCongr_trans, + algebraCongr_trans] + · rfl + · simp [Finset.map_map] + +/-- The symmetries of a local net form a **group** under composition, with `Symmetry.id` the unit + and `Symmetry.inv` the inverse. -/ +noncomputable instance : Group N.Symmetry where + mul a b := a.comp b + one := Symmetry.id N + inv a := a.inv + mul_assoc := Symmetry.comp_assoc + one_mul := Symmetry.id_comp + mul_one := Symmetry.comp_id + inv_mul_cancel := Symmetry.inv_comp + +/-- The group multiplication is composition of symmetries. -/ +theorem mul_def (a b : N.Symmetry) : a * b = a.comp b := rfl + +/-- The group unit is the identity symmetry. -/ +theorem one_def : (1 : N.Symmetry) = Symmetry.id N := rfl + +/-- The group inverse is the inverse symmetry. -/ +theorem inv_def (a : N.Symmetry) : a⁻¹ = a.inv := rfl + +end Symmetry + +end LocalNet From 1435ab8947977bd17dc3fe68edd34e773616e405 Mon Sep 17 00:00:00 2001 From: suzuki Date: Fri, 26 Jun 2026 01:42:43 +0000 Subject: [PATCH 023/113] refactor(localnet): unify net symmetry into covariance module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge LocalNet/Symmetry.lean into Covariance.lean and rename the abstract `Symmetry` structure and group to `Covariance`, aligning the terminology with the AQFT covariance axiom β(𝔄(Λ)) = 𝔄(σΛ). Rename the derived declarations accordingly (quasiLocalRelabel → quasiLocalCovariance, relabelAlgebra → localCovariance, relabelRegionIdx → regionIdxEquiv, toLocalNetSymmetry → toLocalNetCovariance, quasiLocalCStarRelabel → quasiLocalCStarCovarianceEquiv), drop the obsolete Symmetry import from the aggregate root, and refresh the module docs. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 1 - QuantumSystem/Algebra/LocalNet/Basic.lean | 2 +- .../Algebra/LocalNet/Covariance.lean | 472 ++++++++++++------ QuantumSystem/Algebra/LocalNet/Symmetry.lean | 194 ------- 4 files changed, 323 insertions(+), 346 deletions(-) delete mode 100644 QuantumSystem/Algebra/LocalNet/Symmetry.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index e3f5b10..11c2530 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -23,7 +23,6 @@ public import QuantumSystem.Algebra.LocalNet.Isotony public import QuantumSystem.Algebra.LocalNet.Locality public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocal -public import QuantumSystem.Algebra.LocalNet.Symmetry public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra diff --git a/QuantumSystem/Algebra/LocalNet/Basic.lean b/QuantumSystem/Algebra/LocalNet/Basic.lean index c0d98d5..ea475f1 100644 --- a/QuantumSystem/Algebra/LocalNet/Basic.lean +++ b/QuantumSystem/Algebra/LocalNet/Basic.lean @@ -24,7 +24,7 @@ region factorisation equivalences (`regionIdxPairEquiv`, `regionIdxTripleEquiv`) The net **properties** built on this data live in sibling modules: `LocalNet.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `LocalNet.Locality` (disjoint regions commute), `LocalNet.QuasiLocal` (quasi-local C⋆-algebra), `LocalNet.Covariance` -(symmetry action). Restriction / partial trace lives in `Analysis/Matrix/PartialTrace.lean`. +(covariance data and action). Restriction / partial trace lives in `Analysis/Matrix/PartialTrace.lean`. ## References diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index cff54b8..211ed1d 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -1,23 +1,25 @@ module public import QuantumSystem.Algebra.LocalNet.QuasiLocal -public import QuantumSystem.Algebra.LocalNet.Symmetry /-! -# Covariance action of a local net symmetry +# Covariance data and action for a local net -A symmetry of a local net (`LocalNet.Symmetry`, defined in `LocalNet.Symmetry`) acts on the -**algebra of local observables** by `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧`. The per-region -`*`-isomorphisms are natural with respect to isotony (`β_incl`), so they assemble into a -`*`-endomorphism `quasiLocalRelabel` of the quasi-local algebra (the covariance action). This -action is functorial in the symmetry group, `ℂ`-linear and `*`-preserving, hence a -`*`-automorphism; for a `Faithful` net it is isometric and extends to a `*`-automorphism of the -quasi-local C⋆-algebra (Naaijkens 2012 §3.2, Verch 2025 §1.2). +A **covariance** of a local net is a site permutation `σ` together with, for every finite region +`Λ`, a `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect +to the isotony embeddings. The naturality field `β_incl` is the AQFT covariance axiom +`β(𝔄(Λ)) = 𝔄(σΛ)` compatibly with inclusions (Naaijkens 2012 §3.2, Verch 2025 §1.2). -A **symmetry** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each +Such covariance data acts on the **algebra of local observables** by +`β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧`. The per-region `*`-isomorphisms assemble into a +`*`-endomorphism `quasiLocalCovariance` of the quasi-local algebra. This action is functorial in the +covariance group, `ℂ`-linear and `*`-preserving, hence a `*`-automorphism; for a `Faithful` net it +is isometric and extends to a `*`-automorphism of the quasi-local C⋆-algebra. + +A **covariance** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each site, an equivalence `localIdx s ≃ localIdx (σ s)` matching the local dimensions. Such data induces -a `*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` (`relabelAlgebra`), assembling into an abstract -`LocalNet.Symmetry` of the generated net (`toLocalNetSymmetry`) and hence inheriting the covariance +a `*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` (`localCovariance`), assembling into an abstract +`LocalNet.Covariance` of the generated net (`toLocalNetCovariance`) and hence inheriting the action above. -/ @@ -27,13 +29,178 @@ namespace LocalNet variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) -namespace Symmetry +/-! ### Covariances of the net + +A covariance of a local net is a site permutation `σ` together with, for each finite region, a +`*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the +isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)` at the abstract net +level. Being purely algebraic, the covariance group needs no faithfulness hypothesis. +-/ + +/-- A **covariance** of a local net `N`: a site permutation `σ` together with, for every finite + region `Λ`, a `*`-isomorphism `β Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)`, natural with respect to the isotony + embeddings (`β_incl`). This is the AQFT covariance datum at the abstract net level. -/ +structure Covariance where + /-- The underlying site permutation; its image map `Λ ↦ σΛ` carries the region map. -/ + σ : sites ≃ sites + /-- The covariance `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` on each region. -/ + β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding) + /-- **Naturality / covariance**: `β` intertwines the isotony embeddings, so it maps the net to + itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)`. -/ + β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), + β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x) + +namespace Covariance + +variable {N} (a : N.Covariance) + +/-- The image `σΛ` of a region under the covariance. -/ +def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding + +/-- **Extensionality** for covariances: two covariances with the same site permutation and the same + local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality + field `β_incl` is a proposition, hence irrelevant. -/ +@[ext (iff := false)] theorem ext {s t : N.Covariance} (hσ : s.σ = t.σ) + (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), + N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by + revert hσ hβ + obtain ⟨sσ, sβ, -⟩ := s + obtain ⟨tσ, tβ, -⟩ := t + rintro rfl hβ + have hβ' : sβ = tβ := by + funext Λ + ext x + simpa using hβ Λ x rfl + subst hβ' + rfl -variable {N} (a : N.Symmetry) +/-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ +theorem β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : + (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by + have key := a.β_incl h ((a.β Λ).symm y) + rw [StarAlgEquiv.apply_symm_apply] at key + rw [← key, StarAlgEquiv.symm_apply_apply] + +/-- The local `*`-isomorphisms commute with the region-equality transport. -/ +theorem β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : + a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by + subst e; simp + +variable (N) in +/-- The **identity covariance**: the identity site permutation with the identity local + `*`-isomorphisms (transported along `Λ = σ_id Λ`). -/ +def id : N.Covariance where + σ := Equiv.refl sites + β Λ := N.algebraCongr (by simp) + β_incl h x := N.incl_algebraCongr _ _ h _ x + +/-- **Composition of covariances**: apply `b`, then `a`. The site permutations compose; the local + `*`-isomorphisms compose and are transported along the region-map functoriality + `(σ_a ∘ σ_b) Λ = σ_a (σ_b Λ)`. -/ +def comp (a b : N.Covariance) : N.Covariance where + σ := b.σ.trans a.σ + β Λ := ((b.β Λ).trans (a.β (Λ.map b.σ.toEmbedding))).trans + (N.algebraCongr (by simp [Finset.map_map, Equiv.trans_toEmbedding])) + β_incl h x := by + simp only [StarAlgEquiv.trans_apply] + rw [b.β_incl h, a.β_incl (Finset.map_subset_map.mpr h)] + exact N.incl_algebraCongr _ _ _ _ _ + +/-- The **inverse covariance**: the inverse site permutation with the inverse local + `*`-isomorphisms, transported along the region-map functoriality `σ⁻¹σ Λ = Λ`. -/ +def inv (a : N.Covariance) : N.Covariance where + σ := a.σ.symm + β Λ := (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by + simp [Finset.map_map]).symm).trans + (a.β (Λ.map a.σ.symm.toEmbedding)).symm + β_incl h x := by + simp only [StarAlgEquiv.trans_apply] + rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), + a.β_symm_incl] + +@[simp] theorem id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : + (Covariance.id N).β Λ x = + N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := + rfl + +@[simp] theorem comp_β_apply (a b : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : + (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding + = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) + (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := + rfl + +@[simp] theorem inv_β_apply (a : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : + (Covariance.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm + (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by + simp [Finset.map_map]).symm x) := + rfl -/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a symmetry on the algebra of local +@[simp] theorem region_id (Λ : Finset sites) : (Covariance.id N).region Λ = Λ := by + simp [region, Covariance.id] + +@[simp] theorem region_comp (a b : N.Covariance) (Λ : Finset sites) : + (a.comp b).region Λ = a.region (b.region Λ) := by + simp [region, Covariance.comp, Finset.map_map, Equiv.trans_toEmbedding] + +theorem id_comp (a : N.Covariance) : (Covariance.id N).comp a = a := by + refine Covariance.ext ?_ fun Λ x e => ?_ + · simp [Covariance.comp, Covariance.id] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, id_β_apply] + erw [algebraCongr_trans] + rfl + +theorem comp_id (a : N.Covariance) : a.comp (Covariance.id N) = a := by + refine Covariance.ext ?_ fun Λ x e => ?_ + · simp [Covariance.comp, Covariance.id] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, id_β_apply] + erw [a.β_algebraCongr, algebraCongr_trans] + rfl + +theorem comp_assoc (a b c : N.Covariance) : (a.comp b).comp c = a.comp (b.comp c) := by + refine Covariance.ext ?_ fun Λ x e => ?_ + · simp [Covariance.comp, Equiv.trans_assoc] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply] + erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] + rfl + +theorem inv_comp (a : N.Covariance) : (Covariance.inv a).comp a = Covariance.id N := by + refine Covariance.ext ?_ fun Λ x e => ?_ + · simp [Covariance.comp, Covariance.inv, Covariance.id, Equiv.self_trans_symm] + · rw [algebraCongr_eq_iff] + simp only [comp_β_apply, inv_β_apply, id_β_apply] + erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply, algebraCongr_trans, + algebraCongr_trans] + · rfl + · simp [Finset.map_map] + +/-- The covariances of a local net form a **group** under composition, with `Covariance.id` the + unit and `Covariance.inv` the inverse. -/ +noncomputable instance : Group N.Covariance where + mul a b := a.comp b + one := Covariance.id N + inv a := a.inv + mul_assoc := Covariance.comp_assoc + one_mul := Covariance.id_comp + mul_one := Covariance.comp_id + inv_mul_cancel := Covariance.inv_comp + +/-- The group multiplication is composition of covariances. -/ +theorem mul_def (a b : N.Covariance) : a * b = a.comp b := rfl + +/-- The group unit is the identity covariance. -/ +theorem one_def : (1 : N.Covariance) = Covariance.id N := rfl + +/-- The group inverse is the inverse covariance. -/ +theorem inv_def (a : N.Covariance) : a⁻¹ = a.inv := rfl + +/-! ### The induced covariance action -/ + +/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a covariance on the algebra of local observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ -noncomputable def quasiLocalRelabel : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := +noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) (fun Λ Λ' h X => by @@ -41,96 +208,96 @@ noncomputable def quasiLocalRelabel : N.quasiLocalAlgebra →+* N.quasiLocalAlge rw [a.β_incl h] exact N.ιLocal_incl _ _) -@[simp] theorem quasiLocalRelabel_mk {Λ : Finset sites} (X : N.algebra Λ) : - a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := +@[simp] theorem quasiLocalCovariance_mk {Λ : Finset sites} (X : N.algebra Λ) : + a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := rfl -/-- The covariance action of the identity symmetry is the identity: `β_{id} = id`. -/ -@[simp] theorem quasiLocalRelabel_id : - (Symmetry.id N).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by +/-- The covariance action of the identity covariance is the identity: `β_{id} = id`. -/ +@[simp] theorem quasiLocalCovariance_id : + (Covariance.id N).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with - | _ Λ X => rw [quasiLocalRelabel_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X + | _ Λ X => rw [quasiLocalCovariance_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X -/-- **Functoriality of the covariance action**: composing symmetries composes their actions, +/-- **Functoriality of the covariance action**: composing covariances composes their actions, `β_{a∘b} = β_a ∘ β_b`. -/ -@[simp] theorem quasiLocalRelabel_comp (a b : N.Symmetry) : - (a.comp b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by +@[simp] theorem quasiLocalCovariance_comp (a b : N.Covariance) : + (a.comp b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with | _ Λ X => - simp only [RingHom.comp_apply, quasiLocalRelabel_mk] + simp only [RingHom.comp_apply, quasiLocalCovariance_mk] exact N.ιLocal_algebraCongr _ _ -/-- The covariance action sends the unit symmetry to the identity: `β_1 = id`. -/ -@[simp] theorem quasiLocalRelabel_one : - (1 : N.Symmetry).quasiLocalRelabel = RingHom.id N.quasiLocalAlgebra := by - rw [one_def, quasiLocalRelabel_id] +/-- The covariance action sends the unit covariance to the identity: `β_1 = id`. -/ +@[simp] theorem quasiLocalCovariance_one : + (1 : N.Covariance).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by + rw [one_def, quasiLocalCovariance_id] /-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. -/ -theorem quasiLocalRelabel_mul (a b : N.Symmetry) : - (a * b).quasiLocalRelabel = a.quasiLocalRelabel.comp b.quasiLocalRelabel := by - rw [mul_def, quasiLocalRelabel_comp] +theorem quasiLocalCovariance_mul (a b : N.Covariance) : + (a * b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by + rw [mul_def, quasiLocalCovariance_comp] /-! #### The covariance action as a `*`-automorphism -/ /-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ -theorem quasiLocalRelabel_smul (c : ℂ) (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabel (c • z) = c • a.quasiLocalRelabel z := by +theorem quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : + a.quasiLocalCovariance (c • z) = c • a.quasiLocalCovariance z := by induction z using DirectLimit.induction with | _ Λ X => - rw [DirectLimit.smul_def, quasiLocalRelabel_mk, quasiLocalRelabel_mk, DirectLimit.smul_def, + rw [DirectLimit.smul_def, quasiLocalCovariance_mk, quasiLocalCovariance_mk, DirectLimit.smul_def, map_smul] rfl /-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` is a `*`-isomorphism. -/ -theorem quasiLocalRelabel_star (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabel (star z) = star (a.quasiLocalRelabel z) := by +theorem quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : + a.quasiLocalCovariance (star z) = star (a.quasiLocalCovariance z) := by induction z using DirectLimit.induction with | _ Λ X => - rw [star_mk, quasiLocalRelabel_mk, quasiLocalRelabel_mk, star_mk, map_star] + rw [star_mk, quasiLocalCovariance_mk, quasiLocalCovariance_mk, star_mk, map_star] rfl -/-- The covariance action of a symmetry as a `*`-algebra automorphism of the algebra of local - observables, with the action of the inverse symmetry `a⁻¹` as its inverse. -/ -noncomputable def quasiLocalRelabelStarEquiv : +/-- The covariance action as a `*`-algebra automorphism of the algebra of local observables, with + the action of the inverse covariance `a⁻¹` as its inverse. -/ +noncomputable def quasiLocalCovarianceEquiv : N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where - toFun := a.quasiLocalRelabel - invFun := a⁻¹.quasiLocalRelabel + toFun := a.quasiLocalCovariance + invFun := a⁻¹.quasiLocalCovariance left_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, inv_mul_cancel, quasiLocalRelabel_one, + rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, inv_mul_cancel, quasiLocalCovariance_one, RingHom.id_apply] right_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalRelabel_mul, mul_inv_cancel, quasiLocalRelabel_one, + rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, mul_inv_cancel, quasiLocalCovariance_one, RingHom.id_apply] - map_mul' := map_mul a.quasiLocalRelabel - map_add' := map_add a.quasiLocalRelabel - map_smul' := a.quasiLocalRelabel_smul - map_star' := a.quasiLocalRelabel_star + map_mul' := map_mul a.quasiLocalCovariance + map_add' := map_add a.quasiLocalCovariance + map_smul' := a.quasiLocalCovariance_smul + map_star' := a.quasiLocalCovariance_star -@[simp] theorem quasiLocalRelabelStarEquiv_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabelStarEquiv z = a.quasiLocalRelabel z := rfl +@[simp] theorem quasiLocalCovarianceEquiv_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalCovarianceEquiv z = a.quasiLocalCovariance z := rfl -@[simp] theorem quasiLocalRelabelStarEquiv_symm_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalRelabelStarEquiv.symm z = a⁻¹.quasiLocalRelabel z := rfl +@[simp] theorem quasiLocalCovarianceEquiv_symm_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalCovarianceEquiv.symm z = a⁻¹.quasiLocalCovariance z := rfl -/-- A symmetry of the net acts on the algebra of local observables by `*`-algebra automorphisms, +/-- A covariance of the net acts on the algebra of local observables by `*`-algebra automorphisms, assembled as a group homomorphism into the `*`-automorphism group. -/ -noncomputable def quasiLocalRelabelStarHom : - N.Symmetry →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where - toFun a := a.quasiLocalRelabelStarEquiv +noncomputable def quasiLocalCovarianceHom : + N.Covariance →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where + toFun a := a.quasiLocalCovarianceEquiv map_one' := by ext z - simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_one, RingHom.id_apply, + simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_one, RingHom.id_apply, StarAlgEquiv.one_apply] map_mul' a b := by ext z - simp only [quasiLocalRelabelStarEquiv_apply, quasiLocalRelabel_mul, RingHom.comp_apply, + simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_mul, RingHom.comp_apply, StarAlgEquiv.mul_apply] -@[simp] theorem quasiLocalRelabelStarHom_apply (z : N.quasiLocalAlgebra) : - quasiLocalRelabelStarHom a z = a.quasiLocalRelabel z := rfl +@[simp] theorem quasiLocalCovarianceHom_apply (z : N.quasiLocalAlgebra) : + quasiLocalCovarianceHom a z = a.quasiLocalCovariance z := rfl /-! #### The covariance automorphism of the quasi-local C⋆-algebra -/ @@ -140,72 +307,75 @@ variable [N.Faithful] /-- The covariance action is **isometric** on the algebra of local observables: each `β` is a `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ -theorem quasiLocalRelabel_norm (z : N.quasiLocalAlgebra) : - ‖a.quasiLocalRelabel z‖ = ‖z‖ := by +theorem quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : + ‖a.quasiLocalCovariance z‖ = ‖z‖ := by induction z using DirectLimit.induction with | _ Λ X => - rw [quasiLocalRelabel_mk, norm_mk, norm_mk] + rw [quasiLocalCovariance_mk, norm_mk, norm_mk] exact StarAlgEquiv.norm_map _ X /-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is an isometry), so it extends to the C⋆-completion. -/ -theorem quasiLocalRelabelStarEquiv_uniformContinuous : - UniformContinuous a.quasiLocalRelabelStarEquiv := +theorem quasiLocalCovarianceEquiv_uniformContinuous : + UniformContinuous a.quasiLocalCovarianceEquiv := (AddMonoidHomClass.isometry_of_norm _ (fun z => by - rw [quasiLocalRelabelStarEquiv_apply]; exact a.quasiLocalRelabel_norm z)).uniformContinuous + rw [quasiLocalCovarianceEquiv_apply]; exact a.quasiLocalCovariance_norm z)).uniformContinuous /-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is also an isometry). -/ -theorem quasiLocalRelabelStarEquiv_symm_uniformContinuous : - UniformContinuous a.quasiLocalRelabelStarEquiv.symm := by - have h : ∀ z, ‖a.quasiLocalRelabelStarEquiv.symm z‖ = ‖z‖ := fun z => by - rw [quasiLocalRelabelStarEquiv_symm_apply]; exact a⁻¹.quasiLocalRelabel_norm z +theorem quasiLocalCovarianceEquiv_symm_uniformContinuous : + UniformContinuous a.quasiLocalCovarianceEquiv.symm := by + have h : ∀ z, ‖a.quasiLocalCovarianceEquiv.symm z‖ = ‖z‖ := fun z => by + rw [quasiLocalCovarianceEquiv_symm_apply]; exact a⁻¹.quasiLocalCovariance_norm z exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous /-- The covariance automorphism of the quasi-local C⋆-algebra: the continuous extension of - `quasiLocalRelabelStarEquiv` to the completion. -/ -noncomputable def quasiLocalCStarRelabel : + `quasiLocalCovarianceEquiv` to the completion. -/ +noncomputable def quasiLocalCStarCovarianceEquiv : N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := - UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalRelabelStarEquiv - a.quasiLocalRelabelStarEquiv_uniformContinuous - a.quasiLocalRelabelStarEquiv_symm_uniformContinuous + UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalCovarianceEquiv + a.quasiLocalCovarianceEquiv_uniformContinuous + a.quasiLocalCovarianceEquiv_symm_uniformContinuous -@[simp] theorem quasiLocalCStarRelabel_coe (z : N.quasiLocalAlgebra) : - a.quasiLocalCStarRelabel (↑z : N.quasiLocalCStarAlgebra) = ↑(a.quasiLocalRelabel z) := +@[simp] theorem quasiLocalCStarCovarianceEquiv_coe (z : N.quasiLocalAlgebra) : + a.quasiLocalCStarCovarianceEquiv (↑z : N.quasiLocalCStarAlgebra) = + ↑(a.quasiLocalCovariance z) := UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z -theorem quasiLocalCStarRelabel_continuous : - Continuous (⇑a.quasiLocalCStarRelabel) := +theorem quasiLocalCStarCovarianceEquiv_continuous : + Continuous (⇑a.quasiLocalCStarCovarianceEquiv) := UniformSpace.Completion.continuous_map -/-- A symmetry of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, +/-- A covariance of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, assembled as a group homomorphism into the `*`-automorphism group. -/ -noncomputable def quasiLocalCStarRelabelHom : - N.Symmetry →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where - toFun a := a.quasiLocalCStarRelabel +noncomputable def quasiLocalCStarCovarianceHom : + N.Covariance →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where + toFun a := a.quasiLocalCStarCovarianceEquiv map_one' := by refine StarAlgEquiv.ext fun z => ?_ rw [StarAlgEquiv.one_apply] refine UniformSpace.Completion.induction_on z - (isClosed_eq (1 : N.Symmetry).quasiLocalCStarRelabel_continuous continuous_id) ?_ + (isClosed_eq (1 : N.Covariance).quasiLocalCStarCovarianceEquiv_continuous + continuous_id) ?_ intro w - simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_one, RingHom.id_apply] + simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_one, RingHom.id_apply] map_mul' a b := by refine StarAlgEquiv.ext fun z => ?_ rw [StarAlgEquiv.mul_apply] refine UniformSpace.Completion.induction_on z - (isClosed_eq (a * b).quasiLocalCStarRelabel_continuous - (a.quasiLocalCStarRelabel_continuous.comp b.quasiLocalCStarRelabel_continuous)) ?_ + (isClosed_eq (a * b).quasiLocalCStarCovarianceEquiv_continuous + (a.quasiLocalCStarCovarianceEquiv_continuous.comp + b.quasiLocalCStarCovarianceEquiv_continuous)) ?_ intro w - simp only [quasiLocalCStarRelabel_coe, quasiLocalRelabel_mul, RingHom.comp_apply] + simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_mul, RingHom.comp_apply] -@[simp] theorem quasiLocalCStarRelabelHom_apply +@[simp] theorem quasiLocalCStarCovarianceHom_apply (z : N.quasiLocalCStarAlgebra) : - quasiLocalCStarRelabelHom a z = a.quasiLocalCStarRelabel z := rfl + quasiLocalCStarCovarianceHom a z = a.quasiLocalCStarCovarianceEquiv z := rfl end CStarCovariance -end Symmetry +end Covariance end LocalNet @@ -216,83 +386,84 @@ namespace SiteIndexSystem (h : Λ ⊆ Λ_total) (f : L.regionIdx Λ_total) (w : ↥(Λ_total \ Λ)) : ((L.combineIdx h).symm f).2 w = f ⟨w.val, (Finset.mem_sdiff.mp w.property).1⟩ := rfl -/-- A symmetry of a local net: a site permutation together with dimension-matching equivalences - on the local index types. A group acting on the net is a homomorphism into these. -/ -structure Symmetry (L : SiteIndexSystem) where +/-- A covariance datum for a site-index system: a site permutation together with + dimension-matching equivalences on the local index types. -/ +structure Covariance (L : SiteIndexSystem) where /-- The underlying permutation of the sites. -/ σ : L.sites ≃ L.sites - /-- Dimension matching: relabel the local index type at each site. -/ + /-- Dimension-matching equivalence of the local index type at each site. -/ idx : ∀ s, L.localIdx s ≃ L.localIdx (σ s) -namespace Symmetry +namespace Covariance -variable {L : SiteIndexSystem} (a : L.Symmetry) +variable {L : SiteIndexSystem} (a : L.Covariance) -/-- The image of a region under a symmetry. -/ +/-- The image of a region under a covariance. -/ def region (Λ : Finset L.sites) : Finset L.sites := Λ.map a.σ.toEmbedding variable (L) in -/-- The identity symmetry. -/ -def id : L.Symmetry where +/-- The identity covariance. -/ +def id : L.Covariance where σ := Equiv.refl _ idx _ := Equiv.refl _ -/-- Composition of symmetries: apply `b`, then `a`. The per-site equivalences compose, with the +/-- Composition of covariances: apply `b`, then `a`. The per-site equivalences compose, with the intermediate site type aligning definitionally. -/ -def comp (a b : L.Symmetry) : L.Symmetry where +def comp (a b : L.Covariance) : L.Covariance where σ := b.σ.trans a.σ idx s := (b.idx s).trans (a.idx (b.σ s)) -@[simp] theorem region_id (Λ : Finset L.sites) : (Symmetry.id L).region Λ = Λ := by - simp [region, Symmetry.id] +@[simp] theorem region_id (Λ : Finset L.sites) : (Covariance.id L).region Λ = Λ := by + simp [region, Covariance.id] -@[simp] theorem region_comp (a b : L.Symmetry) (Λ : Finset L.sites) : +@[simp] theorem region_comp (a b : L.Covariance) (Λ : Finset L.sites) : (a.comp b).region Λ = a.region (b.region Λ) := by simp [region, comp, Finset.map_map, Equiv.trans_toEmbedding] -/-- Relabelling of region indices: transport along the site permutation and the per-site - dimension equivalences. -/ -def relabelRegionIdx (Λ : Finset L.sites) : +/-- Equivalence of region index types induced by the site permutation and the per-site dimension + equivalences. -/ +def regionIdxEquiv (Λ : Finset L.sites) : L.regionIdx Λ ≃ L.regionIdx (a.region Λ) := Equiv.piCongr (Equiv.subtypeEquiv a.σ (fun _ => (Finset.mem_map' a.σ.toEmbedding).symm)) (fun s => a.idx s.val) /-- The **covariance `*`-isomorphism** `β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)`, obtained by reindexing the - matrix algebra along `relabelRegionIdx`. Realises `β_a(𝔄(Λ)) = 𝔄(a Λ)`. -/ -noncomputable def relabelAlgebra (Λ : Finset L.sites) : + matrix algebra along `regionIdxEquiv`. Realises `β_a(𝔄(Λ)) = 𝔄(a Λ)`. -/ +noncomputable def localCovariance (Λ : Finset L.sites) : L.localAlgebra Λ ≃⋆ₐ[ℂ] L.localAlgebra (a.region Λ) := - StarAlgEquiv.ofAlgEquiv (Matrix.reindexAlgEquiv ℂ ℂ (a.relabelRegionIdx Λ)) + StarAlgEquiv.ofAlgEquiv (Matrix.reindexAlgEquiv ℂ ℂ (a.regionIdxEquiv Λ)) (fun X => by simp only [Matrix.reindexAlgEquiv_apply, Matrix.star_eq_conjTranspose, Matrix.conjTranspose_reindex]) -@[simp] theorem relabelAlgebra_apply (Λ : Finset L.sites) (X : L.localAlgebra Λ) : - a.relabelAlgebra Λ X = Matrix.reindex (a.relabelRegionIdx Λ) (a.relabelRegionIdx Λ) X := +@[simp] theorem localCovariance_apply (Λ : Finset L.sites) (X : L.localAlgebra Λ) : + a.localCovariance Λ X = Matrix.reindex (a.regionIdxEquiv Λ) (a.regionIdxEquiv Λ) X := rfl -/-- The `Λ`-coordinate of decomposing a relabelled index equals relabelling the `aΛ`-coordinate: - `relabelRegionIdx` commutes with the isotony split `combineIdx`. Holds definitionally. -/ -private theorem relabelRegionIdx_symm_combineIdx_fst {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') +/-- The `Λ`-coordinate of decomposing a transported index equals the corresponding transported + `aΛ`-coordinate: `regionIdxEquiv` commutes with the isotony split `combineIdx`. Holds + definitionally. -/ +private theorem regionIdxEquiv_symm_combineIdx_fst {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') (t : L.regionIdx (a.region Λ')) : - ((L.combineIdx h).symm ((a.relabelRegionIdx Λ').symm t)).1 = - (a.relabelRegionIdx Λ).symm ((L.combineIdx (Finset.map_subset_map.mpr h)).symm t).1 := by + ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm t)).1 = + (a.regionIdxEquiv Λ).symm ((L.combineIdx (Finset.map_subset_map.mpr h)).symm t).1 := by funext u rfl -/-- **Covariance / naturality**: the symmetry `*`-isomorphism intertwines the isotony +/-- **Covariance / naturality**: the covariance `*`-isomorphism intertwines the isotony embeddings, so `β_a` is an automorphism of the *net* — `β_a(𝔄(Λ)) = 𝔄(a Λ)` compatibly with inclusions (Naaijkens 2012 §3.2 covariance axiom). -/ -theorem relabelAlgebra_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') +theorem localCovariance_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') (X : L.localAlgebra Λ) : - a.relabelAlgebra Λ' (L.includeAlgebra h X) = - L.includeAlgebra (Finset.map_subset_map.mpr h) (a.relabelAlgebra Λ X) := by + a.localCovariance Λ' (L.includeAlgebra h X) = + L.includeAlgebra (Finset.map_subset_map.mpr h) (a.localCovariance Λ X) := by ext s s' - simp only [relabelAlgebra_apply, Matrix.reindex_apply, Matrix.submatrix_apply, + simp only [localCovariance_apply, Matrix.reindex_apply, Matrix.submatrix_apply, includeAlgebra_apply] - rw [a.relabelRegionIdx_symm_combineIdx_fst h s, a.relabelRegionIdx_symm_combineIdx_fst h s'] - have key2 : (((L.combineIdx h).symm ((a.relabelRegionIdx Λ').symm s)).2 = - ((L.combineIdx h).symm ((a.relabelRegionIdx Λ').symm s')).2) + rw [a.regionIdxEquiv_symm_combineIdx_fst h s, a.regionIdxEquiv_symm_combineIdx_fst h s'] + have key2 : (((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s)).2 = + ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s')).2) ↔ (((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2) := by constructor @@ -303,7 +474,7 @@ theorem relabelAlgebra_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') have hΛ' : a.σ.symm vv ∈ Λ' := Finset.mem_map_equiv.mp hv.1 have hΛ : a.σ.symm vv ∉ Λ := fun hc => hv.2 (Finset.mem_map_equiv.mpr hc) have hcong := congrFun H ⟨a.σ.symm vv, Finset.mem_sdiff.mpr ⟨hΛ', hΛ⟩⟩ - simp only [combineIdx_symm_snd_apply, relabelRegionIdx, Equiv.piCongr_symm_apply, + simp only [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, Equiv.subtypeEquiv_apply, EmbeddingLike.apply_eq_iff_eq] at hcong change s ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ = s' ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ convert hcong using 2 <;> @@ -316,7 +487,7 @@ theorem relabelAlgebra_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') have hv : a.σ w.val ∈ a.region Λ' \ a.region Λ := Finset.mem_sdiff.mpr ⟨Finset.mem_map' _ |>.mpr hw.1, fun hc => hw.2 (Finset.mem_map' _ |>.mp hc)⟩ have hcong := congrFun H ⟨a.σ w.val, hv⟩ - simpa [combineIdx_symm_snd_apply, relabelRegionIdx, Equiv.piCongr_symm_apply, + simpa [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, Equiv.subtypeEquiv_apply, Equiv.symm_apply_apply, EmbeddingLike.apply_eq_iff_eq] using hcong by_cases hc : ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = @@ -326,30 +497,31 @@ theorem relabelAlgebra_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') /-! ### Covariance action on the quasi-local algebra -The per-region symmetry `*`-isomorphisms, being natural with respect to isotony -(`relabelAlgebra_includeAlgebra`), assemble a symmetry `toLocalNetSymmetry` of the abstract net +The per-region covariance `*`-isomorphisms, being natural with respect to isotony +(`localCovariance_includeAlgebra`), assemble a covariance `toLocalNetCovariance` of the abstract net `toLocalNet`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local -observables is therefore inherited from the net-level `LocalNet.Symmetry.quasiLocalRelabel`. -/ +observables is therefore inherited from the net-level `LocalNet.Covariance.quasiLocalCovariance`. -/ -/-- The symmetry of the generated local net `toLocalNet` induced by a lattice symmetry: the same - site permutation, with the reindexing `*`-isomorphisms `relabelAlgebra` as its covariance maps - and `relabelAlgebra_includeAlgebra` as the isotony naturality. This exhibits the concrete - covariance as an instance of the abstract `LocalNet.Symmetry`. -/ -noncomputable def toLocalNetSymmetry : L.toLocalNet.Symmetry where +/-- The covariance of the generated local net `toLocalNet` induced by a lattice covariance: the same + site permutation, with the local `*`-isomorphisms `localCovariance` as its covariance maps and + `localCovariance_includeAlgebra` as the isotony naturality. This exhibits the concrete + covariance as an instance of the abstract `LocalNet.Covariance`. -/ +noncomputable def toLocalNetCovariance : L.toLocalNet.Covariance where σ := a.σ - β := a.relabelAlgebra - β_incl h x := a.relabelAlgebra_includeAlgebra h x - -/-- The action of a symmetry on the algebra of local observables, as a ring homomorphism: - `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, relabel X⟩⟧`. Inherited from the abstract net-level covariance action - `LocalNet.Symmetry.quasiLocalRelabel` on `toLocalNet`. -/ -noncomputable def quasiLocalRelabel : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := - a.toLocalNetSymmetry.quasiLocalRelabel - -@[simp] theorem quasiLocalRelabel_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - a.quasiLocalRelabel (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.relabelAlgebra Λ X⟩⟧ := + β := a.localCovariance + β_incl h x := a.localCovariance_includeAlgebra h x + +/-- The action of a covariance on the algebra of local observables, as a ring homomorphism: + `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧`. Inherited from the abstract net-level covariance action + `LocalNet.Covariance.quasiLocalCovariance` on `toLocalNet`. -/ +noncomputable def quasiLocalCovariance : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := + a.toLocalNetCovariance.quasiLocalCovariance + +@[simp] theorem quasiLocalCovariance_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = + ⟦⟨a.region Λ, a.localCovariance Λ X⟩⟧ := rfl -end Symmetry +end Covariance end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Symmetry.lean b/QuantumSystem/Algebra/LocalNet/Symmetry.lean deleted file mode 100644 index 46e0854..0000000 --- a/QuantumSystem/Algebra/LocalNet/Symmetry.lean +++ /dev/null @@ -1,194 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.Net - -/-! -# Symmetries of a local net - -A **symmetry** of a local net is a site permutation `σ` together with, for every finite region -`Λ`, a `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect -to the isotony embeddings. This realises the AQFT covariance datum `β(𝔄(Λ)) = 𝔄(σΛ)` at the -abstract net level (Naaijkens 2012 §3.2, Verch 2025 §1.2). - -Symmetries compose: the identity and composition below, together with the inverse, make the -symmetries of a net a `Group`. This file carries only the symmetry *group* — purely algebraic data -depending on the net axioms. The induced **covariance action** of a symmetry on the algebra of -local observables (and its C⋆-completion) lives in `LocalNet.Covariance`. --/ - -@[expose] public section - -namespace LocalNet - -variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) - -/-! ### Symmetries of the net - -A **symmetry** of a local net is a site permutation `σ` together with, for each finite region, a -`*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the -isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)` at the abstract net -level. Being purely algebraic, the symmetry group needs no faithfulness hypothesis. --/ - -/-- A **symmetry** of a local net `N`: a site permutation `σ` together with, for every finite - region `Λ`, a `*`-isomorphism `β Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)`, natural with respect to the isotony - embeddings (`β_incl`). This is the AQFT covariance datum at the abstract net level. -/ -structure Symmetry where - /-- The underlying site permutation; its image map `Λ ↦ σΛ` carries the region map. -/ - σ : sites ≃ sites - /-- The covariance `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` on each region. -/ - β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding) - /-- **Naturality / covariance**: `β` intertwines the isotony embeddings, so it maps the net to - itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)`. -/ - β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), - β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x) - -namespace Symmetry - -variable {N} (a : N.Symmetry) - -/-- The image `σΛ` of a region under the symmetry. -/ -def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding - -/-- **Extensionality** for symmetries: two symmetries with the same site permutation and the same - local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality - field `β_incl` is a proposition, hence irrelevant. -/ -@[ext (iff := false)] theorem ext {s t : N.Symmetry} (hσ : s.σ = t.σ) - (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), - N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by - revert hσ hβ - obtain ⟨sσ, sβ, -⟩ := s - obtain ⟨tσ, tβ, -⟩ := t - rintro rfl hβ - have hβ' : sβ = tβ := by - funext Λ - ext x - simpa using hβ Λ x rfl - subst hβ' - rfl - -/-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ -theorem β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : - (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by - have key := a.β_incl h ((a.β Λ).symm y) - rw [StarAlgEquiv.apply_symm_apply] at key - rw [← key, StarAlgEquiv.symm_apply_apply] - -/-- The local `*`-isomorphisms commute with the region-equality transport. -/ -theorem β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : - a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by - subst e; simp - -variable (N) in -/-- The **identity symmetry**: the identity site permutation with the identity local - `*`-isomorphisms (transported along `Λ = σ_id Λ`). -/ -def id : N.Symmetry where - σ := Equiv.refl sites - β Λ := N.algebraCongr (by simp) - β_incl h x := N.incl_algebraCongr _ _ h _ x - -/-- **Composition of symmetries**: apply `b`, then `a`. The site permutations compose; the local - `*`-isomorphisms compose and are transported along the region-map functoriality - `(σ_a ∘ σ_b) Λ = σ_a (σ_b Λ)`. -/ -def comp (a b : N.Symmetry) : N.Symmetry where - σ := b.σ.trans a.σ - β Λ := ((b.β Λ).trans (a.β (Λ.map b.σ.toEmbedding))).trans - (N.algebraCongr (by simp [Finset.map_map, Equiv.trans_toEmbedding])) - β_incl h x := by - simp only [StarAlgEquiv.trans_apply] - rw [b.β_incl h, a.β_incl (Finset.map_subset_map.mpr h)] - exact N.incl_algebraCongr _ _ _ _ _ - -/-- The **inverse symmetry**: the inverse site permutation with the inverse local - `*`-isomorphisms, transported along the region-map functoriality `σ⁻¹σ Λ = Λ`. -/ -def inv (a : N.Symmetry) : N.Symmetry where - σ := a.σ.symm - β Λ := (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by - simp [Finset.map_map]).symm).trans - (a.β (Λ.map a.σ.symm.toEmbedding)).symm - β_incl h x := by - simp only [StarAlgEquiv.trans_apply] - rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), - a.β_symm_incl] - -@[simp] theorem id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : - (Symmetry.id N).β Λ x = - N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := - rfl - -@[simp] theorem comp_β_apply (a b : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : - (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding - = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) - (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := - rfl - -@[simp] theorem inv_β_apply (a : N.Symmetry) (Λ : Finset sites) (x : N.algebra Λ) : - (Symmetry.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm - (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by - simp [Finset.map_map]).symm x) := - rfl - -@[simp] theorem region_id (Λ : Finset sites) : (Symmetry.id N).region Λ = Λ := by - simp [region, Symmetry.id] - -@[simp] theorem region_comp (a b : N.Symmetry) (Λ : Finset sites) : - (a.comp b).region Λ = a.region (b.region Λ) := by - simp [region, Symmetry.comp, Finset.map_map, Equiv.trans_toEmbedding] - -theorem id_comp (a : N.Symmetry) : (Symmetry.id N).comp a = a := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Symmetry.id] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, id_β_apply] - erw [algebraCongr_trans] - rfl - -theorem comp_id (a : N.Symmetry) : a.comp (Symmetry.id N) = a := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Symmetry.id] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, id_β_apply] - erw [a.β_algebraCongr, algebraCongr_trans] - rfl - -theorem comp_assoc (a b c : N.Symmetry) : (a.comp b).comp c = a.comp (b.comp c) := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Equiv.trans_assoc] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply] - erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] - rfl - -theorem inv_comp (a : N.Symmetry) : (Symmetry.inv a).comp a = Symmetry.id N := by - refine Symmetry.ext ?_ fun Λ x e => ?_ - · simp [Symmetry.comp, Symmetry.inv, Symmetry.id, Equiv.self_trans_symm] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, inv_β_apply, id_β_apply] - erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply, algebraCongr_trans, - algebraCongr_trans] - · rfl - · simp [Finset.map_map] - -/-- The symmetries of a local net form a **group** under composition, with `Symmetry.id` the unit - and `Symmetry.inv` the inverse. -/ -noncomputable instance : Group N.Symmetry where - mul a b := a.comp b - one := Symmetry.id N - inv a := a.inv - mul_assoc := Symmetry.comp_assoc - one_mul := Symmetry.id_comp - mul_one := Symmetry.comp_id - inv_mul_cancel := Symmetry.inv_comp - -/-- The group multiplication is composition of symmetries. -/ -theorem mul_def (a b : N.Symmetry) : a * b = a.comp b := rfl - -/-- The group unit is the identity symmetry. -/ -theorem one_def : (1 : N.Symmetry) = Symmetry.id N := rfl - -/-- The group inverse is the inverse symmetry. -/ -theorem inv_def (a : N.Symmetry) : a⁻¹ = a.inv := rfl - -end Symmetry - -end LocalNet From bcd5829fef5ab477b91b658e096518daaa35addd Mon Sep 17 00:00:00 2001 From: suzuki Date: Fri, 26 Jun 2026 04:56:02 +0000 Subject: [PATCH 024/113] refactor(localnet): separate abstract covariance, its action, and the concrete example Split the covariance material across three files by abstraction level: - Covariance.lean: abstract `LocalNet.Covariance` data and group structure only (now depends on Net alone). - QuasiLocal.lean: hosts the abstract covariance action on the quasi-local algebra and its C*-completion. - LatticeCovariance.lean (new): the concrete `SiteIndexSystem.Covariance` of the generated matrix net, together with its inherited action. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 1 + .../Algebra/LocalNet/Covariance.lean | 351 +----------------- .../Algebra/LocalNet/LatticeCovariance.lean | 169 +++++++++ .../Algebra/LocalNet/QuasiLocal.lean | 194 ++++++++++ 4 files changed, 374 insertions(+), 341 deletions(-) create mode 100644 QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 11c2530..6f9ce83 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -20,6 +20,7 @@ public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful public import QuantumSystem.Algebra.LocalNet.Basic public import QuantumSystem.Algebra.LocalNet.Covariance public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.Algebra.LocalNet.LatticeCovariance public import QuantumSystem.Algebra.LocalNet.Locality public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocal diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 211ed1d..fb05170 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -1,26 +1,21 @@ module -public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.Net /-! -# Covariance data and action for a local net +# Covariance data for a local net A **covariance** of a local net is a site permutation `σ` together with, for every finite region `Λ`, a `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the isotony embeddings. The naturality field `β_incl` is the AQFT covariance axiom -`β(𝔄(Λ)) = 𝔄(σΛ)` compatibly with inclusions (Naaijkens 2012 §3.2, Verch 2025 §1.2). - -Such covariance data acts on the **algebra of local observables** by -`β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧`. The per-region `*`-isomorphisms assemble into a -`*`-endomorphism `quasiLocalCovariance` of the quasi-local algebra. This action is functorial in the -covariance group, `ℂ`-linear and `*`-preserving, hence a `*`-automorphism; for a `Faithful` net it -is isometric and extends to a `*`-automorphism of the quasi-local C⋆-algebra. - -A **covariance** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each -site, an equivalence `localIdx s ≃ localIdx (σ s)` matching the local dimensions. Such data induces -a `*`-isomorphism `β : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σ Λ)` (`localCovariance`), assembling into an abstract -`LocalNet.Covariance` of the generated net (`toLocalNetCovariance`) and hence inheriting the -action above. +`β(𝔄(Λ)) = 𝔄(σΛ)` compatibly with inclusions (Naaijkens 2012 §3.2, Verch 2025 §1.2). These +covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp`, `Covariance.inv`). + +This file isolates the abstract covariance *data* and its group structure. Its *action* on the +quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism +`quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local +C⋆-algebra — is built in `LocalNet.QuasiLocal`. The concrete covariance of the matrix net generated +by a `SiteIndexSystem`, together with its inherited action, lives in `LocalNet.LatticeCovariance`. -/ @[expose] public section @@ -196,332 +191,6 @@ theorem one_def : (1 : N.Covariance) = Covariance.id N := rfl /-- The group inverse is the inverse covariance. -/ theorem inv_def (a : N.Covariance) : a⁻¹ = a.inv := rfl -/-! ### The induced covariance action -/ - -/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a covariance on the algebra of local - observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ -noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := - DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra - (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) - (fun Λ Λ' h X => by - change N.ιLocal (a.region Λ') (a.β Λ' (N.incl h X)) = N.ιLocal (a.region Λ) (a.β Λ X) - rw [a.β_incl h] - exact N.ιLocal_incl _ _) - -@[simp] theorem quasiLocalCovariance_mk {Λ : Finset sites} (X : N.algebra Λ) : - a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := - rfl - -/-- The covariance action of the identity covariance is the identity: `β_{id} = id`. -/ -@[simp] theorem quasiLocalCovariance_id : - (Covariance.id N).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by - refine RingHom.ext fun z => ?_ - induction z using DirectLimit.induction with - | _ Λ X => rw [quasiLocalCovariance_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X - -/-- **Functoriality of the covariance action**: composing covariances composes their actions, - `β_{a∘b} = β_a ∘ β_b`. -/ -@[simp] theorem quasiLocalCovariance_comp (a b : N.Covariance) : - (a.comp b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by - refine RingHom.ext fun z => ?_ - induction z using DirectLimit.induction with - | _ Λ X => - simp only [RingHom.comp_apply, quasiLocalCovariance_mk] - exact N.ιLocal_algebraCongr _ _ - -/-- The covariance action sends the unit covariance to the identity: `β_1 = id`. -/ -@[simp] theorem quasiLocalCovariance_one : - (1 : N.Covariance).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by - rw [one_def, quasiLocalCovariance_id] - -/-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. -/ -theorem quasiLocalCovariance_mul (a b : N.Covariance) : - (a * b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by - rw [mul_def, quasiLocalCovariance_comp] - -/-! #### The covariance action as a `*`-automorphism -/ - -/-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ -theorem quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : - a.quasiLocalCovariance (c • z) = c • a.quasiLocalCovariance z := by - induction z using DirectLimit.induction with - | _ Λ X => - rw [DirectLimit.smul_def, quasiLocalCovariance_mk, quasiLocalCovariance_mk, DirectLimit.smul_def, - map_smul] - rfl - -/-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` - is a `*`-isomorphism. -/ -theorem quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : - a.quasiLocalCovariance (star z) = star (a.quasiLocalCovariance z) := by - induction z using DirectLimit.induction with - | _ Λ X => - rw [star_mk, quasiLocalCovariance_mk, quasiLocalCovariance_mk, star_mk, map_star] - rfl - -/-- The covariance action as a `*`-algebra automorphism of the algebra of local observables, with - the action of the inverse covariance `a⁻¹` as its inverse. -/ -noncomputable def quasiLocalCovarianceEquiv : - N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where - toFun := a.quasiLocalCovariance - invFun := a⁻¹.quasiLocalCovariance - left_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, inv_mul_cancel, quasiLocalCovariance_one, - RingHom.id_apply] - right_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, mul_inv_cancel, quasiLocalCovariance_one, - RingHom.id_apply] - map_mul' := map_mul a.quasiLocalCovariance - map_add' := map_add a.quasiLocalCovariance - map_smul' := a.quasiLocalCovariance_smul - map_star' := a.quasiLocalCovariance_star - -@[simp] theorem quasiLocalCovarianceEquiv_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalCovarianceEquiv z = a.quasiLocalCovariance z := rfl - -@[simp] theorem quasiLocalCovarianceEquiv_symm_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalCovarianceEquiv.symm z = a⁻¹.quasiLocalCovariance z := rfl - -/-- A covariance of the net acts on the algebra of local observables by `*`-algebra automorphisms, - assembled as a group homomorphism into the `*`-automorphism group. -/ -noncomputable def quasiLocalCovarianceHom : - N.Covariance →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where - toFun a := a.quasiLocalCovarianceEquiv - map_one' := by - ext z - simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_one, RingHom.id_apply, - StarAlgEquiv.one_apply] - map_mul' a b := by - ext z - simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_mul, RingHom.comp_apply, - StarAlgEquiv.mul_apply] - -@[simp] theorem quasiLocalCovarianceHom_apply (z : N.quasiLocalAlgebra) : - quasiLocalCovarianceHom a z = a.quasiLocalCovariance z := rfl - -/-! #### The covariance automorphism of the quasi-local C⋆-algebra -/ - -section CStarCovariance - -variable [N.Faithful] - -/-- The covariance action is **isometric** on the algebra of local observables: each `β` is a - `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ -theorem quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : - ‖a.quasiLocalCovariance z‖ = ‖z‖ := by - induction z using DirectLimit.induction with - | _ Λ X => - rw [quasiLocalCovariance_mk, norm_mk, norm_mk] - exact StarAlgEquiv.norm_map _ X - -/-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is - an isometry), so it extends to the C⋆-completion. -/ -theorem quasiLocalCovarianceEquiv_uniformContinuous : - UniformContinuous a.quasiLocalCovarianceEquiv := - (AddMonoidHomClass.isometry_of_norm _ (fun z => by - rw [quasiLocalCovarianceEquiv_apply]; exact a.quasiLocalCovariance_norm z)).uniformContinuous - -/-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is - also an isometry). -/ -theorem quasiLocalCovarianceEquiv_symm_uniformContinuous : - UniformContinuous a.quasiLocalCovarianceEquiv.symm := by - have h : ∀ z, ‖a.quasiLocalCovarianceEquiv.symm z‖ = ‖z‖ := fun z => by - rw [quasiLocalCovarianceEquiv_symm_apply]; exact a⁻¹.quasiLocalCovariance_norm z - exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous - -/-- The covariance automorphism of the quasi-local C⋆-algebra: the continuous extension of - `quasiLocalCovarianceEquiv` to the completion. -/ -noncomputable def quasiLocalCStarCovarianceEquiv : - N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := - UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalCovarianceEquiv - a.quasiLocalCovarianceEquiv_uniformContinuous - a.quasiLocalCovarianceEquiv_symm_uniformContinuous - -@[simp] theorem quasiLocalCStarCovarianceEquiv_coe (z : N.quasiLocalAlgebra) : - a.quasiLocalCStarCovarianceEquiv (↑z : N.quasiLocalCStarAlgebra) = - ↑(a.quasiLocalCovariance z) := - UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z - -theorem quasiLocalCStarCovarianceEquiv_continuous : - Continuous (⇑a.quasiLocalCStarCovarianceEquiv) := - UniformSpace.Completion.continuous_map - -/-- A covariance of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, - assembled as a group homomorphism into the `*`-automorphism group. -/ -noncomputable def quasiLocalCStarCovarianceHom : - N.Covariance →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where - toFun a := a.quasiLocalCStarCovarianceEquiv - map_one' := by - refine StarAlgEquiv.ext fun z => ?_ - rw [StarAlgEquiv.one_apply] - refine UniformSpace.Completion.induction_on z - (isClosed_eq (1 : N.Covariance).quasiLocalCStarCovarianceEquiv_continuous - continuous_id) ?_ - intro w - simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_one, RingHom.id_apply] - map_mul' a b := by - refine StarAlgEquiv.ext fun z => ?_ - rw [StarAlgEquiv.mul_apply] - refine UniformSpace.Completion.induction_on z - (isClosed_eq (a * b).quasiLocalCStarCovarianceEquiv_continuous - (a.quasiLocalCStarCovarianceEquiv_continuous.comp - b.quasiLocalCStarCovarianceEquiv_continuous)) ?_ - intro w - simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_mul, RingHom.comp_apply] - -@[simp] theorem quasiLocalCStarCovarianceHom_apply - (z : N.quasiLocalCStarAlgebra) : - quasiLocalCStarCovarianceHom a z = a.quasiLocalCStarCovarianceEquiv z := rfl - -end CStarCovariance - end Covariance end LocalNet - -namespace SiteIndexSystem - -/-- Pointwise value of the complement projection of `combineIdx.symm` (holds by `rfl`). -/ -@[simp] theorem combineIdx_symm_snd_apply {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) (f : L.regionIdx Λ_total) (w : ↥(Λ_total \ Λ)) : - ((L.combineIdx h).symm f).2 w = f ⟨w.val, (Finset.mem_sdiff.mp w.property).1⟩ := rfl - -/-- A covariance datum for a site-index system: a site permutation together with - dimension-matching equivalences on the local index types. -/ -structure Covariance (L : SiteIndexSystem) where - /-- The underlying permutation of the sites. -/ - σ : L.sites ≃ L.sites - /-- Dimension-matching equivalence of the local index type at each site. -/ - idx : ∀ s, L.localIdx s ≃ L.localIdx (σ s) - -namespace Covariance - -variable {L : SiteIndexSystem} (a : L.Covariance) - -/-- The image of a region under a covariance. -/ -def region (Λ : Finset L.sites) : Finset L.sites := Λ.map a.σ.toEmbedding - -variable (L) in -/-- The identity covariance. -/ -def id : L.Covariance where - σ := Equiv.refl _ - idx _ := Equiv.refl _ - -/-- Composition of covariances: apply `b`, then `a`. The per-site equivalences compose, with the - intermediate site type aligning definitionally. -/ -def comp (a b : L.Covariance) : L.Covariance where - σ := b.σ.trans a.σ - idx s := (b.idx s).trans (a.idx (b.σ s)) - -@[simp] theorem region_id (Λ : Finset L.sites) : (Covariance.id L).region Λ = Λ := by - simp [region, Covariance.id] - -@[simp] theorem region_comp (a b : L.Covariance) (Λ : Finset L.sites) : - (a.comp b).region Λ = a.region (b.region Λ) := by - simp [region, comp, Finset.map_map, Equiv.trans_toEmbedding] - -/-- Equivalence of region index types induced by the site permutation and the per-site dimension - equivalences. -/ -def regionIdxEquiv (Λ : Finset L.sites) : - L.regionIdx Λ ≃ L.regionIdx (a.region Λ) := - Equiv.piCongr - (Equiv.subtypeEquiv a.σ (fun _ => (Finset.mem_map' a.σ.toEmbedding).symm)) - (fun s => a.idx s.val) - -/-- The **covariance `*`-isomorphism** `β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)`, obtained by reindexing the - matrix algebra along `regionIdxEquiv`. Realises `β_a(𝔄(Λ)) = 𝔄(a Λ)`. -/ -noncomputable def localCovariance (Λ : Finset L.sites) : - L.localAlgebra Λ ≃⋆ₐ[ℂ] L.localAlgebra (a.region Λ) := - StarAlgEquiv.ofAlgEquiv (Matrix.reindexAlgEquiv ℂ ℂ (a.regionIdxEquiv Λ)) - (fun X => by - simp only [Matrix.reindexAlgEquiv_apply, Matrix.star_eq_conjTranspose, - Matrix.conjTranspose_reindex]) - -@[simp] theorem localCovariance_apply (Λ : Finset L.sites) (X : L.localAlgebra Λ) : - a.localCovariance Λ X = Matrix.reindex (a.regionIdxEquiv Λ) (a.regionIdxEquiv Λ) X := - rfl - -/-- The `Λ`-coordinate of decomposing a transported index equals the corresponding transported - `aΛ`-coordinate: `regionIdxEquiv` commutes with the isotony split `combineIdx`. Holds - definitionally. -/ -private theorem regionIdxEquiv_symm_combineIdx_fst {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') - (t : L.regionIdx (a.region Λ')) : - ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm t)).1 = - (a.regionIdxEquiv Λ).symm ((L.combineIdx (Finset.map_subset_map.mpr h)).symm t).1 := by - funext u - rfl - -/-- **Covariance / naturality**: the covariance `*`-isomorphism intertwines the isotony - embeddings, so `β_a` is an automorphism of the *net* — `β_a(𝔄(Λ)) = 𝔄(a Λ)` compatibly with - inclusions (Naaijkens 2012 §3.2 covariance axiom). -/ -theorem localCovariance_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') - (X : L.localAlgebra Λ) : - a.localCovariance Λ' (L.includeAlgebra h X) = - L.includeAlgebra (Finset.map_subset_map.mpr h) (a.localCovariance Λ X) := by - ext s s' - simp only [localCovariance_apply, Matrix.reindex_apply, Matrix.submatrix_apply, - includeAlgebra_apply] - rw [a.regionIdxEquiv_symm_combineIdx_fst h s, a.regionIdxEquiv_symm_combineIdx_fst h s'] - have key2 : (((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s)).2 = - ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s')).2) - ↔ (((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = - ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2) := by - constructor - · intro H - funext v - obtain ⟨vv, hvv⟩ := v - have hv := Finset.mem_sdiff.mp hvv - have hΛ' : a.σ.symm vv ∈ Λ' := Finset.mem_map_equiv.mp hv.1 - have hΛ : a.σ.symm vv ∉ Λ := fun hc => hv.2 (Finset.mem_map_equiv.mpr hc) - have hcong := congrFun H ⟨a.σ.symm vv, Finset.mem_sdiff.mpr ⟨hΛ', hΛ⟩⟩ - simp only [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, - Equiv.subtypeEquiv_apply, EmbeddingLike.apply_eq_iff_eq] at hcong - change s ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ = s' ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ - convert hcong using 2 <;> - first - | exact (a.σ.apply_symm_apply vv).symm - | exact Subtype.ext (a.σ.apply_symm_apply vv).symm - · intro H - funext w - have hw := Finset.mem_sdiff.mp w.property - have hv : a.σ w.val ∈ a.region Λ' \ a.region Λ := Finset.mem_sdiff.mpr - ⟨Finset.mem_map' _ |>.mpr hw.1, fun hc => hw.2 (Finset.mem_map' _ |>.mp hc)⟩ - have hcong := congrFun H ⟨a.σ w.val, hv⟩ - simpa [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, - Equiv.subtypeEquiv_apply, Equiv.symm_apply_apply, - EmbeddingLike.apply_eq_iff_eq] using hcong - by_cases hc : ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = - ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2 - · rw [if_pos (key2.mpr hc), if_pos hc] - · rw [if_neg (fun hcc => hc (key2.mp hcc)), if_neg hc] - -/-! ### Covariance action on the quasi-local algebra - -The per-region covariance `*`-isomorphisms, being natural with respect to isotony -(`localCovariance_includeAlgebra`), assemble a covariance `toLocalNetCovariance` of the abstract net -`toLocalNet`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local -observables is therefore inherited from the net-level `LocalNet.Covariance.quasiLocalCovariance`. -/ - -/-- The covariance of the generated local net `toLocalNet` induced by a lattice covariance: the same - site permutation, with the local `*`-isomorphisms `localCovariance` as its covariance maps and - `localCovariance_includeAlgebra` as the isotony naturality. This exhibits the concrete - covariance as an instance of the abstract `LocalNet.Covariance`. -/ -noncomputable def toLocalNetCovariance : L.toLocalNet.Covariance where - σ := a.σ - β := a.localCovariance - β_incl h x := a.localCovariance_includeAlgebra h x - -/-- The action of a covariance on the algebra of local observables, as a ring homomorphism: - `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧`. Inherited from the abstract net-level covariance action - `LocalNet.Covariance.quasiLocalCovariance` on `toLocalNet`. -/ -noncomputable def quasiLocalCovariance : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := - a.toLocalNetCovariance.quasiLocalCovariance - -@[simp] theorem quasiLocalCovariance_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = - ⟦⟨a.region Λ, a.localCovariance Λ X⟩⟧ := - rfl - -end Covariance - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean b/QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean new file mode 100644 index 0000000..cf5ee79 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean @@ -0,0 +1,169 @@ +module + +public import QuantumSystem.Algebra.LocalNet.QuasiLocal + +/-! +# Covariance of the local net generated by a lattice system + +A **covariance** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each +site, a dimension-matching equivalence `localIdx s ≃ localIdx (σ s)` of the local index types. Such +data reindexes the finite-region matrix algebras and so induces a `*`-isomorphism +`β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)` (`localCovariance`), natural with respect to the isotony embeddings +(`localCovariance_includeAlgebra`) — the AQFT covariance axiom `β_a(𝔄(Λ)) = 𝔄(a Λ)` for the +finite-dimensional matrix model. + +These per-region `*`-isomorphisms assemble a covariance `toLocalNetCovariance` of the generated +abstract net `toLocalNet`, exhibiting the concrete covariance as an instance of the abstract +`LocalNet.Covariance`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local +observables is therefore inherited from the net-level `LocalNet.Covariance.quasiLocalCovariance`, +together with the `*`-automorphism and C⋆-completion structure built there. +-/ + +@[expose] public section + +namespace SiteIndexSystem + +/-- Pointwise value of the complement projection of `combineIdx.symm` (holds by `rfl`). -/ +@[simp] theorem combineIdx_symm_snd_apply {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} + (h : Λ ⊆ Λ_total) (f : L.regionIdx Λ_total) (w : ↥(Λ_total \ Λ)) : + ((L.combineIdx h).symm f).2 w = f ⟨w.val, (Finset.mem_sdiff.mp w.property).1⟩ := rfl + +/-- A covariance datum for a site-index system: a site permutation together with + dimension-matching equivalences on the local index types. -/ +structure Covariance (L : SiteIndexSystem) where + /-- The underlying permutation of the sites. -/ + σ : L.sites ≃ L.sites + /-- Dimension-matching equivalence of the local index type at each site. -/ + idx : ∀ s, L.localIdx s ≃ L.localIdx (σ s) + +namespace Covariance + +variable {L : SiteIndexSystem} (a : L.Covariance) + +/-- The image of a region under a covariance. -/ +def region (Λ : Finset L.sites) : Finset L.sites := Λ.map a.σ.toEmbedding + +variable (L) in +/-- The identity covariance. -/ +def id : L.Covariance where + σ := Equiv.refl _ + idx _ := Equiv.refl _ + +/-- Composition of covariances: apply `b`, then `a`. The per-site equivalences compose, with the + intermediate site type aligning definitionally. -/ +def comp (a b : L.Covariance) : L.Covariance where + σ := b.σ.trans a.σ + idx s := (b.idx s).trans (a.idx (b.σ s)) + +@[simp] theorem region_id (Λ : Finset L.sites) : (Covariance.id L).region Λ = Λ := by + simp [region, Covariance.id] + +@[simp] theorem region_comp (a b : L.Covariance) (Λ : Finset L.sites) : + (a.comp b).region Λ = a.region (b.region Λ) := by + simp [region, comp, Finset.map_map, Equiv.trans_toEmbedding] + +/-- Equivalence of region index types induced by the site permutation and the per-site dimension + equivalences. -/ +def regionIdxEquiv (Λ : Finset L.sites) : + L.regionIdx Λ ≃ L.regionIdx (a.region Λ) := + Equiv.piCongr + (Equiv.subtypeEquiv a.σ (fun _ => (Finset.mem_map' a.σ.toEmbedding).symm)) + (fun s => a.idx s.val) + +/-- The **covariance `*`-isomorphism** `β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)`, obtained by reindexing the + matrix algebra along `regionIdxEquiv`. Realises `β_a(𝔄(Λ)) = 𝔄(a Λ)`. -/ +noncomputable def localCovariance (Λ : Finset L.sites) : + L.localAlgebra Λ ≃⋆ₐ[ℂ] L.localAlgebra (a.region Λ) := + StarAlgEquiv.ofAlgEquiv (Matrix.reindexAlgEquiv ℂ ℂ (a.regionIdxEquiv Λ)) + (fun X => by + simp only [Matrix.reindexAlgEquiv_apply, Matrix.star_eq_conjTranspose, + Matrix.conjTranspose_reindex]) + +@[simp] theorem localCovariance_apply (Λ : Finset L.sites) (X : L.localAlgebra Λ) : + a.localCovariance Λ X = Matrix.reindex (a.regionIdxEquiv Λ) (a.regionIdxEquiv Λ) X := + rfl + +/-- The `Λ`-coordinate of decomposing a transported index equals the corresponding transported + `aΛ`-coordinate: `regionIdxEquiv` commutes with the isotony split `combineIdx`. Holds + definitionally. -/ +private theorem regionIdxEquiv_symm_combineIdx_fst {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') + (t : L.regionIdx (a.region Λ')) : + ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm t)).1 = + (a.regionIdxEquiv Λ).symm ((L.combineIdx (Finset.map_subset_map.mpr h)).symm t).1 := by + funext u + rfl + +/-- **Covariance / naturality**: the covariance `*`-isomorphism intertwines the isotony + embeddings, so `β_a` is an automorphism of the *net* — `β_a(𝔄(Λ)) = 𝔄(a Λ)` compatibly with + inclusions (Naaijkens 2012 §3.2 covariance axiom). -/ +theorem localCovariance_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') + (X : L.localAlgebra Λ) : + a.localCovariance Λ' (L.includeAlgebra h X) = + L.includeAlgebra (Finset.map_subset_map.mpr h) (a.localCovariance Λ X) := by + ext s s' + simp only [localCovariance_apply, Matrix.reindex_apply, Matrix.submatrix_apply, + includeAlgebra_apply] + rw [a.regionIdxEquiv_symm_combineIdx_fst h s, a.regionIdxEquiv_symm_combineIdx_fst h s'] + have key2 : (((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s)).2 = + ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s')).2) + ↔ (((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = + ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2) := by + constructor + · intro H + funext v + obtain ⟨vv, hvv⟩ := v + have hv := Finset.mem_sdiff.mp hvv + have hΛ' : a.σ.symm vv ∈ Λ' := Finset.mem_map_equiv.mp hv.1 + have hΛ : a.σ.symm vv ∉ Λ := fun hc => hv.2 (Finset.mem_map_equiv.mpr hc) + have hcong := congrFun H ⟨a.σ.symm vv, Finset.mem_sdiff.mpr ⟨hΛ', hΛ⟩⟩ + simp only [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, + Equiv.subtypeEquiv_apply, EmbeddingLike.apply_eq_iff_eq] at hcong + change s ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ = s' ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ + convert hcong using 2 <;> + first + | exact (a.σ.apply_symm_apply vv).symm + | exact Subtype.ext (a.σ.apply_symm_apply vv).symm + · intro H + funext w + have hw := Finset.mem_sdiff.mp w.property + have hv : a.σ w.val ∈ a.region Λ' \ a.region Λ := Finset.mem_sdiff.mpr + ⟨Finset.mem_map' _ |>.mpr hw.1, fun hc => hw.2 (Finset.mem_map' _ |>.mp hc)⟩ + have hcong := congrFun H ⟨a.σ w.val, hv⟩ + simpa [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, + Equiv.subtypeEquiv_apply, Equiv.symm_apply_apply, + EmbeddingLike.apply_eq_iff_eq] using hcong + by_cases hc : ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = + ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2 + · rw [if_pos (key2.mpr hc), if_pos hc] + · rw [if_neg (fun hcc => hc (key2.mp hcc)), if_neg hc] + +/-! ### Covariance action on the quasi-local algebra + +The per-region covariance `*`-isomorphisms, being natural with respect to isotony +(`localCovariance_includeAlgebra`), assemble a covariance `toLocalNetCovariance` of the abstract net +`toLocalNet`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local +observables is therefore inherited from the net-level `LocalNet.Covariance.quasiLocalCovariance`. -/ + +/-- The covariance of the generated local net `toLocalNet` induced by a lattice covariance: the same + site permutation, with the local `*`-isomorphisms `localCovariance` as its covariance maps and + `localCovariance_includeAlgebra` as the isotony naturality. This exhibits the concrete + covariance as an instance of the abstract `LocalNet.Covariance`. -/ +noncomputable def toLocalNetCovariance : L.toLocalNet.Covariance where + σ := a.σ + β := a.localCovariance + β_incl h x := a.localCovariance_includeAlgebra h x + +/-- The action of a covariance on the algebra of local observables, as a ring homomorphism: + `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧`. Inherited from the abstract net-level covariance action + `LocalNet.Covariance.quasiLocalCovariance` on `toLocalNet`. -/ +noncomputable def quasiLocalCovariance : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := + a.toLocalNetCovariance.quasiLocalCovariance + +@[simp] theorem quasiLocalCovariance_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : + a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = + ⟦⟨a.region Λ, a.localCovariance Λ X⟩⟧ := + rfl + +end Covariance + +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean index 434fb7a..179c1a3 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean @@ -1,6 +1,7 @@ module public import Mathlib.Analysis.CStarAlgebra.Matrix +public import QuantumSystem.Algebra.LocalNet.Covariance public import QuantumSystem.Algebra.LocalNet.Locality public import QuantumSystem.Algebra.LocalNet.Net @@ -25,6 +26,14 @@ assignment `Λ ↦ 𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` to each finite region The lattice-system-level abbreviations `quasiLocalAlgebra` / `ιLocal` / `quasiLocalCStarAlgebra` below are thin wrappers around the corresponding `LocalNet` constructions on `toLocalNet`. + +A `LocalNet.Covariance` (defined in `LocalNet.Covariance`) acts on these algebras: its per-region +`*`-isomorphisms assemble into a `*`-endomorphism `quasiLocalCovariance` of the algebra of local +observables, which is functorial, `ℂ`-linear and `*`-preserving — hence a `*`-automorphism +`quasiLocalCovarianceEquiv`, assembled into a group homomorphism `quasiLocalCovarianceHom`. For a +`Faithful` net it is isometric and extends to a `*`-automorphism `quasiLocalCStarCovarianceEquiv` of +the quasi-local C⋆-algebra. The concrete `SiteIndexSystem.Covariance` and its inherited action are +built on top of these constructions in `LocalNet.LatticeCovariance`. -/ @[expose] public section @@ -156,6 +165,191 @@ theorem denseRange_iUnion_ιLocalCStar : end CStar +namespace Covariance + +variable {N} (a : N.Covariance) + +/-! ### The induced covariance action -/ + +/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a covariance on the algebra of local + observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ +noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := + DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra + (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) + (fun Λ Λ' h X => by + change N.ιLocal (a.region Λ') (a.β Λ' (N.incl h X)) = N.ιLocal (a.region Λ) (a.β Λ X) + rw [a.β_incl h] + exact N.ιLocal_incl _ _) + +@[simp] theorem quasiLocalCovariance_mk {Λ : Finset sites} (X : N.algebra Λ) : + a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := + rfl + +/-- The covariance action of the identity covariance is the identity: `β_{id} = id`. -/ +@[simp] theorem quasiLocalCovariance_id : + (Covariance.id N).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by + refine RingHom.ext fun z => ?_ + induction z using DirectLimit.induction with + | _ Λ X => rw [quasiLocalCovariance_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X + +/-- **Functoriality of the covariance action**: composing covariances composes their actions, + `β_{a∘b} = β_a ∘ β_b`. -/ +@[simp] theorem quasiLocalCovariance_comp (a b : N.Covariance) : + (a.comp b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by + refine RingHom.ext fun z => ?_ + induction z using DirectLimit.induction with + | _ Λ X => + simp only [RingHom.comp_apply, quasiLocalCovariance_mk] + exact N.ιLocal_algebraCongr _ _ + +/-- The covariance action sends the unit covariance to the identity: `β_1 = id`. -/ +@[simp] theorem quasiLocalCovariance_one : + (1 : N.Covariance).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by + rw [one_def, quasiLocalCovariance_id] + +/-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. -/ +theorem quasiLocalCovariance_mul (a b : N.Covariance) : + (a * b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by + rw [mul_def, quasiLocalCovariance_comp] + +/-! #### The covariance action as a `*`-automorphism -/ + +/-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ +theorem quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : + a.quasiLocalCovariance (c • z) = c • a.quasiLocalCovariance z := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [DirectLimit.smul_def, quasiLocalCovariance_mk, quasiLocalCovariance_mk, DirectLimit.smul_def, + map_smul] + rfl + +/-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` + is a `*`-isomorphism. -/ +theorem quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : + a.quasiLocalCovariance (star z) = star (a.quasiLocalCovariance z) := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [star_mk, quasiLocalCovariance_mk, quasiLocalCovariance_mk, star_mk, map_star] + rfl + +/-- The covariance action as a `*`-algebra automorphism of the algebra of local observables, with + the action of the inverse covariance `a⁻¹` as its inverse. -/ +noncomputable def quasiLocalCovarianceEquiv : + N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where + toFun := a.quasiLocalCovariance + invFun := a⁻¹.quasiLocalCovariance + left_inv z := by + rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, inv_mul_cancel, quasiLocalCovariance_one, + RingHom.id_apply] + right_inv z := by + rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, mul_inv_cancel, quasiLocalCovariance_one, + RingHom.id_apply] + map_mul' := map_mul a.quasiLocalCovariance + map_add' := map_add a.quasiLocalCovariance + map_smul' := a.quasiLocalCovariance_smul + map_star' := a.quasiLocalCovariance_star + +@[simp] theorem quasiLocalCovarianceEquiv_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalCovarianceEquiv z = a.quasiLocalCovariance z := rfl + +@[simp] theorem quasiLocalCovarianceEquiv_symm_apply (z : N.quasiLocalAlgebra) : + a.quasiLocalCovarianceEquiv.symm z = a⁻¹.quasiLocalCovariance z := rfl + +/-- A covariance of the net acts on the algebra of local observables by `*`-algebra automorphisms, + assembled as a group homomorphism into the `*`-automorphism group. -/ +noncomputable def quasiLocalCovarianceHom : + N.Covariance →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where + toFun a := a.quasiLocalCovarianceEquiv + map_one' := by + ext z + simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_one, RingHom.id_apply, + StarAlgEquiv.one_apply] + map_mul' a b := by + ext z + simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_mul, RingHom.comp_apply, + StarAlgEquiv.mul_apply] + +@[simp] theorem quasiLocalCovarianceHom_apply (z : N.quasiLocalAlgebra) : + quasiLocalCovarianceHom a z = a.quasiLocalCovariance z := rfl + +/-! #### The covariance automorphism of the quasi-local C⋆-algebra -/ + +section CStarCovariance + +variable [N.Faithful] + +/-- The covariance action is **isometric** on the algebra of local observables: each `β` is a + `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ +theorem quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : + ‖a.quasiLocalCovariance z‖ = ‖z‖ := by + induction z using DirectLimit.induction with + | _ Λ X => + rw [quasiLocalCovariance_mk, norm_mk, norm_mk] + exact StarAlgEquiv.norm_map _ X + +/-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is + an isometry), so it extends to the C⋆-completion. -/ +theorem quasiLocalCovarianceEquiv_uniformContinuous : + UniformContinuous a.quasiLocalCovarianceEquiv := + (AddMonoidHomClass.isometry_of_norm _ (fun z => by + rw [quasiLocalCovarianceEquiv_apply]; exact a.quasiLocalCovariance_norm z)).uniformContinuous + +/-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is + also an isometry). -/ +theorem quasiLocalCovarianceEquiv_symm_uniformContinuous : + UniformContinuous a.quasiLocalCovarianceEquiv.symm := by + have h : ∀ z, ‖a.quasiLocalCovarianceEquiv.symm z‖ = ‖z‖ := fun z => by + rw [quasiLocalCovarianceEquiv_symm_apply]; exact a⁻¹.quasiLocalCovariance_norm z + exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous + +/-- The covariance automorphism of the quasi-local C⋆-algebra: the continuous extension of + `quasiLocalCovarianceEquiv` to the completion. -/ +noncomputable def quasiLocalCStarCovarianceEquiv : + N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := + UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalCovarianceEquiv + a.quasiLocalCovarianceEquiv_uniformContinuous + a.quasiLocalCovarianceEquiv_symm_uniformContinuous + +@[simp] theorem quasiLocalCStarCovarianceEquiv_coe (z : N.quasiLocalAlgebra) : + a.quasiLocalCStarCovarianceEquiv (↑z : N.quasiLocalCStarAlgebra) = + ↑(a.quasiLocalCovariance z) := + UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z + +theorem quasiLocalCStarCovarianceEquiv_continuous : + Continuous (⇑a.quasiLocalCStarCovarianceEquiv) := + UniformSpace.Completion.continuous_map + +/-- A covariance of a faithful net acts on the quasi-local C⋆-algebra by `*`-automorphisms, + assembled as a group homomorphism into the `*`-automorphism group. -/ +noncomputable def quasiLocalCStarCovarianceHom : + N.Covariance →* (N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra) where + toFun a := a.quasiLocalCStarCovarianceEquiv + map_one' := by + refine StarAlgEquiv.ext fun z => ?_ + rw [StarAlgEquiv.one_apply] + refine UniformSpace.Completion.induction_on z + (isClosed_eq (1 : N.Covariance).quasiLocalCStarCovarianceEquiv_continuous + continuous_id) ?_ + intro w + simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_one, RingHom.id_apply] + map_mul' a b := by + refine StarAlgEquiv.ext fun z => ?_ + rw [StarAlgEquiv.mul_apply] + refine UniformSpace.Completion.induction_on z + (isClosed_eq (a * b).quasiLocalCStarCovarianceEquiv_continuous + (a.quasiLocalCStarCovarianceEquiv_continuous.comp + b.quasiLocalCStarCovarianceEquiv_continuous)) ?_ + intro w + simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_mul, RingHom.comp_apply] + +@[simp] theorem quasiLocalCStarCovarianceHom_apply + (z : N.quasiLocalCStarAlgebra) : + quasiLocalCStarCovarianceHom a z = a.quasiLocalCStarCovarianceEquiv z := rfl + +end CStarCovariance + +end Covariance + end LocalNet namespace SiteIndexSystem From 3656105ea18a739954d9bf6fc8f26acb070d67df Mon Sep 17 00:00:00 2001 From: suzuki Date: Fri, 26 Jun 2026 07:48:19 +0000 Subject: [PATCH 025/113] refactor(localnet): split abstract net layer from concrete matrix model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate the abstract Haag–Kastler net layer (namespace LocalNet) from the finite-dimensional matrix model (namespace SiteIndexSystem), which were mixed across files and names. - Abstract layer stays at LocalNet/ top level: Net (bundled structure), Covariance, and QuasiLocal (inductive limit, C*-completion, covariance action only). QuasiLocal no longer transitively pulls in Channel or the matrix norm. - Concrete matrix model moves under LocalNet/MatrixModel/: Basic -> SiteIndexSystem, Isotony, Locality, TensorDecomposition, LatticeCovariance -> Covariance, and a new Net carrying toLocalNet plus the quasi-local wrappers split out of QuasiLocal. - Update the two downstream importers (PartialTrace, PartialTraceOperator) and regenerate the QuantumSystem aggregate. Pure reorganization: no proof or statement changes; lake build is green. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 11 +- .../Algebra/LocalNet/Covariance.lean | 2 +- .../Covariance.lean} | 2 +- .../LocalNet/{ => MatrixModel}/Isotony.lean | 2 +- .../LocalNet/{ => MatrixModel}/Locality.lean | 2 +- .../Algebra/LocalNet/MatrixModel/Net.lean | 105 +++++++++++++++ .../SiteIndexSystem.lean} | 22 ++-- .../TensorDecomposition.lean | 2 +- QuantumSystem/Algebra/LocalNet/Net.lean | 13 +- .../Algebra/LocalNet/QuasiLocal.lean | 120 +++--------------- .../Analysis/Matrix/PartialTrace.lean | 2 +- .../Analysis/Matrix/PartialTraceOperator.lean | 2 +- 12 files changed, 157 insertions(+), 128 deletions(-) rename QuantumSystem/Algebra/LocalNet/{LatticeCovariance.lean => MatrixModel/Covariance.lean} (99%) rename QuantumSystem/Algebra/LocalNet/{ => MatrixModel}/Isotony.lean (99%) rename QuantumSystem/Algebra/LocalNet/{ => MatrixModel}/Locality.lean (99%) create mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean rename QuantumSystem/Algebra/LocalNet/{Basic.lean => MatrixModel/SiteIndexSystem.lean} (93%) rename QuantumSystem/Algebra/LocalNet/{ => MatrixModel}/TensorDecomposition.lean (99%) diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 6f9ce83..e043c4f 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -17,14 +17,15 @@ public import QuantumSystem.Algebra.CStarAlgebra.Representation.UnitaryEquiv public import QuantumSystem.Algebra.CStarAlgebra.State public import QuantumSystem.Algebra.CStarAlgebra.State.Continuity public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful -public import QuantumSystem.Algebra.LocalNet.Basic public import QuantumSystem.Algebra.LocalNet.Covariance -public import QuantumSystem.Algebra.LocalNet.Isotony -public import QuantumSystem.Algebra.LocalNet.LatticeCovariance -public import QuantumSystem.Algebra.LocalNet.Locality +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Covariance +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Locality +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Net +public import QuantumSystem.Algebra.LocalNet.MatrixModel.SiteIndexSystem +public import QuantumSystem.Algebra.LocalNet.MatrixModel.TensorDecomposition public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocal -public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index fb05170..1aeef16 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -15,7 +15,7 @@ This file isolates the abstract covariance *data* and its group structure. Its * quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism `quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local C⋆-algebra — is built in `LocalNet.QuasiLocal`. The concrete covariance of the matrix net generated -by a `SiteIndexSystem`, together with its inherited action, lives in `LocalNet.LatticeCovariance`. +by a `SiteIndexSystem`, together with its inherited action, lives in `LocalNet.MatrixModel.Covariance`. -/ @[expose] public section diff --git a/QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean similarity index 99% rename from QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean rename to QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean index cf5ee79..9fe1271 100644 --- a/QuantumSystem/Algebra/LocalNet/LatticeCovariance.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Net /-! # Covariance of the local net generated by a lattice system diff --git a/QuantumSystem/Algebra/LocalNet/Isotony.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean similarity index 99% rename from QuantumSystem/Algebra/LocalNet/Isotony.lean rename to QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean index 8368052..fb55b09 100644 --- a/QuantumSystem/Algebra/LocalNet/Isotony.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet.Basic +public import QuantumSystem.Algebra.LocalNet.MatrixModel.SiteIndexSystem /-! # Isotony embedding of the local net diff --git a/QuantumSystem/Algebra/LocalNet/Locality.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean similarity index 99% rename from QuantumSystem/Algebra/LocalNet/Locality.lean rename to QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean index c973627..b80e904 100644 --- a/QuantumSystem/Algebra/LocalNet/Locality.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony /-! # Locality (Einstein causality) of the local net diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean new file mode 100644 index 0000000..d8efdee --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean @@ -0,0 +1,105 @@ +module + +public import Mathlib.Analysis.CStarAlgebra.Matrix +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Locality +public import QuantumSystem.Algebra.LocalNet.QuasiLocal + +/-! +# The local net generated by a site-index system + +A `SiteIndexSystem` on a (possibly infinite) lattice of sites — the data of a finite local +index type at each site — generates a genuine **local net of C⋆-algebras** (`LocalNet`): the +assignment `Λ ↦ 𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` to each finite region, with the isotony embeddings +`includeAlgebra (h : Λ ⊆ Λ')` (the inclusion `A ↦ A ⊗ I` of `LocalNet.MatrixModel.Isotony`), +functorial (`includeAlgebra_trans_apply`, `includeAlgebra_refl_apply`) and local +(`includeAlgebra_commute_of_disjoint`). + +* `instCStarAlgebraLocal` makes each finite-region matrix algebra a C⋆-algebra under the + `L2Operator` norm; this discharges the C⋆-structure required by `LocalNet`. +* `SiteIndexSystem.toLocalNet` packages the matrix algebras and isotony embeddings into a + `LocalNet`. The **algebra of local observables** and the **quasi-local C⋆-algebra** are then + inherited from the abstract net (`LocalNet.quasiLocalAlgebra`, `LocalNet.quasiLocalCStarAlgebra`). +* When each site has a non-empty local index type the embeddings are injective, so the generated + net is `LocalNet.Faithful` and its quasi-local C⋆-algebra is the AQFT quasi-local algebra + `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2). + +The site-index-system-level abbreviations `quasiLocalAlgebra` / `ιLocal` / `quasiLocalCStarAlgebra` +below are thin wrappers around the corresponding `LocalNet` constructions on `toLocalNet`. The +concrete covariance of this net and its inherited action live in `LocalNet.MatrixModel.Covariance`. +-/ + +@[expose] public section + +namespace SiteIndexSystem + +open scoped Matrix.Norms.L2Operator + +variable (S : SiteIndexSystem) + +/-- Each finite-region matrix algebra `𝔄(Λ) = Matrix (regionIdx Λ) (regionIdx Λ) ℂ` is a + (complex) C⋆-algebra under the `L2Operator` norm. Stated for `localAlgebra` so the choice of + the `L2Operator` norm does not leak to arbitrary matrices. -/ +noncomputable instance instCStarAlgebraLocal (Λ : Finset S.sites) : + CStarAlgebra (S.localAlgebra Λ) where + +/-- The **local net generated by the lattice system**: the assignment of matrix algebras to + finite regions, with the isotony embeddings as connecting maps. This realises the abstract + Haag–Kastler net `LocalNet` for the finite-dimensional matrix model. -/ +noncomputable def toLocalNet : LocalNet S.sites where + algebra := S.localAlgebra + incl h := S.includeAlgebra h + incl_refl x := S.includeAlgebra_refl_apply x + incl_trans h₁₂ h₂₃ x := S.includeAlgebra_trans_apply h₁₂ h₂₃ x + locality h₁ h₂ hd x y := S.includeAlgebra_commute_of_disjoint h₁ h₂ hd x y + +@[simp] theorem toLocalNet_algebra (Λ : Finset S.sites) : + S.toLocalNet.algebra Λ = S.localAlgebra Λ := rfl + +@[simp] theorem toLocalNet_incl {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') : + S.toLocalNet.incl h = S.includeAlgebra h := rfl + +/-- The generated net is **faithful**: if each site has a non-empty local index type, the complementary + region indices are non-empty, so the isotony embeddings are injective. -/ +instance toLocalNet_faithful [∀ s, Nonempty (S.localIdx s)] : S.toLocalNet.Faithful where + incl_injective h := S.includeAlgebra_injective h + +/-! ### Lattice-system-level quasi-local algebra + +Thin wrappers exposing the `LocalNet` constructions on `toLocalNet` directly on the lattice system. -/ + +/-- The **algebra of local observables** of the lattice system: the algebraic inductive limit of the + finite-region matrix algebras (inherited from `LocalNet.quasiLocalAlgebra` on `toLocalNet`). -/ +noncomputable abbrev quasiLocalAlgebra : Type _ := S.toLocalNet.quasiLocalAlgebra + +/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local + observables (the cocone of the inductive limit). -/ +noncomputable def ιLocal (Λ : Finset S.sites) : + S.localAlgebra Λ →+* S.quasiLocalAlgebra := + S.toLocalNet.ιLocal Λ + +/-- Compatibility of the cocone with the isotony embeddings. -/ +@[simp] theorem ιLocal_includeAlgebra {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') + (X : S.localAlgebra Λ) : + S.ιLocal Λ' (S.includeAlgebra h X) = S.ιLocal Λ X := + S.toLocalNet.ιLocal_incl h X + +/-- **Exhaustion**: every element of the algebra of local observables comes from some finite + region. -/ +theorem exists_ιLocal (z : S.quasiLocalAlgebra) : + ∃ (Λ : Finset S.sites) (X : S.localAlgebra Λ), z = S.ιLocal Λ X := + S.toLocalNet.exists_ιLocal z + +/-- **Locality**: observables localised in disjoint regions commute inside the algebra of local + observables. -/ +theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset S.sites} (hd : Disjoint Λ₁ Λ₂) + (X : S.localAlgebra Λ₁) (Y : S.localAlgebra Λ₂) : + Commute (S.ιLocal Λ₁ X) (S.ιLocal Λ₂ Y) := + S.toLocalNet.ιLocal_commute_of_disjoint hd X Y + +/-- The **quasi-local C⋆-algebra** of the lattice system (assuming non-empty local dimensions): the + completion of the algebra of local observables, i.e. the AQFT quasi-local algebra + `𝔄 = ‾⋃_Λ 𝔄(Λ)`. -/ +noncomputable abbrev quasiLocalCStarAlgebra [∀ s, Nonempty (S.localIdx s)] : Type _ := + S.toLocalNet.quasiLocalCStarAlgebra + +end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Basic.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean similarity index 93% rename from QuantumSystem/Algebra/LocalNet/Basic.lean rename to QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean index ea475f1..0765b9d 100644 --- a/QuantumSystem/Algebra/LocalNet/Basic.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean @@ -3,12 +3,14 @@ module public import QuantumSystem.Channel /-! -# Local Net of Matrix Algebras — basic data +# Site-index system: data of a local net of matrix algebras -This file carries the **data** of a local net of matrix algebras and the region-index -combinatorics on which the AQFT net properties are built. An AQFT system assigns to each -region `Λ` an algebra `𝔄(Λ)` of observables; for finite-dimensional site-index -systems this specialises to: +This file carries the **data** of the finite-dimensional matrix model of a local net — the +`SiteIndexSystem` — and the region-index combinatorics on which the concrete AQFT net properties +are built. It is the foundation of the *concrete* layer (`LocalNet.MatrixModel`), which instances +the abstract Haag–Kastler net `LocalNet` (`LocalNet.Net`). An AQFT system assigns to each region +`Λ` an algebra `𝔄(Λ)` of observables; for finite-dimensional site-index systems this specialises +to: - a **set of sites** `L` (an arbitrary type with `DecidableEq`; no order/geometric structure), - a finite local index type `ℂ^{n_x}` at each site `x`, @@ -21,10 +23,12 @@ equivalence `combineIdx` realising `regionIdx Λ_total ≃ regionIdx Λ × regio the cardinality factorisation, the transport `regionIdxCongr`, and the bipartite and tripartite region factorisation equivalences (`regionIdxPairEquiv`, `regionIdxTripleEquiv`). -The net **properties** built on this data live in sibling modules: -`LocalNet.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `LocalNet.Locality` -(disjoint regions commute), `LocalNet.QuasiLocal` (quasi-local C⋆-algebra), `LocalNet.Covariance` -(covariance data and action). Restriction / partial trace lives in `Analysis/Matrix/PartialTrace.lean`. +The net **properties** built on this data live in sibling modules of `LocalNet.MatrixModel`: +`MatrixModel.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `MatrixModel.Locality` +(disjoint regions commute), `MatrixModel.Net` (the generated `LocalNet` and quasi-local wrappers), +`MatrixModel.Covariance` (concrete covariance data and action). The abstract net axioms and the +quasi-local C⋆-algebra they generate live in `LocalNet.Net` / `LocalNet.QuasiLocal`. Restriction / +partial trace lives in `Analysis/Matrix/PartialTrace.lean`. ## References diff --git a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean similarity index 99% rename from QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean rename to QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean index 4342206..48c97f9 100644 --- a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct public import QuantumSystem.ForMathlib.LinearAlgebra.Trace diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index a3b3d9d..8d12d81 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -1,8 +1,9 @@ module -public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar -public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit -public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion + + +public import Mathlib.Analysis.CStarAlgebra.Classes +public import Mathlib.Order.DirectedInverseSystem /-! # Local nets of C⋆-algebras @@ -10,9 +11,9 @@ public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion This file contains the abstract **local net** data: finite regions are assigned local C⋆-algebras, with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms. -The quasi-local algebra built from a net lives in `LocalNet.QuasiLocal`; covariance actions live in -`LocalNet.Covariance`. The finite-dimensional matrix net generated by a `SiteIndexSystem` is also -packaged in `LocalNet.QuasiLocal`. +The quasi-local algebra built from a net lives in `LocalNet.QuasiLocal`; covariance data and its +action live in `LocalNet.Covariance` / `LocalNet.QuasiLocal`. The finite-dimensional matrix net +generated by a `SiteIndexSystem` is packaged in `LocalNet.MatrixModel.Net`. -/ @[expose] public section diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean index 179c1a3..df6d5f9 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean @@ -1,39 +1,31 @@ module -public import Mathlib.Analysis.CStarAlgebra.Matrix public import QuantumSystem.Algebra.LocalNet.Covariance -public import QuantumSystem.Algebra.LocalNet.Locality -public import QuantumSystem.Algebra.LocalNet.Net +public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar +public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit +public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion /-! -# The local net generated by a lattice system - -A `SiteIndexSystem` on a (possibly infinite) lattice of sites — the data of a finite local -index type at each site — generates a genuine **local net of C⋆-algebras** (`LocalNet`): the -assignment `Λ ↦ 𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` to each finite region, with the isotony embeddings -`includeAlgebra (h : Λ ⊆ Λ')` (the inclusion `A ↦ A ⊗ I` of `LocalNet.Isotony`), functorial -(`includeAlgebra_trans_apply`, `includeAlgebra_refl_apply`) and local -(`includeAlgebra_commute_of_disjoint`). - -* `instCStarAlgebraLocal` makes each finite-region matrix algebra a C⋆-algebra under the - `L2Operator` norm; this discharges the C⋆-structure required by `LocalNet`. -* `SiteIndexSystem.toLocalNet` packages the matrix algebras and isotony embeddings into a - `LocalNet`. The **algebra of local observables** and the **quasi-local C⋆-algebra** are then - inherited from the abstract net (`LocalNet.quasiLocalAlgebra`, `LocalNet.quasiLocalCStarAlgebra`). -* When each site has a non-empty local index type the embeddings are injective, so the generated - net is `LocalNet.Faithful` and its quasi-local C⋆-algebra is the AQFT quasi-local algebra - `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2). - -The lattice-system-level abbreviations `quasiLocalAlgebra` / `ιLocal` / `quasiLocalCStarAlgebra` -below are thin wrappers around the corresponding `LocalNet` constructions on `toLocalNet`. +# The quasi-local algebra of a local net + +The **algebra of local observables** and the **quasi-local C⋆-algebra** of an abstract local net +`LocalNet`. These constructions apply to *any* local net; the concrete finite-dimensional matrix +model that instantiates them lives in `LocalNet.MatrixModel.Net`. + +* `LocalNet.quasiLocalAlgebra` is the algebraic inductive limit `‾⋃_Λ 𝔄(Λ)` of the local algebras + along the isotony embeddings, with cocone `ιLocal`, exhaustion (`exists_ιLocal`) and locality + (`ιLocal_commute_of_disjoint`). +* For a `Faithful` net the connecting maps are isometric, so the algebra of local observables + carries a C⋆-norm whose completion `LocalNet.quasiLocalCStarAlgebra` is the AQFT quasi-local + algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2), with dense local + embeddings `ιLocalCStar`. A `LocalNet.Covariance` (defined in `LocalNet.Covariance`) acts on these algebras: its per-region `*`-isomorphisms assemble into a `*`-endomorphism `quasiLocalCovariance` of the algebra of local observables, which is functorial, `ℂ`-linear and `*`-preserving — hence a `*`-automorphism `quasiLocalCovarianceEquiv`, assembled into a group homomorphism `quasiLocalCovarianceHom`. For a `Faithful` net it is isometric and extends to a `*`-automorphism `quasiLocalCStarCovarianceEquiv` of -the quasi-local C⋆-algebra. The concrete `SiteIndexSystem.Covariance` and its inherited action are -built on top of these constructions in `LocalNet.LatticeCovariance`. +the quasi-local C⋆-algebra. -/ @[expose] public section @@ -42,10 +34,10 @@ namespace LocalNet variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) -/-! ### Abstract quasi-local algebra +/-! ### Algebra of local observables These constructions apply to any abstract local net. The concrete `SiteIndexSystem` wrappers are -provided later in this file after `SiteIndexSystem.toLocalNet` is built. +built on `SiteIndexSystem.toLocalNet` in `LocalNet.MatrixModel.Net`. -/ /-- The **algebra of local observables** of the net: the algebraic inductive limit of the local @@ -351,77 +343,3 @@ end CStarCovariance end Covariance end LocalNet - -namespace SiteIndexSystem - -open scoped Matrix.Norms.L2Operator - -variable (S : SiteIndexSystem) - -/-- Each finite-region matrix algebra `𝔄(Λ) = Matrix (regionIdx Λ) (regionIdx Λ) ℂ` is a - (complex) C⋆-algebra under the `L2Operator` norm. Stated for `localAlgebra` so the choice of - the `L2Operator` norm does not leak to arbitrary matrices. -/ -noncomputable instance instCStarAlgebraLocal (Λ : Finset S.sites) : - CStarAlgebra (S.localAlgebra Λ) where - -/-- The **local net generated by the lattice system**: the assignment of matrix algebras to - finite regions, with the isotony embeddings as connecting maps. This realises the abstract - Haag–Kastler net `LocalNet` for the finite-dimensional matrix model. -/ -noncomputable def toLocalNet : LocalNet S.sites where - algebra := S.localAlgebra - incl h := S.includeAlgebra h - incl_refl x := S.includeAlgebra_refl_apply x - incl_trans h₁₂ h₂₃ x := S.includeAlgebra_trans_apply h₁₂ h₂₃ x - locality h₁ h₂ hd x y := S.includeAlgebra_commute_of_disjoint h₁ h₂ hd x y - -@[simp] theorem toLocalNet_algebra (Λ : Finset S.sites) : - S.toLocalNet.algebra Λ = S.localAlgebra Λ := rfl - -@[simp] theorem toLocalNet_incl {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') : - S.toLocalNet.incl h = S.includeAlgebra h := rfl - -/-- The generated net is **faithful**: if each site has a non-empty local index type, the complementary - region indices are non-empty, so the isotony embeddings are injective. -/ -instance toLocalNet_faithful [∀ s, Nonempty (S.localIdx s)] : S.toLocalNet.Faithful where - incl_injective h := S.includeAlgebra_injective h - -/-! ### Lattice-system-level quasi-local algebra - -Thin wrappers exposing the `LocalNet` constructions on `toLocalNet` directly on the lattice system. -/ - -/-- The **algebra of local observables** of the lattice system: the algebraic inductive limit of the - finite-region matrix algebras (inherited from `LocalNet.quasiLocalAlgebra` on `toLocalNet`). -/ -noncomputable abbrev quasiLocalAlgebra : Type _ := S.toLocalNet.quasiLocalAlgebra - -/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local - observables (the cocone of the inductive limit). -/ -noncomputable def ιLocal (Λ : Finset S.sites) : - S.localAlgebra Λ →+* S.quasiLocalAlgebra := - S.toLocalNet.ιLocal Λ - -/-- Compatibility of the cocone with the isotony embeddings. -/ -@[simp] theorem ιLocal_includeAlgebra {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') - (X : S.localAlgebra Λ) : - S.ιLocal Λ' (S.includeAlgebra h X) = S.ιLocal Λ X := - S.toLocalNet.ιLocal_incl h X - -/-- **Exhaustion**: every element of the algebra of local observables comes from some finite - region. -/ -theorem exists_ιLocal (z : S.quasiLocalAlgebra) : - ∃ (Λ : Finset S.sites) (X : S.localAlgebra Λ), z = S.ιLocal Λ X := - S.toLocalNet.exists_ιLocal z - -/-- **Locality**: observables localised in disjoint regions commute inside the algebra of local - observables. -/ -theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset S.sites} (hd : Disjoint Λ₁ Λ₂) - (X : S.localAlgebra Λ₁) (Y : S.localAlgebra Λ₂) : - Commute (S.ιLocal Λ₁ X) (S.ιLocal Λ₂ Y) := - S.toLocalNet.ιLocal_commute_of_disjoint hd X Y - -/-- The **quasi-local C⋆-algebra** of the lattice system (assuming non-empty local dimensions): the - completion of the algebra of local observables, i.e. the AQFT quasi-local algebra - `𝔄 = ‾⋃_Λ 𝔄(Λ)`. -/ -noncomputable abbrev quasiLocalCStarAlgebra [∀ s, Nonempty (S.localIdx s)] : Type _ := - S.toLocalNet.quasiLocalCStarAlgebra - -end SiteIndexSystem diff --git a/QuantumSystem/Analysis/Matrix/PartialTrace.lean b/QuantumSystem/Analysis/Matrix/PartialTrace.lean index 87b6aa4..ce46e05 100644 --- a/QuantumSystem/Analysis/Matrix/PartialTrace.lean +++ b/QuantumSystem/Analysis/Matrix/PartialTrace.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet.Isotony +public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace /-! diff --git a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean index a61d2eb..b457b8f 100644 --- a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean +++ b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Algebra.LocalNet.TensorDecomposition +public import QuantumSystem.Algebra.LocalNet.MatrixModel.TensorDecomposition public import QuantumSystem.Analysis.Matrix.PartialTrace public import Mathlib.Analysis.InnerProductSpace.Trace From 6c96b289391918e81b2e4174b1cee208d7f7a9e1 Mon Sep 17 00:00:00 2001 From: suzuki Date: Fri, 26 Jun 2026 08:20:51 +0000 Subject: [PATCH 026/113] refactor(localnet): rename QuasiLocal module to QuasiLocalAlgebra Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 2 +- QuantumSystem/Algebra/LocalNet/Covariance.lean | 5 +++-- QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean | 2 +- .../Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean | 4 ++-- QuantumSystem/Algebra/LocalNet/Net.lean | 8 ++++---- .../LocalNet/{QuasiLocal.lean => QuasiLocalAlgebra.lean} | 0 6 files changed, 11 insertions(+), 10 deletions(-) rename QuantumSystem/Algebra/LocalNet/{QuasiLocal.lean => QuasiLocalAlgebra.lean} (100%) diff --git a/QuantumSystem.lean b/QuantumSystem.lean index e043c4f..303a46c 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -25,7 +25,7 @@ public import QuantumSystem.Algebra.LocalNet.MatrixModel.Net public import QuantumSystem.Algebra.LocalNet.MatrixModel.SiteIndexSystem public import QuantumSystem.Algebra.LocalNet.MatrixModel.TensorDecomposition public import QuantumSystem.Algebra.LocalNet.Net -public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 1aeef16..176b476 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -14,8 +14,9 @@ covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp` This file isolates the abstract covariance *data* and its group structure. Its *action* on the quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism `quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local -C⋆-algebra — is built in `LocalNet.QuasiLocal`. The concrete covariance of the matrix net generated -by a `SiteIndexSystem`, together with its inherited action, lives in `LocalNet.MatrixModel.Covariance`. +C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. The concrete covariance of the matrix net +generated by a `SiteIndexSystem`, together with its inherited action, lives in +`LocalNet.MatrixModel.Covariance`. -/ @[expose] public section diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean index d8efdee..7ca8ee5 100644 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean @@ -2,7 +2,7 @@ module public import Mathlib.Analysis.CStarAlgebra.Matrix public import QuantumSystem.Algebra.LocalNet.MatrixModel.Locality -public import QuantumSystem.Algebra.LocalNet.QuasiLocal +public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra /-! # The local net generated by a site-index system diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean index 0765b9d..5b4e3bf 100644 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean +++ b/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean @@ -27,8 +27,8 @@ The net **properties** built on this data live in sibling modules of `LocalNet.M `MatrixModel.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `MatrixModel.Locality` (disjoint regions commute), `MatrixModel.Net` (the generated `LocalNet` and quasi-local wrappers), `MatrixModel.Covariance` (concrete covariance data and action). The abstract net axioms and the -quasi-local C⋆-algebra they generate live in `LocalNet.Net` / `LocalNet.QuasiLocal`. Restriction / -partial trace lives in `Analysis/Matrix/PartialTrace.lean`. +quasi-local C⋆-algebra they generate live in `LocalNet.Net` / `LocalNet.QuasiLocalAlgebra`. +Restriction / partial trace lives in `Analysis/Matrix/PartialTrace.lean`. ## References diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 8d12d81..17ba3a9 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -11,9 +11,9 @@ public import Mathlib.Order.DirectedInverseSystem This file contains the abstract **local net** data: finite regions are assigned local C⋆-algebras, with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms. -The quasi-local algebra built from a net lives in `LocalNet.QuasiLocal`; covariance data and its -action live in `LocalNet.Covariance` / `LocalNet.QuasiLocal`. The finite-dimensional matrix net -generated by a `SiteIndexSystem` is packaged in `LocalNet.MatrixModel.Net`. +The quasi-local algebra built from a net lives in `LocalNet.QuasiLocalAlgebra`; covariance data and +its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. The finite-dimensional +matrix net generated by a `SiteIndexSystem` is packaged in `LocalNet.MatrixModel.Net`. -/ @[expose] public section @@ -60,7 +60,7 @@ instance directedSystem : A net is *faithful* when its isotony embeddings are injective (the standard AQFT non-degeneracy condition). The quasi-local C⋆-norm built from this hypothesis lives in -`LocalNet.QuasiLocal`. +`LocalNet.QuasiLocalAlgebra`. -/ /-- A local net is **faithful** when all its isotony embeddings are injective. In the standard diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocal.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean similarity index 100% rename from QuantumSystem/Algebra/LocalNet/QuasiLocal.lean rename to QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean From 3f0f2b8f7c35ab865c57f65d3b979c844e2392b0 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 17:42:38 +0000 Subject: [PATCH 027/113] refactor(localnet): replace matrix model with representation-free split net Remove the MatrixModel/SiteIndexSystem layer and the matrix partial-trace bridge, and build the quantum-information stack directly on the abstract split net: - drop QuantumSystem/Algebra/LocalNet/MatrixModel/* and the old Analysis/Matrix partial-trace files plus StrongSubadditivityLocalNet - add abstract Split tensor decomposition (Algebra/LocalNet/TensorDecomposition) - add the representation-free Split* entropy stack: SplitTrace, SplitEntropy, SplitRelativeEntropy, SplitTransport, SplitSSA - merge TensorCommutant into ForMathlib/LinearAlgebra/Trace so ForMathlib imports only Mathlib Co-Authored-By: Claude Opus 4.8 --- .gitignore | 2 + QuantumSystem.lean | 17 +- .../Algebra/LocalNet/Covariance.lean | 4 +- .../LocalNet/MatrixModel/Covariance.lean | 169 ----- .../Algebra/LocalNet/MatrixModel/Isotony.lean | 287 ------- .../LocalNet/MatrixModel/Locality.lean | 127 ---- .../Algebra/LocalNet/MatrixModel/Net.lean | 105 --- .../LocalNet/MatrixModel/SiteIndexSystem.lean | 334 -------- .../MatrixModel/TensorDecomposition.lean | 118 --- QuantumSystem/Algebra/LocalNet/Net.lean | 6 +- .../Algebra/LocalNet/QuasiLocalAlgebra.lean | 6 +- .../Algebra/LocalNet/TensorDecomposition.lean | 142 ++++ .../Analysis/Channel/PartialTrace.lean | 6 +- .../Analysis/Entropy/KroneckerProduct.lean | 7 +- .../Analysis/Entropy/MutualInfoProduct.lean | 5 +- .../Analysis/Entropy/Regularize.lean | 89 --- .../Analysis/Entropy/SplitEntropy.lean | 45 ++ .../Entropy/SplitRelativeEntropy.lean | 101 +++ QuantumSystem/Analysis/Entropy/SplitSSA.lean | 713 ++++++++++++++++++ .../Analysis/Entropy/SplitTrace.lean | 124 +++ .../Analysis/Entropy/SplitTransport.lean | 374 +++++++++ .../Entropy/StrongSubadditivityLocalNet.lean | 526 ------------- .../Entropy/StrongSubadditivityProduct.lean | 12 +- .../Matrix/KroneckerPartialTraceBridge.lean | 84 --- .../Analysis/Matrix/PartialTrace.lean | 439 ----------- .../Analysis/Matrix/PartialTraceOperator.lean | 92 --- .../ForMathlib/LinearAlgebra/Trace.lean | 191 ++++- QuantumSystem/Notation.lean | 6 - 28 files changed, 1714 insertions(+), 2417 deletions(-) delete mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean delete mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean delete mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean delete mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean delete mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean delete mode 100644 QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean create mode 100644 QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean delete mode 100644 QuantumSystem/Analysis/Entropy/Regularize.lean create mode 100644 QuantumSystem/Analysis/Entropy/SplitEntropy.lean create mode 100644 QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean create mode 100644 QuantumSystem/Analysis/Entropy/SplitSSA.lean create mode 100644 QuantumSystem/Analysis/Entropy/SplitTrace.lean create mode 100644 QuantumSystem/Analysis/Entropy/SplitTransport.lean delete mode 100644 QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean delete mode 100644 QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean delete mode 100644 QuantumSystem/Analysis/Matrix/PartialTrace.lean delete mode 100644 QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean diff --git a/.gitignore b/.gitignore index b88588e..015090f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ skill-creator-tests/ # Ignore until https://github.com/microsoft/vscode-remote-release/issues/11616 is fixed. devcontainer-lock.json + +worktrees/ diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 303a46c..231c7df 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -18,32 +18,27 @@ public import QuantumSystem.Algebra.CStarAlgebra.State public import QuantumSystem.Algebra.CStarAlgebra.State.Continuity public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful public import QuantumSystem.Algebra.LocalNet.Covariance -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Covariance -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Locality -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Net -public import QuantumSystem.Algebra.LocalNet.MatrixModel.SiteIndexSystem -public import QuantumSystem.Algebra.LocalNet.MatrixModel.TensorDecomposition public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra +public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal public import QuantumSystem.Analysis.Channel.PartialTrace public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.MutualInfoProduct -public import QuantumSystem.Analysis.Entropy.Regularize public import QuantumSystem.Analysis.Entropy.RelativeEntropy -public import QuantumSystem.Analysis.Entropy.StrongSubadditivityLocalNet +public import QuantumSystem.Analysis.Entropy.SplitEntropy +public import QuantumSystem.Analysis.Entropy.SplitRelativeEntropy +public import QuantumSystem.Analysis.Entropy.SplitSSA +public import QuantumSystem.Analysis.Entropy.SplitTrace +public import QuantumSystem.Analysis.Entropy.SplitTransport public import QuantumSystem.Analysis.Entropy.StrongSubadditivityProduct public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy public import QuantumSystem.Analysis.Matrix.Effros public import QuantumSystem.Analysis.Matrix.HermitianFunctionalCalculus -public import QuantumSystem.Analysis.Matrix.KroneckerPartialTraceBridge public import QuantumSystem.Analysis.Matrix.LiebConcavity public import QuantumSystem.Analysis.Matrix.Order -public import QuantumSystem.Analysis.Matrix.PartialTrace -public import QuantumSystem.Analysis.Matrix.PartialTraceOperator public import QuantumSystem.Analysis.Matrix.Pinching public import QuantumSystem.Analysis.Matrix.PosDef public import QuantumSystem.Channel diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 176b476..9f7ed80 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -14,9 +14,7 @@ covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp` This file isolates the abstract covariance *data* and its group structure. Its *action* on the quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism `quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local -C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. The concrete covariance of the matrix net -generated by a `SiteIndexSystem`, together with its inherited action, lives in -`LocalNet.MatrixModel.Covariance`. +C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. -/ @[expose] public section diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean deleted file mode 100644 index 9fe1271..0000000 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/Covariance.lean +++ /dev/null @@ -1,169 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Net - -/-! -# Covariance of the local net generated by a lattice system - -A **covariance** of a `SiteIndexSystem` is a permutation `σ` of the sites together with, for each -site, a dimension-matching equivalence `localIdx s ≃ localIdx (σ s)` of the local index types. Such -data reindexes the finite-region matrix algebras and so induces a `*`-isomorphism -`β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)` (`localCovariance`), natural with respect to the isotony embeddings -(`localCovariance_includeAlgebra`) — the AQFT covariance axiom `β_a(𝔄(Λ)) = 𝔄(a Λ)` for the -finite-dimensional matrix model. - -These per-region `*`-isomorphisms assemble a covariance `toLocalNetCovariance` of the generated -abstract net `toLocalNet`, exhibiting the concrete covariance as an instance of the abstract -`LocalNet.Covariance`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local -observables is therefore inherited from the net-level `LocalNet.Covariance.quasiLocalCovariance`, -together with the `*`-automorphism and C⋆-completion structure built there. --/ - -@[expose] public section - -namespace SiteIndexSystem - -/-- Pointwise value of the complement projection of `combineIdx.symm` (holds by `rfl`). -/ -@[simp] theorem combineIdx_symm_snd_apply {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) (f : L.regionIdx Λ_total) (w : ↥(Λ_total \ Λ)) : - ((L.combineIdx h).symm f).2 w = f ⟨w.val, (Finset.mem_sdiff.mp w.property).1⟩ := rfl - -/-- A covariance datum for a site-index system: a site permutation together with - dimension-matching equivalences on the local index types. -/ -structure Covariance (L : SiteIndexSystem) where - /-- The underlying permutation of the sites. -/ - σ : L.sites ≃ L.sites - /-- Dimension-matching equivalence of the local index type at each site. -/ - idx : ∀ s, L.localIdx s ≃ L.localIdx (σ s) - -namespace Covariance - -variable {L : SiteIndexSystem} (a : L.Covariance) - -/-- The image of a region under a covariance. -/ -def region (Λ : Finset L.sites) : Finset L.sites := Λ.map a.σ.toEmbedding - -variable (L) in -/-- The identity covariance. -/ -def id : L.Covariance where - σ := Equiv.refl _ - idx _ := Equiv.refl _ - -/-- Composition of covariances: apply `b`, then `a`. The per-site equivalences compose, with the - intermediate site type aligning definitionally. -/ -def comp (a b : L.Covariance) : L.Covariance where - σ := b.σ.trans a.σ - idx s := (b.idx s).trans (a.idx (b.σ s)) - -@[simp] theorem region_id (Λ : Finset L.sites) : (Covariance.id L).region Λ = Λ := by - simp [region, Covariance.id] - -@[simp] theorem region_comp (a b : L.Covariance) (Λ : Finset L.sites) : - (a.comp b).region Λ = a.region (b.region Λ) := by - simp [region, comp, Finset.map_map, Equiv.trans_toEmbedding] - -/-- Equivalence of region index types induced by the site permutation and the per-site dimension - equivalences. -/ -def regionIdxEquiv (Λ : Finset L.sites) : - L.regionIdx Λ ≃ L.regionIdx (a.region Λ) := - Equiv.piCongr - (Equiv.subtypeEquiv a.σ (fun _ => (Finset.mem_map' a.σ.toEmbedding).symm)) - (fun s => a.idx s.val) - -/-- The **covariance `*`-isomorphism** `β_a : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(a Λ)`, obtained by reindexing the - matrix algebra along `regionIdxEquiv`. Realises `β_a(𝔄(Λ)) = 𝔄(a Λ)`. -/ -noncomputable def localCovariance (Λ : Finset L.sites) : - L.localAlgebra Λ ≃⋆ₐ[ℂ] L.localAlgebra (a.region Λ) := - StarAlgEquiv.ofAlgEquiv (Matrix.reindexAlgEquiv ℂ ℂ (a.regionIdxEquiv Λ)) - (fun X => by - simp only [Matrix.reindexAlgEquiv_apply, Matrix.star_eq_conjTranspose, - Matrix.conjTranspose_reindex]) - -@[simp] theorem localCovariance_apply (Λ : Finset L.sites) (X : L.localAlgebra Λ) : - a.localCovariance Λ X = Matrix.reindex (a.regionIdxEquiv Λ) (a.regionIdxEquiv Λ) X := - rfl - -/-- The `Λ`-coordinate of decomposing a transported index equals the corresponding transported - `aΛ`-coordinate: `regionIdxEquiv` commutes with the isotony split `combineIdx`. Holds - definitionally. -/ -private theorem regionIdxEquiv_symm_combineIdx_fst {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') - (t : L.regionIdx (a.region Λ')) : - ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm t)).1 = - (a.regionIdxEquiv Λ).symm ((L.combineIdx (Finset.map_subset_map.mpr h)).symm t).1 := by - funext u - rfl - -/-- **Covariance / naturality**: the covariance `*`-isomorphism intertwines the isotony - embeddings, so `β_a` is an automorphism of the *net* — `β_a(𝔄(Λ)) = 𝔄(a Λ)` compatibly with - inclusions (Naaijkens 2012 §3.2 covariance axiom). -/ -theorem localCovariance_includeAlgebra {Λ Λ' : Finset L.sites} (h : Λ ⊆ Λ') - (X : L.localAlgebra Λ) : - a.localCovariance Λ' (L.includeAlgebra h X) = - L.includeAlgebra (Finset.map_subset_map.mpr h) (a.localCovariance Λ X) := by - ext s s' - simp only [localCovariance_apply, Matrix.reindex_apply, Matrix.submatrix_apply, - includeAlgebra_apply] - rw [a.regionIdxEquiv_symm_combineIdx_fst h s, a.regionIdxEquiv_symm_combineIdx_fst h s'] - have key2 : (((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s)).2 = - ((L.combineIdx h).symm ((a.regionIdxEquiv Λ').symm s')).2) - ↔ (((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = - ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2) := by - constructor - · intro H - funext v - obtain ⟨vv, hvv⟩ := v - have hv := Finset.mem_sdiff.mp hvv - have hΛ' : a.σ.symm vv ∈ Λ' := Finset.mem_map_equiv.mp hv.1 - have hΛ : a.σ.symm vv ∉ Λ := fun hc => hv.2 (Finset.mem_map_equiv.mpr hc) - have hcong := congrFun H ⟨a.σ.symm vv, Finset.mem_sdiff.mpr ⟨hΛ', hΛ⟩⟩ - simp only [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, - Equiv.subtypeEquiv_apply, EmbeddingLike.apply_eq_iff_eq] at hcong - change s ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ = s' ⟨vv, (Finset.mem_sdiff.mp hvv).1⟩ - convert hcong using 2 <;> - first - | exact (a.σ.apply_symm_apply vv).symm - | exact Subtype.ext (a.σ.apply_symm_apply vv).symm - · intro H - funext w - have hw := Finset.mem_sdiff.mp w.property - have hv : a.σ w.val ∈ a.region Λ' \ a.region Λ := Finset.mem_sdiff.mpr - ⟨Finset.mem_map' _ |>.mpr hw.1, fun hc => hw.2 (Finset.mem_map' _ |>.mp hc)⟩ - have hcong := congrFun H ⟨a.σ w.val, hv⟩ - simpa [combineIdx_symm_snd_apply, regionIdxEquiv, Equiv.piCongr_symm_apply, - Equiv.subtypeEquiv_apply, Equiv.symm_apply_apply, - EmbeddingLike.apply_eq_iff_eq] using hcong - by_cases hc : ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s).2 = - ((L.combineIdx (Finset.map_subset_map.mpr h)).symm s').2 - · rw [if_pos (key2.mpr hc), if_pos hc] - · rw [if_neg (fun hcc => hc (key2.mp hcc)), if_neg hc] - -/-! ### Covariance action on the quasi-local algebra - -The per-region covariance `*`-isomorphisms, being natural with respect to isotony -(`localCovariance_includeAlgebra`), assemble a covariance `toLocalNetCovariance` of the abstract net -`toLocalNet`. Its covariance action `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧` on the algebra of local -observables is therefore inherited from the net-level `LocalNet.Covariance.quasiLocalCovariance`. -/ - -/-- The covariance of the generated local net `toLocalNet` induced by a lattice covariance: the same - site permutation, with the local `*`-isomorphisms `localCovariance` as its covariance maps and - `localCovariance_includeAlgebra` as the isotony naturality. This exhibits the concrete - covariance as an instance of the abstract `LocalNet.Covariance`. -/ -noncomputable def toLocalNetCovariance : L.toLocalNet.Covariance where - σ := a.σ - β := a.localCovariance - β_incl h x := a.localCovariance_includeAlgebra h x - -/-- The action of a covariance on the algebra of local observables, as a ring homomorphism: - `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨a Λ, β_a X⟩⟧`. Inherited from the abstract net-level covariance action - `LocalNet.Covariance.quasiLocalCovariance` on `toLocalNet`. -/ -noncomputable def quasiLocalCovariance : L.quasiLocalAlgebra →+* L.quasiLocalAlgebra := - a.toLocalNetCovariance.quasiLocalCovariance - -@[simp] theorem quasiLocalCovariance_mk {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : L.quasiLocalAlgebra) = - ⟦⟨a.region Λ, a.localCovariance Λ X⟩⟧ := - rfl - -end Covariance - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean deleted file mode 100644 index fb55b09..0000000 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/Isotony.lean +++ /dev/null @@ -1,287 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.MatrixModel.SiteIndexSystem - -/-! -# Isotony embedding of the local net - -The **isotony** axiom of an AQFT net: for `Λ ⊆ Λ_total` there is a unital `*`-algebra inclusion -`𝔄(Λ) ↪ 𝔄(Λ_total)`, realised concretely as the tensor with identity on the complement -`A ↦ A ⊗ I_{Λ_total \ Λ}` (Naaijkens 2012 §1.3, Verch 2025 §1.2 axiom (i), Bratteli–Robinson -Vol.2 §6.2). This file builds the embedding `includeAlgebra` (as a `StarAlgHom`), proves it is -injective, and establishes its **functoriality** (`includeAlgebra_trans` / `includeAlgebra_refl`), -which makes the net a directed system of `*`-algebras. - -Pipeline: entry-wise underlying function `includeAlgebraFun` → algebraic identities -`includeAlgebraFun_{one,mul,star,...}` → bundled `includeAlgebra : _ →⋆ₐ[ℂ] _`. --/ - -@[expose] public section - -namespace SiteIndexSystem - -variable (L : SiteIndexSystem) - -/-! ### Isotony embedding (algebra inclusion) -/ - -/-- Entry-wise underlying function for `includeAlgebra`, defined separately so the - structural simp lemmas (`includeAlgebraFun_apply`, `..._apply_combineIdx`) reduce - by `rfl`/`simp` without going through the `StarAlgHom` coercion. -/ -noncomputable def includeAlgebraFun {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) : L.localAlgebra Λ_total := - Matrix.of fun s s' => - if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then - X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 - else 0 - -@[simp] lemma includeAlgebraFun_apply {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) (s s' : L.regionIdx Λ_total) : - L.includeAlgebraFun h X s s' = - if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then - X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 - else 0 := rfl - -/-- Entry-wise behaviour of `includeAlgebraFun` at combined indices: the off-diagonal - components in the complementary region vanish, leaving `X a a'` on the diagonal. -/ -@[simp] lemma includeAlgebraFun_apply_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) (X : L.localAlgebra Λ) - (a a' : L.regionIdx Λ) (b b' : L.regionIdx (Λ_total \ Λ)) : - L.includeAlgebraFun h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) = - if b = b' then X a a' else 0 := by - simp [includeAlgebraFun, Equiv.symm_apply_apply] - -lemma includeAlgebraFun_zero {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.includeAlgebraFun h 0 = 0 := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.zero_apply] - split_ifs <;> rfl - -lemma includeAlgebraFun_add {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X Y : L.localAlgebra Λ) : - L.includeAlgebraFun h (X + Y) = - L.includeAlgebraFun h X + L.includeAlgebraFun h Y := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.add_apply] - split_ifs with hbb - · rfl - · rw [add_zero] - -lemma includeAlgebraFun_smul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (c : ℂ) (X : L.localAlgebra Λ) : - L.includeAlgebraFun h (c • X) = c • L.includeAlgebraFun h X := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.smul_apply, smul_eq_mul] - split_ifs with hbb - · rfl - · rw [mul_zero] - -lemma includeAlgebraFun_one {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.includeAlgebraFun h 1 = 1 := by - ext s s' - by_cases hss : s = s' - · subst hss - rw [includeAlgebraFun_apply, if_pos rfl, Matrix.one_apply_eq, Matrix.one_apply_eq] - · rw [includeAlgebraFun_apply, Matrix.one_apply_ne hss] - -- Translate `s ≠ s'` to a disjunction on the two coordinates of `(combineIdx h).symm`. - have hne : (L.combineIdx h).symm s ≠ (L.combineIdx h).symm s' := fun heq => - hss ((L.combineIdx h).symm.injective heq) - rw [Ne, Prod.ext_iff, not_and_or] at hne - by_cases h2 : ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 - · rw [if_pos h2] - rcases hne with h1 | h2' - · rw [Matrix.one_apply_ne h1] - · exact absurd h2 h2' - · rw [if_neg h2] - -lemma includeAlgebraFun_star {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) : - L.includeAlgebraFun h (star X) = star (L.includeAlgebraFun h X) := by - ext s s' - simp only [includeAlgebraFun_apply, Matrix.star_apply] - by_cases h2 : ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 - · rw [if_pos h2, if_pos h2.symm] - · rw [if_neg h2, if_neg (fun hh => h2 hh.symm), star_zero] - -lemma includeAlgebraFun_mul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X Y : L.localAlgebra Λ) : - L.includeAlgebraFun h (X * Y) = - L.includeAlgebraFun h X * L.includeAlgebraFun h Y := by - ext s s' - -- Express both rows/columns through `combineIdx` so the `_apply_combineIdx` simp lemma fires. - set sa := ((L.combineIdx h).symm s).1 with hsa - set sb := ((L.combineIdx h).symm s).2 with hsb - set s'a := ((L.combineIdx h).symm s').1 with hs'a - set s'b := ((L.combineIdx h).symm s').2 with hs'b - have hs : s = L.combineIdx h (sa, sb) := by - simp [sa, sb, Equiv.apply_symm_apply] - have hs' : s' = L.combineIdx h (s'a, s'b) := by - simp [s'a, s'b, Equiv.apply_symm_apply] - rw [hs, hs', includeAlgebraFun_apply_combineIdx, Matrix.mul_apply] - -- Reindex the RHS sum (over `regionIdx Λ_total`) via `combineIdx`. - rw [show ((L.includeAlgebraFun h X * L.includeAlgebraFun h Y) - (L.combineIdx h (sa, sb)) (L.combineIdx h (s'a, s'b))) = - ∑ p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ), - L.includeAlgebraFun h X (L.combineIdx h (sa, sb)) (L.combineIdx h p) * - L.includeAlgebraFun h Y (L.combineIdx h p) (L.combineIdx h (s'a, s'b)) from by - rw [Matrix.mul_apply] - exact ((L.combineIdx h).sum_comp _).symm] - rw [Fintype.sum_prod_type] - simp_rw [includeAlgebraFun_apply_combineIdx] - -- Goal: - -- (if sb = s'b then ∑ a'', X sa a'' * Y a'' s'a else 0) - -- = ∑ a'', ∑ b'', (if sb = b'' then X sa a'' else 0) * (if b'' = s'b then Y a'' s'a else 0) - by_cases hbb : sb = s'b - · rw [if_pos hbb] - refine Finset.sum_congr rfl fun a'' _ => ?_ - rw [Finset.sum_eq_single sb - (fun b'' _ hb'' => by rw [if_neg fun heq => hb'' heq.symm, zero_mul]) - (fun h_not_mem => absurd (Finset.mem_univ sb) h_not_mem)] - rw [if_pos rfl, ← hbb, if_pos rfl] - · rw [if_neg hbb] - refine (Finset.sum_eq_zero fun a'' _ => ?_).symm - refine Finset.sum_eq_zero fun b'' _ => ?_ - by_cases hb_sb : sb = b'' - · subst hb_sb - rw [if_neg hbb, mul_zero] - · rw [if_neg hb_sb, zero_mul] - -lemma includeAlgebraFun_algebraMap {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) (c : ℂ) : - L.includeAlgebraFun h ((algebraMap ℂ (L.localAlgebra Λ)) c) = - (algebraMap ℂ (L.localAlgebra Λ_total)) c := by - rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, - includeAlgebraFun_smul, includeAlgebraFun_one] - -/-- **Isotony embedding** `𝔄(Λ) ↪ 𝔄(Λ_total)`: tensor a local matrix with the identity on - the complementary region. Realises the inclusion `A ↦ A ⊗ I_{Λ_total \ Λ}` from - Naaijkens 2012 §1.3 line 211, Verch 2025 §1.2 axiom (i), Bratteli–Robinson Vol.2 §6.2. - That this embedding is literally `A ↦ A ⊗ 1` of operators on Hilbert spaces is proved in - `SiteIndexSystem.opEquiv_includeAlgebra` (`TensorDecomposition`); the dual marginal is the partial - trace `SiteIndexSystem.opEquiv_restrict` (`PartialTraceOperator`). - Bundled as a unital `*`-algebra homomorphism so that `map_one`, `map_mul`, `map_star` - are available via the `StarAlgHom` API. Entry-wise: - `(includeAlgebra h X) s s' = X (combineIdx⁻¹ s).1 (combineIdx⁻¹ s').1` when the - complementary indices match, else `0`. -/ -noncomputable def includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.localAlgebra Λ →⋆ₐ[ℂ] L.localAlgebra Λ_total where - toFun := L.includeAlgebraFun h - map_zero' := L.includeAlgebraFun_zero h - map_add' := L.includeAlgebraFun_add h - map_one' := L.includeAlgebraFun_one h - map_mul' := L.includeAlgebraFun_mul h - commutes' := L.includeAlgebraFun_algebraMap h - map_star' := L.includeAlgebraFun_star h - -/-- Entry-wise unfolding of `includeAlgebra h X`: at indices `(s, s')` of the larger - region, the embedded matrix equals `X` on the diagonal (in the complementary index) - and zero off-diagonal. -/ -@[simp] lemma includeAlgebra_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) (s s' : L.regionIdx Λ_total) : - L.includeAlgebra h X s s' = - if ((L.combineIdx h).symm s).2 = ((L.combineIdx h).symm s').2 then - X ((L.combineIdx h).symm s).1 ((L.combineIdx h).symm s').1 - else 0 := rfl - -/-- Combined-index unfolding of the bundled `includeAlgebra` (the `StarAlgHom` coercion is - definitionally `includeAlgebraFun`, so this is `includeAlgebraFun_apply_combineIdx`). -/ -@[simp] lemma includeAlgebra_apply_combineIdx {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) (a a' : L.regionIdx Λ) (b b' : L.regionIdx (Λ_total \ Λ)) : - L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) = - if b = b' then X a a' else 0 := - L.includeAlgebraFun_apply_combineIdx h X a a' b b' - -/-- **Injectivity of the isotony embedding** (the `↪` of `𝔄(Λ) ↪ 𝔄(Λ_total)`): under - the standing AQFT non-degeneracy assumption that the complementary region has a - non-empty index type, `includeAlgebra h` is injective as a map of `*`-algebras. -/ -theorem includeAlgebra_injective {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - [hne : Nonempty (L.regionIdx (Λ_total \ Λ))] : - Function.Injective (L.includeAlgebra h) := by - rw [injective_iff_map_eq_zero] - intro X hX - ext a a' - obtain ⟨b⟩ := hne - have heq : L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = - 0 := by rw [hX]; rfl - have key : L.includeAlgebra h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = - X a a' := by - change L.includeAlgebraFun h X (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) = X a a' - rw [includeAlgebraFun_apply_combineIdx, if_pos rfl] - rw [key] at heq - simpa using heq - -/-! ### Functoriality (composition of the isotony net) - -The isotony embeddings compose: including `Λ₁ ↪ Λ₂ ↪ Λ₃` equals the direct inclusion -`Λ₁ ↪ Λ₃`. This upgrades `includeAlgebra` from a family of embeddings to a genuine functor -on the region poset — a directed system of `*`-algebras — matching the net structure of -Naaijkens 2012 §3.2 and Verch 2025 §1.2. -/ - -/-- The `Λ₁`-coordinate of a `Λ₃`-index is unchanged by routing through an intermediate - region `Λ₂`: restricting to `Λ₂` then to `Λ₁` equals restricting directly to `Λ₁`. - Holds definitionally by proof irrelevance of the `⊆` witnesses. -/ -private lemma combineIdx_symm_fst_trans {Λ₁ Λ₂ Λ₃ : Finset L.sites} - (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (s : L.regionIdx Λ₃) : - ((L.combineIdx h₁₂).symm ((L.combineIdx h₂₃).symm s).1).1 - = ((L.combineIdx (Finset.Subset.trans h₁₂ h₂₃)).symm s).1 := rfl - -/-- The complementary index of a `Λ₃`-index over `Λ₁` matches between `s` and `s'` iff it - matches both over `Λ₂` (the outer complement) and over `Λ₁` inside `Λ₂` (the inner - complement). This is the factorisation `Λ₃ \ Λ₁ = (Λ₃ \ Λ₂) ⊔ (Λ₂ \ Λ₁)` at the level - of region indices, and is the bookkeeping core of functoriality. -/ -private lemma combineIdx_symm_snd_trans_iff {Λ₁ Λ₂ Λ₃ : Finset L.sites} - (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (s s' : L.regionIdx Λ₃) : - (((L.combineIdx (Finset.Subset.trans h₁₂ h₂₃)).symm s).2 - = ((L.combineIdx (Finset.Subset.trans h₁₂ h₂₃)).symm s').2) - ↔ (((L.combineIdx h₂₃).symm s).2 = ((L.combineIdx h₂₃).symm s').2 - ∧ ((L.combineIdx h₁₂).symm ((L.combineIdx h₂₃).symm s).1).2 - = ((L.combineIdx h₁₂).symm ((L.combineIdx h₂₃).symm s').1).2) := by - constructor - · intro h - refine ⟨?_, ?_⟩ - · funext t - exact congrFun h ⟨t.val, Finset.mem_sdiff.mpr - ⟨(Finset.mem_sdiff.mp t.property).1, - fun hh => (Finset.mem_sdiff.mp t.property).2 (h₁₂ hh)⟩⟩ - · funext t - exact congrFun h ⟨t.val, Finset.mem_sdiff.mpr - ⟨h₂₃ (Finset.mem_sdiff.mp t.property).1, (Finset.mem_sdiff.mp t.property).2⟩⟩ - · rintro ⟨hA, hB⟩ - funext t - by_cases ht2 : t.val ∈ Λ₂ - · exact congrFun hB ⟨t.val, Finset.mem_sdiff.mpr ⟨ht2, (Finset.mem_sdiff.mp t.property).2⟩⟩ - · exact congrFun hA ⟨t.val, Finset.mem_sdiff.mpr ⟨(Finset.mem_sdiff.mp t.property).1, ht2⟩⟩ - -/-- Pointwise form of functoriality: including `X` from `Λ₁` into `Λ₃` directly equals first - including into `Λ₂`, then into `Λ₃`. -/ -theorem includeAlgebra_trans_apply {Λ₁ Λ₂ Λ₃ : Finset L.sites} - (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (X : L.localAlgebra Λ₁) : - L.includeAlgebra h₂₃ (L.includeAlgebra h₁₂ X) - = L.includeAlgebra (Finset.Subset.trans h₁₂ h₂₃) X := by - ext s s' - simp only [includeAlgebra_apply] - rw [combineIdx_symm_fst_trans, combineIdx_symm_fst_trans, ← ite_and] - simp only [L.combineIdx_symm_snd_trans_iff h₁₂ h₂₃ s s'] - -/-- **Functoriality of the isotony net**: the inclusions compose. For `Λ₁ ⊆ Λ₂ ⊆ Λ₃`, - `includeAlgebra` of the composite subset equals the composition of the two embeddings, - so the net is a directed system of `*`-algebras (Naaijkens 2012 §3.2). -/ -theorem includeAlgebra_trans {Λ₁ Λ₂ Λ₃ : Finset L.sites} - (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) : - (L.includeAlgebra h₂₃).comp (L.includeAlgebra h₁₂) - = L.includeAlgebra (Finset.Subset.trans h₁₂ h₂₃) := - StarAlgHom.ext fun X => by rw [StarAlgHom.comp_apply, includeAlgebra_trans_apply] - -/-- The identity inclusion `Λ ⊆ Λ` acts as the identity: `includeAlgebra (subset_refl Λ)` - is the identity `*`-algebra map. The complementary region `Λ \ Λ` is empty, so the - diagonal condition is vacuously satisfied. -/ -theorem includeAlgebra_refl_apply {Λ : Finset L.sites} (X : L.localAlgebra Λ) : - L.includeAlgebra (subset_refl Λ) X = X := by - ext s s' - have hc : ((L.combineIdx (subset_refl Λ)).symm s).2 - = ((L.combineIdx (subset_refl Λ)).symm s').2 := by - funext t - exact absurd (Finset.mem_sdiff.mp t.property).1 (Finset.mem_sdiff.mp t.property).2 - rw [includeAlgebra_apply, if_pos hc] - rfl - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean deleted file mode 100644 index b80e904..0000000 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/Locality.lean +++ /dev/null @@ -1,127 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony - -/-! -# Locality (Einstein causality) of the local net - -Observables localised in **disjoint** regions commute. For finite-dimensional lattice systems this -is the concrete realisation of the AQFT locality axiom (Naaijkens 2012 §3.2: spacelike-separated -— here disjoint — regions commute; Verch 2025 §1.2). The proof reduces to the union region -`Λ₁ ∪ Λ₂`, where the two embeddings act on complementary tensor factors, and ultimately to -commutativity of the scalar matrix entries in `ℂ`. --/ - -@[expose] public section - -namespace SiteIndexSystem - -variable (L : SiteIndexSystem) - -/-- The right-region embedding `𝔄(Λ₂) ↪ 𝔄(Λ₁ ∪ Λ₂)` evaluated at indices factored through - the *left* split `combineIdx (Λ₁ ⊆ Λ₁ ∪ Λ₂)`: since `Λ₁` and `Λ₂` are disjoint, the - complement `(Λ₁ ∪ Λ₂) \ Λ₁` is exactly `Λ₂`, so the value is `Y` on the complementary - coordinate, with the diagonal condition now living on the `Λ₁` coordinate. -/ -private lemma includeAlgebra_union_right_combineIdx_left - {Λ₁ Λ₂ : Finset L.sites} (hd : Disjoint Λ₁ Λ₂) (Y : L.localAlgebra Λ₂) - (a a' : L.regionIdx Λ₁) (b b' : L.regionIdx ((Λ₁ ∪ Λ₂) \ Λ₁)) : - L.includeAlgebra Finset.subset_union_right Y - (L.combineIdx Finset.subset_union_left (a, b)) - (L.combineIdx Finset.subset_union_left (a', b')) - = if a = a' then - Y (L.regionIdxCongr (Finset.union_sdiff_cancel_left hd) b) - (L.regionIdxCongr (Finset.union_sdiff_cancel_left hd) b') else 0 := by - have hcompl : (Λ₁ ∪ Λ₂) \ Λ₁ = Λ₂ := Finset.union_sdiff_cancel_left hd - -- The `Λ₂`-coordinate (first projection under `combineIdx Λ₂⊆U`) of a left-combined index - -- is the complement coordinate, transported along `hcompl`. - have hdR : ∀ (c : L.regionIdx Λ₁) (d : L.regionIdx ((Λ₁ ∪ Λ₂) \ Λ₁)), - ((L.combineIdx Finset.subset_union_right).symm - (L.combineIdx Finset.subset_union_left (c, d))).1 - = L.regionIdxCongr hcompl d := by - intro c d - funext w - obtain ⟨wv, wp⟩ := w - have hw1 : wv ∉ Λ₁ := fun hh => (Finset.disjoint_left.mp hd hh) wp - change L.combineIdx Finset.subset_union_left (c, d) - ⟨wv, Finset.subset_union_right wp⟩ = _ - rw [combineIdx_apply_not_mem Finset.subset_union_left c d ⟨wv, _⟩ hw1, - L.regionIdxCongr_apply hcompl d - (Finset.mem_sdiff.mpr ⟨Finset.subset_union_right wp, hw1⟩) wp] - -- The `(U\Λ₂)`-coordinate (second projection under `combineIdx Λ₂⊆U`) only sees `Λ₁`, - -- transported along `(Λ₁ ∪ Λ₂) \ Λ₂ = Λ₁`. - have hcR : ∀ (c : L.regionIdx Λ₁) (d : L.regionIdx ((Λ₁ ∪ Λ₂) \ Λ₁)), - ((L.combineIdx Finset.subset_union_right).symm - (L.combineIdx Finset.subset_union_left (c, d))).2 - = L.regionIdxCongr (Finset.union_sdiff_cancel_right hd).symm c := by - intro c d - funext w - obtain ⟨wv, wp⟩ := w - have hwU : wv ∈ Λ₁ ∪ Λ₂ := (Finset.mem_sdiff.mp wp).1 - have hw1 : wv ∈ Λ₁ := by - rcases Finset.mem_union.mp hwU with h | h - · exact h - · exact absurd h (Finset.mem_sdiff.mp wp).2 - change L.combineIdx Finset.subset_union_left (c, d) ⟨wv, hwU⟩ = _ - rw [combineIdx_apply_mem Finset.subset_union_left c d ⟨wv, hwU⟩ hw1, - L.regionIdxCongr_apply (Finset.union_sdiff_cancel_right hd).symm c hw1 wp] - have hcond : (((L.combineIdx Finset.subset_union_right).symm - (L.combineIdx Finset.subset_union_left (a, b))).2 - = ((L.combineIdx Finset.subset_union_right).symm - (L.combineIdx Finset.subset_union_left (a', b'))).2) ↔ a = a' := by - rw [hcR a b, hcR a' b'] - exact (L.regionIdxCongr (Finset.union_sdiff_cancel_right hd).symm).apply_eq_iff_eq - rw [includeAlgebra_apply, hdR a b, hdR a' b'] - simp only [hcond] - -/-- **Bipartite locality**: in the union region `Λ₁ ∪ Λ₂` of two disjoint regions, a - `Λ₁`-observable and a `Λ₂`-observable commute. The two embeddings act on complementary - tensor factors, so the matrix entries collapse to commuting scalar products in `ℂ`. -/ -private lemma includeAlgebra_commute_union {Λ₁ Λ₂ : Finset L.sites} (hd : Disjoint Λ₁ Λ₂) - (X : L.localAlgebra Λ₁) (Y : L.localAlgebra Λ₂) : - Commute (L.includeAlgebra Finset.subset_union_left X) - (L.includeAlgebra Finset.subset_union_right Y) := by - suffices h : L.includeAlgebra Finset.subset_union_left X * - L.includeAlgebra Finset.subset_union_right Y = - L.includeAlgebra Finset.subset_union_right Y * - L.includeAlgebra Finset.subset_union_left X from h - ext s s' - obtain ⟨⟨a, b⟩, rfl⟩ := (L.combineIdx Finset.subset_union_left).surjective s - obtain ⟨⟨a', b'⟩, rfl⟩ := (L.combineIdx Finset.subset_union_left).surjective s' - rw [Matrix.mul_apply, Matrix.mul_apply, - ← (L.combineIdx Finset.subset_union_left).sum_comp - (fun t => L.includeAlgebra Finset.subset_union_left X - (L.combineIdx Finset.subset_union_left (a, b)) t * - L.includeAlgebra Finset.subset_union_right Y t - (L.combineIdx Finset.subset_union_left (a', b'))), - ← (L.combineIdx Finset.subset_union_left).sum_comp - (fun t => L.includeAlgebra Finset.subset_union_right Y - (L.combineIdx Finset.subset_union_left (a, b)) t * - L.includeAlgebra Finset.subset_union_left X t - (L.combineIdx Finset.subset_union_left (a', b'))), - Fintype.sum_prod_type, Fintype.sum_prod_type] - simp only [includeAlgebra_apply_combineIdx, - L.includeAlgebra_union_right_combineIdx_left hd, - ite_mul, mul_ite, zero_mul, mul_zero, Finset.sum_ite_irrel, Finset.sum_const_zero, - Finset.sum_ite_eq, Finset.sum_ite_eq', Finset.mem_univ, if_true] - ring - -/-- **Locality / Einstein causality (lattice systems)**: observables localised in disjoint - regions commute inside any common total region. The finite-dimensional concrete form of - the AQFT locality axiom (Naaijkens 2012 §3.2; Verch 2025 §1.2). Reduces to the bipartite - case via functoriality (`includeAlgebra_trans_apply`) and the ring-hom property of the - embedding into the union. -/ -theorem includeAlgebra_commute_of_disjoint {Λ₁ Λ₂ Λ_total : Finset L.sites} - (h₁ : Λ₁ ⊆ Λ_total) (h₂ : Λ₂ ⊆ Λ_total) (hd : Disjoint Λ₁ Λ₂) - (X : L.localAlgebra Λ₁) (Y : L.localAlgebra Λ₂) : - Commute (L.includeAlgebra h₁ X) (L.includeAlgebra h₂ Y) := by - have hU : Λ₁ ∪ Λ₂ ⊆ Λ_total := Finset.union_subset h₁ h₂ - have e1 : L.includeAlgebra h₁ X - = L.includeAlgebra hU (L.includeAlgebra Finset.subset_union_left X) := by - rw [includeAlgebra_trans_apply] - have e2 : L.includeAlgebra h₂ Y - = L.includeAlgebra hU (L.includeAlgebra Finset.subset_union_right Y) := by - rw [includeAlgebra_trans_apply] - rw [e1, e2] - exact (L.includeAlgebra_commute_union hd X Y).map (L.includeAlgebra hU) - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean deleted file mode 100644 index 7ca8ee5..0000000 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/Net.lean +++ /dev/null @@ -1,105 +0,0 @@ -module - -public import Mathlib.Analysis.CStarAlgebra.Matrix -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Locality -public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra - -/-! -# The local net generated by a site-index system - -A `SiteIndexSystem` on a (possibly infinite) lattice of sites — the data of a finite local -index type at each site — generates a genuine **local net of C⋆-algebras** (`LocalNet`): the -assignment `Λ ↦ 𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` to each finite region, with the isotony embeddings -`includeAlgebra (h : Λ ⊆ Λ')` (the inclusion `A ↦ A ⊗ I` of `LocalNet.MatrixModel.Isotony`), -functorial (`includeAlgebra_trans_apply`, `includeAlgebra_refl_apply`) and local -(`includeAlgebra_commute_of_disjoint`). - -* `instCStarAlgebraLocal` makes each finite-region matrix algebra a C⋆-algebra under the - `L2Operator` norm; this discharges the C⋆-structure required by `LocalNet`. -* `SiteIndexSystem.toLocalNet` packages the matrix algebras and isotony embeddings into a - `LocalNet`. The **algebra of local observables** and the **quasi-local C⋆-algebra** are then - inherited from the abstract net (`LocalNet.quasiLocalAlgebra`, `LocalNet.quasiLocalCStarAlgebra`). -* When each site has a non-empty local index type the embeddings are injective, so the generated - net is `LocalNet.Faithful` and its quasi-local C⋆-algebra is the AQFT quasi-local algebra - `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2). - -The site-index-system-level abbreviations `quasiLocalAlgebra` / `ιLocal` / `quasiLocalCStarAlgebra` -below are thin wrappers around the corresponding `LocalNet` constructions on `toLocalNet`. The -concrete covariance of this net and its inherited action live in `LocalNet.MatrixModel.Covariance`. --/ - -@[expose] public section - -namespace SiteIndexSystem - -open scoped Matrix.Norms.L2Operator - -variable (S : SiteIndexSystem) - -/-- Each finite-region matrix algebra `𝔄(Λ) = Matrix (regionIdx Λ) (regionIdx Λ) ℂ` is a - (complex) C⋆-algebra under the `L2Operator` norm. Stated for `localAlgebra` so the choice of - the `L2Operator` norm does not leak to arbitrary matrices. -/ -noncomputable instance instCStarAlgebraLocal (Λ : Finset S.sites) : - CStarAlgebra (S.localAlgebra Λ) where - -/-- The **local net generated by the lattice system**: the assignment of matrix algebras to - finite regions, with the isotony embeddings as connecting maps. This realises the abstract - Haag–Kastler net `LocalNet` for the finite-dimensional matrix model. -/ -noncomputable def toLocalNet : LocalNet S.sites where - algebra := S.localAlgebra - incl h := S.includeAlgebra h - incl_refl x := S.includeAlgebra_refl_apply x - incl_trans h₁₂ h₂₃ x := S.includeAlgebra_trans_apply h₁₂ h₂₃ x - locality h₁ h₂ hd x y := S.includeAlgebra_commute_of_disjoint h₁ h₂ hd x y - -@[simp] theorem toLocalNet_algebra (Λ : Finset S.sites) : - S.toLocalNet.algebra Λ = S.localAlgebra Λ := rfl - -@[simp] theorem toLocalNet_incl {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') : - S.toLocalNet.incl h = S.includeAlgebra h := rfl - -/-- The generated net is **faithful**: if each site has a non-empty local index type, the complementary - region indices are non-empty, so the isotony embeddings are injective. -/ -instance toLocalNet_faithful [∀ s, Nonempty (S.localIdx s)] : S.toLocalNet.Faithful where - incl_injective h := S.includeAlgebra_injective h - -/-! ### Lattice-system-level quasi-local algebra - -Thin wrappers exposing the `LocalNet` constructions on `toLocalNet` directly on the lattice system. -/ - -/-- The **algebra of local observables** of the lattice system: the algebraic inductive limit of the - finite-region matrix algebras (inherited from `LocalNet.quasiLocalAlgebra` on `toLocalNet`). -/ -noncomputable abbrev quasiLocalAlgebra : Type _ := S.toLocalNet.quasiLocalAlgebra - -/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local - observables (the cocone of the inductive limit). -/ -noncomputable def ιLocal (Λ : Finset S.sites) : - S.localAlgebra Λ →+* S.quasiLocalAlgebra := - S.toLocalNet.ιLocal Λ - -/-- Compatibility of the cocone with the isotony embeddings. -/ -@[simp] theorem ιLocal_includeAlgebra {Λ Λ' : Finset S.sites} (h : Λ ⊆ Λ') - (X : S.localAlgebra Λ) : - S.ιLocal Λ' (S.includeAlgebra h X) = S.ιLocal Λ X := - S.toLocalNet.ιLocal_incl h X - -/-- **Exhaustion**: every element of the algebra of local observables comes from some finite - region. -/ -theorem exists_ιLocal (z : S.quasiLocalAlgebra) : - ∃ (Λ : Finset S.sites) (X : S.localAlgebra Λ), z = S.ιLocal Λ X := - S.toLocalNet.exists_ιLocal z - -/-- **Locality**: observables localised in disjoint regions commute inside the algebra of local - observables. -/ -theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset S.sites} (hd : Disjoint Λ₁ Λ₂) - (X : S.localAlgebra Λ₁) (Y : S.localAlgebra Λ₂) : - Commute (S.ιLocal Λ₁ X) (S.ιLocal Λ₂ Y) := - S.toLocalNet.ιLocal_commute_of_disjoint hd X Y - -/-- The **quasi-local C⋆-algebra** of the lattice system (assuming non-empty local dimensions): the - completion of the algebra of local observables, i.e. the AQFT quasi-local algebra - `𝔄 = ‾⋃_Λ 𝔄(Λ)`. -/ -noncomputable abbrev quasiLocalCStarAlgebra [∀ s, Nonempty (S.localIdx s)] : Type _ := - S.toLocalNet.quasiLocalCStarAlgebra - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean deleted file mode 100644 index 5b4e3bf..0000000 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/SiteIndexSystem.lean +++ /dev/null @@ -1,334 +0,0 @@ -module - -public import QuantumSystem.Channel - -/-! -# Site-index system: data of a local net of matrix algebras - -This file carries the **data** of the finite-dimensional matrix model of a local net — the -`SiteIndexSystem` — and the region-index combinatorics on which the concrete AQFT net properties -are built. It is the foundation of the *concrete* layer (`LocalNet.MatrixModel`), which instances -the abstract Haag–Kastler net `LocalNet` (`LocalNet.Net`). An AQFT system assigns to each region -`Λ` an algebra `𝔄(Λ)` of observables; for finite-dimensional site-index systems this specialises -to: - -- a **set of sites** `L` (an arbitrary type with `DecidableEq`; no order/geometric structure), -- a finite local index type `ℂ^{n_x}` at each site `x`, -- regions `Λ : Finset L.sites`, -- local algebra `𝔄(Λ) = ⊗_{x ∈ Λ} M_{n_x}(ℂ)` realised as - `Matrix (Π s ∈ Λ, idx s) (Π s ∈ Λ, idx s) ℂ`. - -This file provides the carrier structure, the derived region-index types, the index-combiner -equivalence `combineIdx` realising `regionIdx Λ_total ≃ regionIdx Λ × regionIdx (Λ_total \ Λ)`, -the cardinality factorisation, the transport `regionIdxCongr`, and the bipartite and tripartite -region factorisation equivalences (`regionIdxPairEquiv`, `regionIdxTripleEquiv`). - -The net **properties** built on this data live in sibling modules of `LocalNet.MatrixModel`: -`MatrixModel.Isotony` (the embedding `𝔄(Λ) ↪ 𝔄(Λ_total)` + functoriality), `MatrixModel.Locality` -(disjoint regions commute), `MatrixModel.Net` (the generated `LocalNet` and quasi-local wrappers), -`MatrixModel.Covariance` (concrete covariance data and action). The abstract net axioms and the -quasi-local C⋆-algebra they generate live in `LocalNet.Net` / `LocalNet.QuasiLocalAlgebra`. -Restriction / partial trace lives in `Analysis/Matrix/PartialTrace.lean`. - -## References - -* Verch 2025 (`https://arxiv.org/abs/2507.00900`) -* Naaijkens 2012 (`https://repository.ubn.ru.nl/handle/2066/92737`) --/ - -@[expose] public section - -/-- Data for a **local net of matrix algebras** over a (possibly infinite) **set of sites** — an - arbitrary index type with no order or geometric lattice structure assumed. - Each site `s : sites` carries a finite index type `localIdx s` whose cardinality is the - local Hilbert-space dimension. The local algebra at a *finite* region `Λ : Finset sites` - is then the matrix algebra on the dependent product `Π s ∈ Λ, localIdx s` — finite even - when `sites` is infinite, since regions are finite subsets. Leaving `sites` unrestricted - (only `DecidableEq`) is what allows the quasi-local algebra to be a genuine inductive - limit over the directed set of finite regions, as in Naaijkens 2012 §1.3 and - Bratteli–Robinson Vol.2 §6.2. -/ -structure SiteIndexSystem where - /-- The set of sites — an arbitrary index type; regions are its finite subsets. -/ - sites : Type* - [sitesDecEq : DecidableEq sites] - /-- Local Hilbert-space index type at each site. -/ - localIdx : sites → Type* - [localFintype : ∀ s, Fintype (localIdx s)] - [localDecEq : ∀ s, DecidableEq (localIdx s)] - -namespace SiteIndexSystem - -attribute [instance] sitesDecEq localFintype localDecEq - -variable (L : SiteIndexSystem) - -/-- Index type of a region: dependent product of local indices over the sites in `Λ`. -/ -abbrev regionIdx (Λ : Finset L.sites) : Type _ := ∀ s : Λ, L.localIdx s.val - -/-- A region's index type stays nonempty when restricting to a sub-region: any element of - `regionIdx Λ_total` restricts to an element of `regionIdx Λ` along `h : Λ ⊆ Λ_total`. -/ -lemma regionIdx_nonempty_of_subset {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - [hne : Nonempty (L.regionIdx Λ_total)] : Nonempty (L.regionIdx Λ) := - hne.elim fun f => ⟨fun s => f ⟨s.val, h s.property⟩⟩ - -/-- Local algebra `𝔄(Λ)` at a region — concrete matrix algebra over `ℂ`. -/ -abbrev localAlgebra (Λ : Finset L.sites) : Type _ := - Matrix (L.regionIdx Λ) (L.regionIdx Λ) ℂ - -/-- Density matrices on a region (positive semi-definite, trace 1). -/ -abbrev densityMatrix (Λ : Finset L.sites) : Type _ := - DensityMatrix (L.regionIdx Λ) - -/-! ### Combining region indices via disjoint union -/ - -/-- For `Λ ⊆ Λ_total`, the index type of the larger region splits as a product: - `regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ regionIdx Λ_total`. This realises the tensor - factorisation `ℋ_Λ_total = ℋ_Λ ⊗ ℋ_{Λ_total \ Λ}` underlying isotony and partial trace. - The factorisation is made formal at the operator level by `SiteIndexSystem.tensorEquiv` - (`TensorDecomposition`), an algebra isomorphism of the corresponding operator algebras. -/ -def combineIdx {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - (L.regionIdx Λ × L.regionIdx (Λ_total \ Λ)) ≃ L.regionIdx Λ_total where - toFun ab s := - if hs : s.val ∈ Λ then ab.1 ⟨s.val, hs⟩ - else ab.2 ⟨s.val, Finset.mem_sdiff.mpr ⟨s.property, hs⟩⟩ - invFun f := - (fun s => f ⟨s.val, h s.property⟩, - fun s => f ⟨s.val, (Finset.mem_sdiff.mp s.property).1⟩) - left_inv := by - rintro ⟨a, b⟩ - ext1 - · funext s - have hs : s.val ∈ Λ := s.property - simp [hs] - · funext s - have hns : s.val ∉ Λ := (Finset.mem_sdiff.mp s.property).2 - simp [hns] - right_inv := by - intro f - funext s - by_cases hs : s.val ∈ Λ <;> simp [hs] - -/-! ### Pointwise behaviour of `combineIdx` -/ - -variable {L} in -@[simp] lemma combineIdx_apply_mem - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (a : L.regionIdx Λ) (b : L.regionIdx (Λ_total \ Λ)) - (s : ↥Λ_total) (hs : s.val ∈ Λ) : - (L.combineIdx h (a, b)) s = a ⟨s.val, hs⟩ := by - simp only [combineIdx, Equiv.coe_fn_mk] - rw [dif_pos hs] - -variable {L} in -@[simp] lemma combineIdx_apply_not_mem - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (a : L.regionIdx Λ) (b : L.regionIdx (Λ_total \ Λ)) - (s : ↥Λ_total) (hs : s.val ∉ Λ) : - (L.combineIdx h (a, b)) s - = b ⟨s.val, Finset.mem_sdiff.mpr ⟨s.property, hs⟩⟩ := by - simp only [combineIdx, Equiv.coe_fn_mk] - rw [dif_neg hs] - -/-- Cardinality factorisation for region indices induced by `combineIdx`. -/ -theorem card_regionIdx_total {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - Fintype.card (L.regionIdx Λ_total) = - Fintype.card (L.regionIdx Λ) * Fintype.card (L.regionIdx (Λ_total \ Λ)) := by - rw [← Fintype.card_prod] - exact Fintype.card_congr (L.combineIdx h).symm - -/-- Transport `regionIdx` along a Finset equality. -/ -def regionIdxCongr {Λ Λ' : Finset L.sites} (h : Λ = Λ') : - L.regionIdx Λ ≃ L.regionIdx Λ' := - h ▸ Equiv.refl _ - -@[simp] lemma regionIdxCongr_apply - {Λ Λ' : Finset L.sites} (h : Λ = Λ') (x : L.regionIdx Λ) - {s : L.sites} (hs : s ∈ Λ) (hs' : s ∈ Λ') : - (L.regionIdxCongr h x) ⟨s, hs'⟩ = x ⟨s, hs⟩ := by - subst h - rfl - -/-! ### Region equivalences - -Bipartite and tripartite factorisations of a region's index type over arbitrary site types: -`regionIdx {a, b} ≃ localIdx a × localIdx b` and the right-associated three-element analogue. -Both are direct definitions with concrete `toFun`, so every projection evaluates by `rfl`. -/ - -variable (L : SiteIndexSystem) - -/-- **1-element factorisation**: `regionIdx {a} ≃ localIdx a`. Evaluation at the single site `a`. -/ -def regionIdxSingletonEquiv (a : L.sites) : - L.regionIdx ({a} : Finset L.sites) ≃ L.localIdx a where - toFun f := f ⟨a, Finset.mem_singleton_self a⟩ - invFun x := fun ⟨s, hs⟩ => (Finset.mem_singleton.mp hs) ▸ x - left_inv f := by - funext ⟨s, hs⟩ - obtain rfl : s = a := Finset.mem_singleton.mp hs - rfl - right_inv x := rfl - -@[simp] lemma regionIdxSingletonEquiv_apply (a : L.sites) - (f : L.regionIdx ({a} : Finset L.sites)) : - L.regionIdxSingletonEquiv a f = f ⟨a, Finset.mem_singleton_self a⟩ := rfl - -/-- **2-element factorisation**: `regionIdx {a, b} ≃ localIdx a × localIdx b` when - `a ≠ b`. Direct definition with concrete `toFun` so both projections evaluate by `rfl`. -/ -def regionIdxPairEquiv {a b : L.sites} (hab : a ≠ b) : - L.regionIdx ({a, b} : Finset L.sites) ≃ L.localIdx a × L.localIdx b where - toFun f := - (f ⟨a, Finset.mem_insert_self a {b}⟩, - f ⟨b, Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)⟩) - invFun ab := fun ⟨s, hs⟩ => - if h : s = a then h ▸ ab.1 - else - have hsb : s = b := by - rcases Finset.mem_insert.mp hs with h' | h' - · exact absurd h' h - · exact Finset.mem_singleton.mp h' - hsb ▸ ab.2 - left_inv f := by - funext ⟨s, hs⟩ - by_cases hsa : s = a - · subst hsa - simp - · have hsb : s = b := by - rcases Finset.mem_insert.mp hs with h' | h' - · exact absurd h' hsa - · exact Finset.mem_singleton.mp h' - subst hsb - simp [hsa] - right_inv ab := by - have hba : b ≠ a := fun h_eq => hab h_eq.symm - ext1 - · simp - · simp [hba] - -/-- Closed-form unfolding of `regionIdxPairEquiv` as a pair. -/ -@[simp] lemma regionIdxPairEquiv_apply {a b : L.sites} (hab : a ≠ b) - (f : L.regionIdx ({a, b} : Finset L.sites)) : - L.regionIdxPairEquiv hab f = - (f ⟨a, Finset.mem_insert_self a {b}⟩, - f ⟨b, Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)⟩) := rfl - -/-- Closed-form first projection of `regionIdxPairEquiv` — picks out the value at site `a`. -/ -@[simp] lemma regionIdxPairEquiv_apply_fst {a b : L.sites} (hab : a ≠ b) - (f : L.regionIdx ({a, b} : Finset L.sites)) : - (L.regionIdxPairEquiv hab f).1 = f ⟨a, Finset.mem_insert_self a {b}⟩ := rfl - -/-- Closed-form second projection of `regionIdxPairEquiv` — picks out the value at site `b`. -/ -@[simp] lemma regionIdxPairEquiv_apply_snd {a b : L.sites} (hab : a ≠ b) - (f : L.regionIdx ({a, b} : Finset L.sites)) : - (L.regionIdxPairEquiv hab f).2 = - f ⟨b, Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl)⟩ := rfl - -/-- **3-element factorisation (right-associated)**: - `regionIdx {a, b, c} ≃ localIdx a × localIdx b × localIdx c` when the sites are - pairwise distinct. Direct definition with concrete `toFun` so all three projections - evaluate by `rfl`. -/ -def regionIdxTripleEquiv {a b c : L.sites} (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) : - L.regionIdx ({a, b, c} : Finset L.sites) ≃ - L.localIdx a × L.localIdx b × L.localIdx c where - toFun f := - (f ⟨a, Finset.mem_insert_self a {b, c}⟩, - f ⟨b, Finset.mem_insert_of_mem (Finset.mem_insert_self b {c})⟩, - f ⟨c, Finset.mem_insert_of_mem - (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl))⟩) - invFun abc := fun ⟨s, hs⟩ => - if h : s = a then h ▸ abc.1 - else if h' : s = b then h' ▸ abc.2.1 - else - have hsc : s = c := by - rcases Finset.mem_insert.mp hs with hh | hh - · exact absurd hh h - · rcases Finset.mem_insert.mp hh with hh | hh - · exact absurd hh h' - · exact Finset.mem_singleton.mp hh - hsc ▸ abc.2.2 - left_inv f := by - funext ⟨s, hs⟩ - by_cases hsa : s = a - · subst hsa; simp - by_cases hsb : s = b - · subst hsb; simp [hsa] - have hsc : s = c := by - rcases Finset.mem_insert.mp hs with hh | hh - · exact absurd hh hsa - · rcases Finset.mem_insert.mp hh with hh | hh - · exact absurd hh hsb - · exact Finset.mem_singleton.mp hh - subst hsc; simp [hsa, hsb] - right_inv abc := by - have hba : b ≠ a := fun h => hab h.symm - have hca : c ≠ a := fun h => hac h.symm - have hcb : c ≠ b := fun h => hbc h.symm - ext1 - · simp - · ext1 - · simp [hba] - · simp [hca, hcb] - -/-- Closed-form first projection of `regionIdxTripleEquiv` — value at site `a`. -/ -@[simp] lemma regionIdxTripleEquiv_apply_fst {a b c : L.sites} - (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) - (f : L.regionIdx ({a, b, c} : Finset L.sites)) : - (L.regionIdxTripleEquiv hab hbc hac f).1 = f ⟨a, Finset.mem_insert_self a {b, c}⟩ := rfl - -/-- Second projection of `regionIdxTripleEquiv` — value at site `b`. -/ -@[simp] lemma regionIdxTripleEquiv_apply_snd_fst {a b c : L.sites} - (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) - (f : L.regionIdx ({a, b, c} : Finset L.sites)) : - (L.regionIdxTripleEquiv hab hbc hac f).2.1 = - f ⟨b, Finset.mem_insert_of_mem (Finset.mem_insert_self b {c})⟩ := rfl - -/-- Third projection of `regionIdxTripleEquiv` — value at site `c`. -/ -@[simp] lemma regionIdxTripleEquiv_apply_snd_snd {a b c : L.sites} - (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) - (f : L.regionIdx ({a, b, c} : Finset L.sites)) : - (L.regionIdxTripleEquiv hab hbc hac f).2.2 = - f ⟨c, Finset.mem_insert_of_mem - (Finset.mem_insert_of_mem (Finset.mem_singleton.mpr rfl))⟩ := rfl - -/-- **Compatibility of the triple factorisation with the `{a, b}`-cut.** Reading a region index -of `{a, b, c}` that was assembled from an `{a, b}`-part `ab` and a complement-part `cc` (via -`combineIdx`) through the three-element factorisation returns the `a`- and `b`-values from `ab` -(via `regionIdxPairEquiv`) and the `c`-value from `cc`. This is the index-level statement that -the associative regrouping `(localIdx a × localIdx b) × localIdx c` underlying `combineIdx` for -`{a, b} ⊆ {a, b, c}` agrees with the right-associated `regionIdxTripleEquiv`. -/ -theorem regionIdxTripleEquiv_combineIdx {a b c : L.sites} - (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) - (h_ab : ({a, b} : Finset L.sites) ⊆ {a, b, c}) - (ab : L.regionIdx ({a, b} : Finset L.sites)) - (cc : L.regionIdx (({a, b, c} : Finset L.sites) \ {a, b})) - (hc : c ∈ ({a, b, c} : Finset L.sites) \ {a, b}) : - L.regionIdxTripleEquiv hab hbc hac (L.combineIdx h_ab (ab, cc)) - = ((L.regionIdxPairEquiv hab ab).1, (L.regionIdxPairEquiv hab ab).2, cc ⟨c, hc⟩) := by - have hca : c ∉ ({a, b} : Finset L.sites) := (Finset.mem_sdiff.mp hc).2 - refine Prod.ext ?_ (Prod.ext ?_ ?_) <;> simp [hca] - -/-- **Compatibility of the triple factorisation with the `{b, c}`-cut.** The dual of -`regionIdxTripleEquiv_combineIdx` for the inclusion `{b, c} ⊆ {a, b, c}`: the `a`-value comes from -the complement part, the `b`- and `c`-values from the `{b, c}`-part via `regionIdxPairEquiv`. -/ -theorem regionIdxTripleEquiv_combineIdx_bc {a b c : L.sites} - (hab : a ≠ b) (hbc : b ≠ c) (hac : a ≠ c) - (h_bc : ({b, c} : Finset L.sites) ⊆ {a, b, c}) - (bc : L.regionIdx ({b, c} : Finset L.sites)) - (aa : L.regionIdx (({a, b, c} : Finset L.sites) \ {b, c})) - (ha : a ∈ ({a, b, c} : Finset L.sites) \ {b, c}) : - L.regionIdxTripleEquiv hab hbc hac (L.combineIdx h_bc (bc, aa)) - = (aa ⟨a, ha⟩, (L.regionIdxPairEquiv hbc bc).1, (L.regionIdxPairEquiv hbc bc).2) := by - have haa : a ∉ ({b, c} : Finset L.sites) := (Finset.mem_sdiff.mp ha).2 - refine Prod.ext ?_ (Prod.ext ?_ ?_) <;> simp [haa] - -/-- **Compatibility of the pair factorisation with the `{a}`-cut.** For `{a} ⊆ {a, b}`, the -`a`-value comes from the singleton part, the `b`-value from the complement part. -/ -theorem regionIdxPairEquiv_combineIdx {a b : L.sites} (hab : a ≠ b) - (h_a : ({a} : Finset L.sites) ⊆ {a, b}) - (ma : L.regionIdx ({a} : Finset L.sites)) - (mb : L.regionIdx (({a, b} : Finset L.sites) \ {a})) - (hb : b ∈ ({a, b} : Finset L.sites) \ {a}) : - L.regionIdxPairEquiv hab (L.combineIdx h_a (ma, mb)) - = (L.regionIdxSingletonEquiv a ma, mb ⟨b, hb⟩) := by - have hba : b ∉ ({a} : Finset L.sites) := (Finset.mem_sdiff.mp hb).2 - refine Prod.ext ?_ ?_ <;> simp [hba] - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean b/QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean deleted file mode 100644 index 48c97f9..0000000 --- a/QuantumSystem/Algebra/LocalNet/MatrixModel/TensorDecomposition.lean +++ /dev/null @@ -1,118 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony -public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct -public import QuantumSystem.ForMathlib.LinearAlgebra.Trace - -/-! -# Operator-level tensor decomposition of the local net - -The combinatorial index bijection `combineIdx h : regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ -regionIdx Λ_total` is promoted here to a genuine **tensor factorisation of operators on Hilbert -spaces**, rather than a matrix Kronecker product. - -For each finite region we take the Hilbert space `ℋ Λ := EuclideanSpace ℂ (regionIdx Λ)` and -identify the local matrix algebra `𝔄(Λ) = localAlgebra Λ` with the operator algebra -`End ℂ (ℋ Λ)` via `opEquiv`. The index bijection then induces a Hilbert-space tensor isometry -`ℋ Λ ⊗ ℋ (Λ_total \ Λ) ≃ ℋ Λ_total`, conjugation by which assembles, with -`endTensorEndAlgEquiv`, into an algebra isomorphism - - `tensorEquiv h : End ℂ (ℋ Λ) ⊗ End ℂ (ℋ (Λ_total \ Λ)) ≃ₐ End ℂ (ℋ Λ_total)`. - -The isotony embedding is then literally "tensoring with the identity on the complement" -(`opEquiv_includeAlgebra`): `includeAlgebra h X` corresponds to `(op X) ⊗ 1`. --/ - -@[expose] public section - -open WithLp -open scoped TensorProduct Matrix - -namespace SiteIndexSystem - -variable (L : SiteIndexSystem) - -/-- The Hilbert space of a region: the Euclidean space on its index type. -/ -abbrev ℋ (Λ : Finset L.sites) : Type _ := EuclideanSpace ℂ (L.regionIdx Λ) - -/-- The local matrix algebra `𝔄(Λ)`, identified with the algebra of operators on the region -Hilbert space `ℋ Λ` (matrices acting by multiplication on `EuclideanSpace`). -/ -noncomputable def opEquiv (Λ : Finset L.sites) : - L.localAlgebra Λ ≃ₐ[ℂ] Module.End ℂ (L.ℋ Λ) := - Matrix.toLinAlgEquiv'.trans - ((EuclideanSpace.equiv (L.regionIdx Λ) ℂ).symm.toLinearEquiv.conjAlgEquiv ℂ) - -@[simp] -lemma ofLp_opEquiv (Λ : Finset L.sites) (X : L.localAlgebra Λ) (v : L.ℋ Λ) : - ofLp (L.opEquiv Λ X v) = X *ᵥ ofLp v := - rfl - -/-- The **operator tensor decomposition** induced by the index bijection `combineIdx h`: -`End ℂ (ℋ Λ) ⊗ End ℂ (ℋ (Λ_total \ Λ)) ≃ₐ End ℂ (ℋ Λ_total)`. It is the operator-algebra tensor -equivalence followed by conjugation along the Hilbert-space tensor isometry. -/ -noncomputable def tensorEquiv {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - Module.End ℂ (L.ℋ Λ) ⊗[ℂ] Module.End ℂ (L.ℋ (Λ_total \ Λ)) ≃ₐ[ℂ] - Module.End ℂ (L.ℋ Λ_total) := - TensorProduct.endTensorEndAlgEquiv.trans - ((EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).toLinearEquiv.conjAlgEquiv ℂ) - -/-- Action of `tensorEquiv` on an operator tensor: conjugate `f ⊗ g` (as `TensorProduct.map f g`) -by the Hilbert-space tensor isometry. -/ -lemma tensorEquiv_tmul_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (f : Module.End ℂ (L.ℋ Λ)) (g : Module.End ℂ (L.ℋ (Λ_total \ Λ))) (v : L.ℋ Λ_total) : - L.tensorEquiv h (f ⊗ₜ[ℂ] g) v - = EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h) - (TensorProduct.map f g - ((EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).symm v)) := by - rw [tensorEquiv, AlgEquiv.trans_apply, TensorProduct.endTensorEndAlgEquiv_tmul, - LinearEquiv.conjAlgEquiv_apply, LinearMap.comp_apply, LinearMap.comp_apply] - rfl - -/-- The inverse Hilbert-space tensor isometry sends a combined basis vector `single (combineIdx h -(a, b))` back to the pure tensor `single a ⊗ single b`. -/ -lemma combineIdx_tensorEquiv_symm_single {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (a : L.regionIdx Λ) (b : L.regionIdx (Λ_total \ Λ)) : - (EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).symm - (EuclideanSpace.single (L.combineIdx h (a, b)) (1 : ℂ)) - = EuclideanSpace.single a (1 : ℂ) ⊗ₜ[ℂ] EuclideanSpace.single b (1 : ℂ) := by - rw [← EuclideanSpace.tensorEquiv_single_tmul (𝕜 := ℂ) (L.combineIdx h) a b] - exact (EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).symm_apply_apply _ - -/-- Internal: isotony embedding as `(op X) ⊗ 1` against the operator tensor decomposition -`tensorEquiv`. The public, explicit-subspace form is `opEquiv_includeAlgebra` below. -/ -private theorem opEquiv_includeAlgebra_aux {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) : - L.opEquiv Λ_total (L.includeAlgebra h X) - = L.tensorEquiv h - (L.opEquiv Λ X ⊗ₜ[ℂ] (1 : Module.End ℂ (L.ℋ (Λ_total \ Λ)))) := by - refine (EuclideanSpace.basisFun (L.regionIdx Λ_total) ℂ).toBasis.ext fun s' => ?_ - obtain ⟨⟨a', b'⟩, rfl⟩ := (L.combineIdx h).surjective s' - rw [OrthonormalBasis.coe_toBasis, EuclideanSpace.basisFun_apply] - apply WithLp.ofLp_injective (p := 2) - funext s - obtain ⟨⟨a, b⟩, rfl⟩ := (L.combineIdx h).surjective s - rw [tensorEquiv_tmul_apply, L.combineIdx_tensorEquiv_symm_single h a' b', - TensorProduct.map_tmul, Module.End.one_apply, EuclideanSpace.ofLp_tensorEquiv_tmul, - Equiv.symm_apply_apply, ofLp_opEquiv, ofLp_opEquiv, PiLp.ofLp_single, PiLp.ofLp_single] - simp - -/-- The bipartition of the total Hilbert space induced by `combineIdx h`, with the complementary -factor `ℋ (Λ_total \ Λ)` as the (traced-out) second factor. Feeding this to -`LinearMap.partialTrace` / `LinearMap.ampliate` names the traced-out subspace explicitly. -/ -noncomputable def regionBipartition {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.ℋ Λ_total ≃ₗ[ℂ] L.ℋ Λ ⊗[ℂ] L.ℋ (Λ_total \ Λ) := - (EuclideanSpace.tensorEquiv (𝕜 := ℂ) (L.combineIdx h)).toLinearEquiv.symm - -/-- **Isotony is the ampliation along the named bipartition**: `includeAlgebra h X` acts as `X` on -`ℋ Λ` and the identity on the traced-out factor `ℋ (Λ_total \ Λ)`. This is the formal sense in which -`combineIdx` realises the tensor factorisation, with the complementary subspace named by -`regionBipartition h`. -/ -theorem opEquiv_includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (X : L.localAlgebra Λ) : - L.opEquiv Λ_total (L.includeAlgebra h X) - = LinearMap.ampliate (L.regionBipartition h) (L.opEquiv Λ X) := by - rw [L.opEquiv_includeAlgebra_aux, LinearMap.ampliate, tensorEquiv, AlgEquiv.trans_apply, - TensorProduct.endTensorEndAlgEquiv_tmul, regionBipartition, LinearEquiv.symm_conjAlgEquiv, - LinearEquiv.symm_symm] - -end SiteIndexSystem diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 17ba3a9..5df7b9e 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -12,8 +12,7 @@ This file contains the abstract **local net** data: finite regions are assigned with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms. The quasi-local algebra built from a net lives in `LocalNet.QuasiLocalAlgebra`; covariance data and -its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. The finite-dimensional -matrix net generated by a `SiteIndexSystem` is packaged in `LocalNet.MatrixModel.Net`. +its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. -/ @[expose] public section @@ -21,8 +20,7 @@ matrix net generated by a `SiteIndexSystem` is packaged in `LocalNet.MatrixModel /-- A **local net of C⋆-algebras** over the finite regions of a site set `sites`: the assignment `Λ ↦ 𝔄(Λ)` together with isotony embeddings `incl : 𝔄(Λ) →⋆ₐ[ℂ] 𝔄(Λ')` for `Λ ⊆ Λ'`, functorial (`incl_refl`/`incl_trans`) and local (`locality`). This is the Haag–Kastler net - structure for a lattice of sites; the matrix lattice net is one instance via - `SiteIndexSystem.toLocalNet`. -/ + structure for a lattice of sites. -/ structure LocalNet (sites : Type*) [DecidableEq sites] where /-- The local C⋆-algebra `𝔄(Λ)` assigned to a finite region. -/ algebra : Finset sites → Type* diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean index df6d5f9..5b2b7bc 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean @@ -9,8 +9,7 @@ public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion # The quasi-local algebra of a local net The **algebra of local observables** and the **quasi-local C⋆-algebra** of an abstract local net -`LocalNet`. These constructions apply to *any* local net; the concrete finite-dimensional matrix -model that instantiates them lives in `LocalNet.MatrixModel.Net`. +`LocalNet`. These constructions apply to *any* local net. * `LocalNet.quasiLocalAlgebra` is the algebraic inductive limit `‾⋃_Λ 𝔄(Λ)` of the local algebras along the isotony embeddings, with cocone `ιLocal`, exhaustion (`exists_ιLocal`) and locality @@ -36,8 +35,7 @@ variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) /-! ### Algebra of local observables -These constructions apply to any abstract local net. The concrete `SiteIndexSystem` wrappers are -built on `SiteIndexSystem.toLocalNet` in `LocalNet.MatrixModel.Net`. +These constructions apply to any abstract local net. -/ /-- The **algebra of local observables** of the net: the algebraic inductive limit of the local diff --git a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean new file mode 100644 index 0000000..8e30f3e --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean @@ -0,0 +1,142 @@ +module + +public import QuantumSystem.Algebra.LocalNet.Net +public import QuantumSystem.ForMathlib.LinearAlgebra.Trace +public import Mathlib.Analysis.InnerProductSpace.Adjoint +public import Mathlib.Analysis.InnerProductSpace.TensorProduct + +/-! +# The split property and the tensor decomposition of a local net + +This file implements the **split property** for an abstract local net `LocalNet` and derives, +*without committing to any particular representation*, the **tensor factorisation of the action +space** and the **partial trace** that it induces. + +In the operator-algebraic literature the split property of an inclusion `𝔄(Λ) ⊆ 𝔄(Λ')` is the +existence of an intermediate type I factor `𝔄(Λ) ⊆ N ⊆ 𝔄(Λ')`; in its spatial / standard form +(Doplicher–Longo standard split inclusion, Fewster 2016 eqns (12)–(13), Matsui 2011 eqns +(2.1)–(2.2)) this is equivalent to a factorisation of the Hilbert space the algebra acts on, +`ℋ Λ' ≅ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)`, under which `𝔄(Λ)` acts as `B(ℋ Λ) ⊗ 1`. We take this spatial form as +the definition: a `Split` structure assigns to each region a finite-dimensional action space +`ℋ Λ`, identifies `𝔄(Λ)` with the type I factor `End ℂ (ℋ Λ)` (`act`), and presents each isotony +embedding `incl h` as the **ampliation** `X ↦ X ⊗ 1` along a tensor factorisation `decomp h` +(`act_incl`). + +From this hypothesis we derive the consequences that the literature uses: + +* `Split.decomp` is the tensor factorisation of the action space itself; +* `Split.partialTrace` is the partial trace on the action space (trace out the complementary + factor), reusing `LinearMap.partialTrace` from `ForMathlib.LinearAlgebra.Trace`; +* `Split.restrict` transports it to a marginal map `𝔄(Λ') →ₗ 𝔄(Λ)` on the algebra; +* `Split.restrict_incl_mul` is the conditional-expectation / partial-trace pull-out + `restrict (incl x * y) = x * restrict y`, the algebraic heart of statistical independence. + +None of this requires von Neumann algebra theory: the partial trace and the ampliation are the +purely linear-algebraic operators of `ForMathlib.LinearAlgebra.Trace`, parameterised by the +explicit decomposition `decomp h`. The split factorisation is carried as spatial data on the +abstract net (`act`/`decomp`/`act_incl`/`act_incl_compl`), not committed to any concrete model. + +## References + +* Matsui 2011 (`https://arxiv.org/abs/1109.5778`) §2, eqns (2.1)–(2.4). +* Fewster 2016 (`https://arxiv.org/abs/1601.06936`) eqns (12)–(13). +-/ + +@[expose] public section + +open scoped TensorProduct + +namespace LocalNet + +variable {sites : Type*} [DecidableEq sites] + +/-- A **split structure** on a local net `N` over a family of finite-dimensional action spaces +`ℋ`: the spatial form of the split property. Each local algebra is identified with the type I +factor of operators on its action space (`act : 𝔄(Λ) ≃ₐ End ℂ (ℋ Λ)`), and each isotony +embedding is the ampliation `X ↦ X ⊗ 1` along a tensor factorisation of the action space +`decomp h : ℋ Λ' ≃ₗ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)` (`act_incl`). This is the Doplicher–Longo standard split +inclusion (Fewster 2016 eqns (12)–(13)) / Matsui 2011 eqn (2.2) read as a hypothesis: it holds for +some nets and fails for others, and there is no universal proof, so it is carried as data. -/ +structure Split (N : LocalNet sites) (ℋ : Finset sites → Type*) + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] where + /-- Each local algebra `𝔄(Λ)` is the type I factor `End ℂ (ℋ Λ)` of operators on its action + space, `*`-isomorphically (the `*`-structure is recorded by `act_star`). -/ + act : ∀ Λ, N.algebra Λ ≃ₐ[ℂ] Module.End ℂ (ℋ Λ) + /-- `act` is a `*`-isomorphism: it intertwines the C⋆-involution of `𝔄(Λ)` with the adjoint on + `End ℂ (ℋ Λ)`. Together with `act` this is the spatial split property's type I identification + `𝔄(Λ) ≅ B(ℋ Λ)` as C⋆-algebras (not merely as algebras). -/ + act_star : ∀ {Λ : Finset sites} (x : N.algebra Λ), act Λ (star x) = star (act Λ x) + /-- The **tensor factorisation of the action space** `ℋ Λ' ≅ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)` for an + inclusion `Λ ⊆ Λ'`. This is the spatial content of the split property. -/ + decomp : ∀ {Λ Λ' : Finset sites}, Λ ⊆ Λ' → (ℋ Λ' ≃ₗ[ℂ] ℋ Λ ⊗[ℂ] ℋ (Λ' \ Λ)) + /-- The factorisation is a **unitary** (norm-preserving): the Hilbert space splits *isometrically* + as `ℋ Λ' ≅ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)`. This is what makes the induced marginal a quantum channel + (the partial trace of a positive operator stays positive); see `decompᵢ`. -/ + decomp_norm : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : ℋ Λ'), ‖decomp h x‖ = ‖x‖ + /-- **Isotony is the ampliation**: under the identification `act`, the isotony embedding + `incl h` acts as `X ↦ X ⊗ 1` along the factorisation `decomp h` (Matsui eqn (2.2)). -/ + act_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), + act Λ' (N.incl h x) = LinearMap.ampliate (decomp h) (act Λ x) + /-- **The complementary region acts on the complementary factor**: under the identification + `act`, the isotony embedding of the complement `Λ' ∖ Λ` acts as `Y ↦ 1 ⊗ Y` along the + factorisation `decomp h`. This is the second half of the spatial split property (Fewster 2016 + eqns (12)–(13)): the standard split inclusion factorises `ℋ Λ'` so that *both* `𝔄(Λ)` and + `𝔄(Λ' ∖ Λ)` act canonically on their respective tensor factors. It is genuine spatial data: + the bare net axioms and `act_incl` pin the complement action only up to an inner unitary on + the complementary factor (Skolem–Noether), and this field fixes that gauge to the canonical + one, as the standard-form factorisation does. -/ + act_incl_compl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ' \ Λ)), + act Λ' (N.incl Finset.sdiff_subset y) = LinearMap.coampliate (decomp h) (act (Λ' \ Λ) y) + +namespace Split + +variable {N : LocalNet sites} {ℋ : Finset sites → Type*} + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] + (S : Split N ℋ) + +/-- The tensor factorisation `decomp h` as a **unitary** (`LinearIsometryEquiv`), using the +norm-preservation witness `decomp_norm`. This is the Hilbert-space tensor isometry +`U : ℋ Λ' ≃ₗᵢ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)` of the spatial split property (Fewster 2016 eqn (13)). -/ +noncomputable def decompᵢ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + ℋ Λ' ≃ₗᵢ[ℂ] ℋ Λ ⊗[ℂ] ℋ (Λ' \ Λ) := + { S.decomp h with norm_map' := S.decomp_norm h } + +@[simp] theorem decompᵢ_toLinearEquiv {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + (S.decompᵢ h).toLinearEquiv = S.decomp h := + rfl + +/-- The **partial trace on the action space** induced by the split factorisation: trace out the +complementary factor `ℋ (Λ' ∖ Λ)` and retain `ℋ Λ`. This is `LinearMap.partialTrace` paired with +the tensor decomposition `decomp h`. -/ +noncomputable def partialTrace {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + Module.End ℂ (ℋ Λ') →ₗ[ℂ] Module.End ℂ (ℋ Λ) := + LinearMap.partialTrace (S.decomp h) + +/-- The **marginal map** `𝔄(Λ') →ₗ 𝔄(Λ)` of the net: the partial trace on the action space +transported to the algebra along `act`. This is the abstract, representation-free analogue of +`Matrix.restrict` (partial trace of a density matrix onto the subregion). -/ +noncomputable def restrict {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + N.algebra Λ' →ₗ[ℂ] N.algebra Λ := + (S.act Λ).symm.toLinearMap ∘ₗ LinearMap.partialTrace (S.decomp h) ∘ₗ (S.act Λ').toLinearMap + +theorem restrict_apply {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra Λ') : + S.restrict h y = (S.act Λ).symm (LinearMap.partialTrace (S.decomp h) (S.act Λ' y)) := + rfl + +/-- **Partial-trace pull-out** (conditional-expectation property): tracing the complement out of +`incl h x * y` factors the embedded `x` out of the marginal, +`restrict h (incl h x * y) = x * restrict h y`. This is the algebraic heart of the statistical +independence supplied by the split property (Fewster 2016 eqn (3)); it is the Heisenberg-picture +trace identity `Tr_B((X ⊗ 1) · ρ) = X · Tr_B ρ` (`LinearMap.partialTrace_ampliate_mul`) +transported to the net. -/ +theorem restrict_incl_mul {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') + (x : N.algebra Λ) (y : N.algebra Λ') : + S.restrict h (N.incl h x * y) = x * S.restrict h y := by + rw [restrict_apply, restrict_apply, map_mul (S.act Λ'), S.act_incl h x, + LinearMap.partialTrace_ampliate_mul, map_mul (S.act Λ).symm, AlgEquiv.symm_apply_apply] + +end Split + +end LocalNet diff --git a/QuantumSystem/Analysis/Channel/PartialTrace.lean b/QuantumSystem/Analysis/Channel/PartialTrace.lean index 7010237..7979f1d 100644 --- a/QuantumSystem/Analysis/Channel/PartialTrace.lean +++ b/QuantumSystem/Analysis/Channel/PartialTrace.lean @@ -7,10 +7,8 @@ public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace # Partial trace as a quantum channel (product index types) The **partial trace** on plain product index types `X × Y`, packaged as a completely positive -trace-preserving map (`QuantumChannel`). This is the `SiteIndexSystem`-free analogue of -`Matrix.QuantumChannel.restrict` (`Analysis/Matrix/PartialTrace.lean`): it traces out the right -factor `Y` of a matrix on `X × Y`, leaving a matrix on `X`. The construction mirrors the region -version with `SiteIndexSystem.combineIdx (a, b)` replaced by the plain pair `(x, y)`. +trace-preserving map (`QuantumChannel`): it traces out the right factor `Y` of a matrix on `X × Y`, +leaving a matrix on `X`. We also package conjugation by an index equivalence (`reindexₗ`) as a channel, and compose the two into the trace-out-`C` channel `QuantumChannel.traceOutC : QuantumChannel (A × B × C) (A × B)`, diff --git a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean index 0292aba..683b03a 100644 --- a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean +++ b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean @@ -26,9 +26,7 @@ This file is the hub for **Kronecker-product calculus on bipartite matrices**: The retained subsystem is determined by the codomain of the chosen equivalence `e : X ≃ A × B`. For native product types, `partialTrace (Equiv.refl (n × m))` retains the `n` factor, while `partialTrace (Equiv.prodComm n m)` retains the -`m` factor. SiteIndexSystem-facing theorems should instead expose the split subset -`Λ ⊆ Λ_total` (and its complement) explicitly, and use these matrix-level lemmas -only after reindexing by `SiteIndexSystem.combineIdx`. +`m` factor. The proof of the log-tensor identity uses the spectral decomposition of `A ⊗ B` constructed explicitly from spectral decompositions of `A` and `B`, combined @@ -48,9 +46,6 @@ a unitary). * `Matrix.kronecker_eq_unitary_conj_diagonal` — Kronecker spectral decomposition. * `Matrix.cfc_log_kronecker_posDef` — the log-tensor identity. * `Matrix.partialTrace_apply` — entrywise unfolding of the equivalence-indexed partial trace. -* `Matrix.restrict_eq_partialTrace_combineIdx` / - `Matrix.restrict_compl_eq_partialTrace_combineIdx` — SiteIndexSystem restriction as an - equivalence-indexed partial trace. * `Matrix.trace_mul_kronecker_one_right` — `Tr(ρ · (X ⊗ 1)) = Tr((partialTrace (Equiv.refl (n × m)) ρ) · X)`. * `Matrix.trace_mul_kronecker_one_left` — diff --git a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean b/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean index c115d7b..e7f0037 100644 --- a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean +++ b/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean @@ -12,8 +12,9 @@ product index type `n × m`: `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -This is `SiteIndexSystem`-free; it is the analytic core reused both by the AQFT strong-subadditivity proof -(`Analysis/Entropy/SSA.lean`) and by the product-form proof (`Analysis/Entropy/SSAProduct.lean`). +It is representation-free; the analytic core reused both by the product-form proof +(`Analysis/Entropy/StrongSubadditivityProduct.lean`) and, via transport, by the abstract split-net +proof (`Analysis/Entropy/SplitSSA.lean`). -/ @[expose] public section diff --git a/QuantumSystem/Analysis/Entropy/Regularize.lean b/QuantumSystem/Analysis/Entropy/Regularize.lean deleted file mode 100644 index c3ca5be..0000000 --- a/QuantumSystem/Analysis/Entropy/Regularize.lean +++ /dev/null @@ -1,89 +0,0 @@ -module - -public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy -public import QuantumSystem.Analysis.Matrix.PartialTrace - -/-! -# Regularization on a local net: compatibility with restriction - -The structural definitions (`maximallyMixed`, `regularize`, `regularize_eq_cfc`, -`regularize_mapEquiv`) and the entropy identities for regularized states -(`vonNeumannEntropy_regularize_eq_negMulLog_sum`, `tendsto_negMulLog_regularize_sum_zero`, -`vonNeumannEntropy_mapEquiv`) live in `State.lean` and `VonNeumannEntropy.lean`. - -This file specialises that infrastructure to a `SiteIndexSystem`. It proves compatibility of -regularization with restriction (partial trace), which is the key fact behind extending -PosDef-only theorems to PosSemidef. The cardinality factorisation for region indices now -lives next to `SiteIndexSystem.combineIdx` in `SiteIndexSystem/Basic.lean`. --/ - -@[expose] public section - -open scoped ComplexOrder - -/-! ### Regularization commutes with restriction - -The marginal of a regularized state equals the regularized marginal: -`restrict h (regularize ρ ε) = regularize (restrict h ρ) ε`. - -This is the key fact behind the "regularization respects partial trace" property -used in extending PosDef-only theorems to PosSemidef. -/ - -namespace Matrix - -/-- `Matrix.restrict h` of the maximally-mixed state at `Λ_total` equals the - maximally-mixed state at `Λ`, after dimension cancellation. -/ -theorem restrict_maximallyMixed {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) [Nonempty (L.regionIdx Λ)] [Nonempty (L.regionIdx Λ_total)] : - Matrix.restrict h (DensityMatrix.maximallyMixed (n := L.regionIdx Λ_total)).toMatrix = - (DensityMatrix.maximallyMixed (n := L.regionIdx Λ)).toMatrix := by - have hcomp_nonempty : Nonempty (L.regionIdx (Λ_total \ Λ)) := by - obtain ⟨x⟩ := ‹Nonempty (L.regionIdx Λ_total)› - exact ⟨((L.combineIdx h).symm x).2⟩ - rw [DensityMatrix.maximallyMixed_toMatrix, - DensityMatrix.maximallyMixed_toMatrix] - rw [Matrix.restrict_smul, Matrix.restrict_one] - rw [smul_smul] - congr 1 - have hdΛ : (Fintype.card (L.regionIdx Λ) : ℂ) ≠ 0 := by - exact_mod_cast (Fintype.card_pos (α := L.regionIdx Λ)).ne' - have hdComp : (Fintype.card (L.regionIdx (Λ_total \ Λ)) : ℂ) ≠ 0 := by - exact_mod_cast (Fintype.card_pos (α := L.regionIdx (Λ_total \ Λ))).ne' - rw [SiteIndexSystem.card_regionIdx_total (L := L) h] - have h_inv_mul : - ((((Fintype.card (L.regionIdx Λ) : ℂ) * - (Fintype.card (L.regionIdx (Λ_total \ Λ)) : ℂ)))⁻¹) * - (Fintype.card (L.regionIdx (Λ_total \ Λ)) : ℂ) = - (Fintype.card (L.regionIdx Λ) : ℂ)⁻¹ := by - field_simp [hdΛ, hdComp] - simpa [Nat.cast_mul] using h_inv_mul - -end Matrix - -namespace DensityMatrix - -/-- The regularization commutes with `restrict` (Matrix-level): - `restrict h (regularize ρ ε).toMatrix = (regularize (restrict h ρ) ε).toMatrix`. -/ -theorem regularize_restrict_toMatrix {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) [Nonempty (L.regionIdx Λ)] [Nonempty (L.regionIdx Λ_total)] - (ρ : L.densityMatrix Λ_total) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : - Matrix.restrict h (regularize ρ hε hε').toMatrix = - (regularize (restrict h ρ) hε hε').toMatrix := by - rw [regularize_toMatrix, regularize_toMatrix] - rw [DensityMatrix.restrict_toMatrix] - rw [(Matrix.restrict h).map_add] - rw [(Matrix.restrict h).map_smul, (Matrix.restrict h).map_smul] - rw [Matrix.restrict_maximallyMixed h] - -/-- The regularization commutes with `restrict` (DensityMatrix-level): - `(regularize ρ ε).restrict h = regularize (restrict h ρ) ε`. -/ -theorem regularize_restrict {L : SiteIndexSystem} {Λ Λ_total : Finset L.sites} - (h : Λ ⊆ Λ_total) [Nonempty (L.regionIdx Λ)] [Nonempty (L.regionIdx Λ_total)] - (ρ : L.densityMatrix Λ_total) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : - restrict h (regularize ρ hε hε') = - regularize (restrict h ρ) hε hε' := by - apply ext - rw [DensityMatrix.restrict_toMatrix] - exact regularize_restrict_toMatrix h ρ hε hε' - -end DensityMatrix diff --git a/QuantumSystem/Analysis/Entropy/SplitEntropy.lean b/QuantumSystem/Analysis/Entropy/SplitEntropy.lean new file mode 100644 index 0000000..ea6eb53 --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/SplitEntropy.lean @@ -0,0 +1,45 @@ +module + +public import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Basic +public import Mathlib.Analysis.SpecialFunctions.Log.NegMulLog +public import QuantumSystem.Analysis.Entropy.SplitTrace + +/-! +# Von Neumann entropy on a split net + +The von Neumann entropy of a state of a split net, stated **representation-free** on the local +C⋆-algebra. The local algebra `N.algebra Λ` of a split net is a unital C⋆-algebra, so it carries +the continuous functional calculus `cfc`; combined with the split trace `LocalNet.Split.trace` +this defines + + `S(ρ) = Tr (negMulLog ρ) = -Tr (ρ log ρ)`, + +exactly mirroring the matrix definition `Matrix.vonNeumannEntropy` (`vonNeumannEntropy_eq_cfc_re`) +but with no index basis. Here `Real.negMulLog x = -x * log x` is Mathlib's entropy integrand, with +the `0 log 0 = 0` convention built in. + +Its quantitative properties (non-negativity, strong subadditivity) are obtained in later files by +transporting the matrix theory along an orthonormal basis of the action space. +-/ + +@[expose] public section + +namespace LocalNet.Split + +variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] + (S : Split N ℋ) + +/-- **Von Neumann entropy** of a state `ρ` of a split net at region `Λ`: +`S(ρ) = Tr (negMulLog ρ)`, the representation-free analogue of `Matrix.vonNeumannEntropy`. The +trace is the split trace `Split.trace` and `negMulLog ρ` is the continuous functional calculus of +`Real.negMulLog` on the local C⋆-algebra. -/ +noncomputable def entropy {Λ : Finset sites} (ρ : N.algebra Λ) : ℝ := + (S.trace Λ (cfc Real.negMulLog ρ)).re + +theorem entropy_def {Λ : Finset sites} (ρ : N.algebra Λ) : + S.entropy ρ = (S.trace Λ (cfc Real.negMulLog ρ)).re := + rfl + +end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean new file mode 100644 index 0000000..6bc989e --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean @@ -0,0 +1,101 @@ +module + +public import QuantumSystem.Analysis.Entropy.SplitTransport +public import QuantumSystem.Analysis.Entropy.RelativeEntropy + +/-! +# Relative entropy on a split net + +The **quantum relative entropy** of two states of a split net, stated representation-free on the +local C⋆-algebra. Since the split property makes each local algebra a type I factor (`act`), a state +is a density operator and the Araki relative entropy coincides with the density-operator relative +entropy `D(ρ ‖ σ) = Tr (ρ (log ρ - log σ))`; we obtain it by transporting to the matrix +representation `toMatrix` and reusing `Matrix.relativeEntropy`. + +The key inequality (the **data-processing inequality** under the marginal `restrict`) is the engine +of strong subadditivity; it is established in `SplitSSA` via the transported quantum channel. +-/ + +@[expose] public section + +open scoped MatrixOrder ComplexOrder + +namespace LocalNet.Split + +variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] + (S : Split N ℋ) + +/-- **Quantum relative entropy** `D(ρ ‖ σ)` of two states of the split net at region `Λ`, defined +by transporting to the matrix representation (`toDensityMatrix`) and reusing `Matrix.relativeEntropy` +(for the type I factor this is the Araki relative entropy). -/ +noncomputable def relativeEntropy {Λ : Finset sites} {ρ σ : N.algebra Λ} + (hρ : S.IsDensity ρ) (hσ : S.IsDensity σ) : EReal := + Matrix.relativeEntropy (S.toDensityMatrix hρ) (S.toDensityMatrix hσ) + +/-- Relative entropy is **non-negative** (Klein's inequality), transported from the matrix result. -/ +theorem relativeEntropy_nonneg {Λ : Finset sites} {ρ σ : N.algebra Λ} + (hρ : S.IsDensity ρ) (hσ : S.IsDensity σ) : + 0 ≤ S.relativeEntropy hρ hσ := + Matrix.relativeEntropy_nonneg _ _ + +/-- The **transported marginal as a matrix map** `M ↦ toMatrix (restrict (toMatrix.symm M))`: the +partial-trace marginal `restrict h` read through the matrix representation of the type I factors. -/ +noncomputable def restrictChannelMap {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + Matrix (Fin (Module.finrank ℂ (ℋ Λ'))) (Fin (Module.finrank ℂ (ℋ Λ'))) ℂ →ₗ[ℂ] + Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ))) ℂ where + toFun M := S.toMatrix Λ (S.restrict h ((S.toMatrix Λ').symm M)) + map_add' M M' := by simp only [map_add] + map_smul' c M := by simp only [map_smul, RingHom.id_apply] + +@[simp] theorem restrictChannelMap_apply {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') + (M : Matrix (Fin (Module.finrank ℂ (ℋ Λ'))) (Fin (Module.finrank ℂ (ℋ Λ'))) ℂ) : + S.restrictChannelMap h M = S.toMatrix Λ (S.restrict h ((S.toMatrix Λ').symm M)) := + rfl + +/-- The transported marginal is a **quantum channel** (completely positive + trace preserving): +complete positivity from the matrix Kraus form `toMatrix_restrict_eq_sum_kraus`, trace preservation +from `trace_restrict`. This realises the partial trace as a CPTP map, as required for the +data-processing inequality. -/ +theorem isQuantumChannel_restrictChannelMap {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + Matrix.IsQuantumChannel (S.restrictChannelMap h) where + completelyPositive := by + refine ⟨Module.finrank ℂ (ℋ (Λ' \ Λ)), S.restrictKraus h, fun M => ?_⟩ + rw [restrictChannelMap_apply, S.toMatrix_restrict_eq_sum_kraus h, + StarAlgEquiv.apply_symm_apply] + tracePreserving := by + intro M + rw [restrictChannelMap_apply, ← S.trace_eq_matrixTrace, S.trace_restrict h, + S.trace_eq_matrixTrace, StarAlgEquiv.apply_symm_apply] + +/-- The transported marginal packaged as a `QuantumChannel`. -/ +noncomputable def restrictMatrixChannel {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : + Matrix.QuantumChannel (Fin (Module.finrank ℂ (ℋ Λ'))) (Fin (Module.finrank ℂ (ℋ Λ))) := + ⟨S.restrictChannelMap h, S.isQuantumChannel_restrictChannelMap h⟩ + +/-- The matrix channel transports `toDensityMatrix` along the marginal: it sends the density matrix +of `ρ` to the density matrix of `restrict h ρ`. -/ +theorem restrictMatrixChannel_apply {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') + {ρ : N.algebra Λ'} (hρ : S.IsDensity ρ) : + S.restrictMatrixChannel h (S.toDensityMatrix hρ) + = S.toDensityMatrix (S.restrict_isDensity h hρ) := by + apply DensityMatrix.ext + change S.restrictChannelMap h (S.toMatrix Λ' ρ) = S.toMatrix Λ (S.restrict h ρ) + rw [restrictChannelMap_apply, StarAlgEquiv.symm_apply_apply] + +/-- **Data-processing inequality for the marginal**: the quantum relative entropy of two states does +not increase under the marginal `restrict h`, +`D(restrict ρ ‖ restrict σ) ≤ D(ρ ‖ σ)`. This is monotonicity of relative entropy under the +partial-trace quantum channel `restrictMatrixChannel`; it is the analytic engine of strong +subadditivity, stated representation-free on the split net. -/ +theorem relativeEntropy_restrict_le {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') + {ρ σ : N.algebra Λ'} (hρ : S.IsDensity ρ) (hσ : S.IsDensity σ) : + S.relativeEntropy (S.restrict_isDensity h hρ) (S.restrict_isDensity h hσ) + ≤ S.relativeEntropy hρ hσ := by + have key := Matrix.relativeEntropy_channel_le (S.restrictMatrixChannel h) + (S.toDensityMatrix hρ) (S.toDensityMatrix hσ) + rw [S.restrictMatrixChannel_apply h hρ, S.restrictMatrixChannel_apply h hσ] at key + exact key + +end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitSSA.lean b/QuantumSystem/Analysis/Entropy/SplitSSA.lean new file mode 100644 index 0000000..8b3b9ec --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/SplitSSA.lean @@ -0,0 +1,713 @@ +module + +public import QuantumSystem.Analysis.Entropy.SplitTransport +public import QuantumSystem.Analysis.Entropy.StrongSubadditivityProduct + +/-! +# Strong subadditivity on a split net + +The **strong subadditivity** of the von Neumann entropy, stated representation-free on the abstract +operator-algebraic split net `LocalNet.Split`, assembled from: + +* the **data-processing inequality** `relativeEntropy_restrict_le` (the analytic engine); +* the **tensor commutant theorem** `LinearMap.exists_map_one_of_commute_map_id`, which makes the + partial trace depend only on the subsystem traced out (factorisation uniqueness); +* **basis-independence of the von Neumann entropy** `vonNeumannEntropy_toDensityMatrixBasis`, + which lets us read marginals in a tensor-factorised orthonormal basis; +* the matrix-level `DensityMatrix.vonNeumannEntropy_SSA_product`. + +The first brick is the **partial-trace correspondence**: in the orthonormal basis pulled back from a +tensor factorisation, the matrix partial trace `Matrix.traceRight` realises the operator partial +trace `LinearMap.partialTrace`. +-/ + +@[expose] public section + +open scoped TensorProduct ComplexOrder MatrixOrder + +namespace LinearMap + +variable {ℋ A B : Type*} + [NormedAddCommGroup ℋ] [InnerProductSpace ℂ ℋ] [FiniteDimensional ℂ ℋ] + [NormedAddCommGroup A] [InnerProductSpace ℂ A] [FiniteDimensional ℂ A] + [NormedAddCommGroup B] [InnerProductSpace ℂ B] [FiniteDimensional ℂ B] + +/-- **Partial-trace correspondence.** Read in the orthonormal basis of `ℋ` pulled back from the +tensor product basis `bA ⊗ bB` along a unitary factorisation `e : ℋ ≃ₗᵢ A ⊗ B`, the matrix partial +trace over the `B`-index (`Matrix.traceRight`) realises the operator partial trace +`LinearMap.partialTrace e`. -/ +theorem traceRight_toMatrixOrthonormal (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) + {κ ν : Type*} [Fintype κ] [DecidableEq κ] [Fintype ν] [DecidableEq ν] + (bA : OrthonormalBasis κ ℂ A) (bB : OrthonormalBasis ν ℂ B) (T : Module.End ℂ ℋ) : + Matrix.traceRight (LinearMap.toMatrixOrthonormal ((bA.tensorProduct bB).map e.symm) T) + = LinearMap.toMatrixOrthonormal bA (LinearMap.partialTrace e.toLinearEquiv T) := by + ext i j + rw [Matrix.traceRight_apply, LinearMap.toMatrixOrthonormal_apply_apply, partialTrace_apply, + ← inner_conj_symm (𝕜 := ℂ), TensorProduct.inner_partialTraceRight bB, map_sum] + refine Finset.sum_congr rfl fun k _ => ?_ + rw [LinearMap.toMatrixOrthonormal_apply_apply, OrthonormalBasis.map_apply, + OrthonormalBasis.tensorProduct_apply, OrthonormalBasis.map_apply, + OrthonormalBasis.tensorProduct_apply, AlgEquiv.apply_symm_apply, + LinearEquiv.conjAlgEquiv_apply_apply, + show (e.toLinearEquiv) (T (e.toLinearEquiv.symm (bA j ⊗ₜ[ℂ] bB k))) + = e (T (e.symm (bA j ⊗ₜ[ℂ] bB k))) from rfl, + ← e.inner_map_map (e.symm (bA i ⊗ₜ[ℂ] bB k)) (T (e.symm (bA j ⊗ₜ[ℂ] bB k))), + e.apply_symm_apply] + exact (inner_conj_symm _ _).symm + +/-- **Partial-trace correspondence, left factor.** Tracing out the *first* index (`Matrix.traceLeft`) +of the matrix in the basis pulled back from `bA ⊗ bB` along `e : ℋ ≃ₗᵢ A ⊗ B` realises the operator +partial trace along `e` post-composed with the tensor swap — i.e. tracing out the `A`-factor and +retaining `B`. This reads the `A`-marginal (`ptLeft`) of the tensor-factorised density matrix. -/ +theorem traceLeft_toMatrixOrthonormal (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) + {κ ν : Type*} [Fintype κ] [DecidableEq κ] [Fintype ν] [DecidableEq ν] + (bA : OrthonormalBasis κ ℂ A) (bB : OrthonormalBasis ν ℂ B) (T : Module.End ℂ ℋ) : + Matrix.traceLeft (LinearMap.toMatrixOrthonormal ((bA.tensorProduct bB).map e.symm) T) + = LinearMap.toMatrixOrthonormal bB + (LinearMap.partialTrace (e.trans (TensorProduct.commIsometry ℂ A B)).toLinearEquiv T) := by + have hswap : ((bA.tensorProduct bB).map e.symm).reindex (Equiv.prodComm κ ν) + = (bB.tensorProduct bA).map (e.trans (TensorProduct.commIsometry ℂ A B)).symm := by + apply DFunLike.ext + rintro ⟨j, i⟩ + simp only [OrthonormalBasis.reindex_apply, OrthonormalBasis.map_apply, + OrthonormalBasis.tensorProduct_apply, Equiv.prodComm_symm, Equiv.prodComm_apply, + Prod.swap_prod_mk, LinearIsometryEquiv.symm_trans, LinearIsometryEquiv.trans_apply, + TensorProduct.commIsometry_symm, TensorProduct.commIsometry_apply, + TensorProduct.comm_tmul] + rw [Matrix.traceLeft_eq_traceRight_prodComm, ← LinearMap.toMatrixOrthonormal_reindex, hswap, + LinearMap.traceRight_toMatrixOrthonormal] + +end LinearMap + +/-! ### Conjugation under a tensor congruence -/ + +/-- Conjugating an ampliation `N ⊗ M` by a tensor congruence `congr f g` distributes: +`(congr f g)-conj (N ⊗ M) = (f-conj N) ⊗ (g-conj M)`. -/ +theorem TensorProduct.congr_conjAlgEquiv_map {𝕜 E F G K : Type*} [Field 𝕜] + [AddCommGroup E] [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F] + [AddCommGroup G] [Module 𝕜 G] [AddCommGroup K] [Module 𝕜 K] + (f : E ≃ₗ[𝕜] F) (g : G ≃ₗ[𝕜] K) (N : Module.End 𝕜 E) (M : Module.End 𝕜 G) : + (TensorProduct.congr f g).conjAlgEquiv 𝕜 (TensorProduct.map N M) + = TensorProduct.map (f.conjAlgEquiv 𝕜 N) (g.conjAlgEquiv 𝕜 M) := by + rw [LinearEquiv.conjAlgEquiv_apply, LinearEquiv.conjAlgEquiv_apply, + LinearEquiv.conjAlgEquiv_apply] + apply TensorProduct.ext' + intro f' k' + simp [TensorProduct.map_tmul] + +/-- Conjugation by a composite equivalence is the composite of conjugations. -/ +theorem LinearEquiv.conjAlgEquiv_trans {𝕜 M₁ M₂ M₃ : Type*} [Field 𝕜] + [AddCommGroup M₁] [Module 𝕜 M₁] [AddCommGroup M₂] [Module 𝕜 M₂] + [AddCommGroup M₃] [Module 𝕜 M₃] (e : M₁ ≃ₗ[𝕜] M₂) (f : M₂ ≃ₗ[𝕜] M₃) + (T : Module.End 𝕜 M₁) : + (e.trans f).conjAlgEquiv 𝕜 T = f.conjAlgEquiv 𝕜 (e.conjAlgEquiv 𝕜 T) := by + rw [LinearEquiv.conjAlgEquiv_apply, LinearEquiv.conjAlgEquiv_apply, + LinearEquiv.conjAlgEquiv_apply] + ext x + simp [LinearMap.comp_assoc] + +/-- Conjugating an ampliation by the tensor commutativity isomorphism swaps the two factors. -/ +theorem TensorProduct.comm_conjAlgEquiv_map {𝕜 A B : Type*} [Field 𝕜] + [AddCommGroup A] [Module 𝕜 A] [AddCommGroup B] [Module 𝕜 B] + (f : Module.End 𝕜 A) (g : Module.End 𝕜 B) : + (TensorProduct.comm 𝕜 A B).conjAlgEquiv 𝕜 (TensorProduct.map f g) + = TensorProduct.map g f := by + rw [LinearEquiv.conjAlgEquiv_apply] + apply TensorProduct.ext' + intro b a + simp [TensorProduct.map_tmul] + +/-- Conjugating a nested ampliation `(f ⊗ g) ⊗ h` by the tensor associativity isomorphism +reassociates it to `f ⊗ (g ⊗ h)`. -/ +theorem TensorProduct.assoc_conjAlgEquiv_map {𝕜 A B C : Type*} [Field 𝕜] + [AddCommGroup A] [Module 𝕜 A] [AddCommGroup B] [Module 𝕜 B] [AddCommGroup C] [Module 𝕜 C] + (f : Module.End 𝕜 A) (g : Module.End 𝕜 B) (h : Module.End 𝕜 C) : + (TensorProduct.assoc 𝕜 A B C).conjAlgEquiv 𝕜 + (TensorProduct.map (TensorProduct.map f g) h) + = TensorProduct.map f (TensorProduct.map g h) := by + rw [LinearEquiv.conjAlgEquiv_apply] + apply TensorProduct.ext' + intro a bc + induction bc using TensorProduct.induction_on with + | zero => simp + | tmul b c => simp [TensorProduct.map_tmul] + | add y z hy hz => simp only [map_add, TensorProduct.tmul_add, hy, hz] + +/-! ### Naturality of the partial trace under relabelling the retained factor -/ + +section Naturality + +variable {R H K K' D : Type*} [Field R] + [AddCommGroup H] [Module R H] + [AddCommGroup K] [Module R K] [Module.Finite R K] [Module.Free R K] + [AddCommGroup K'] [Module R K'] [Module.Finite R K'] [Module.Free R K'] + [AddCommGroup D] [Module R D] [Module.Finite R D] [Module.Free R D] + +omit [Module.Finite R K] [Module.Free R K] [Module.Finite R K'] [Module.Free R K'] + [Module.Finite R D] [Module.Free R D] in +/-- `partialTraceRight` is natural under relabelling the retained (first) factor by `V`: it carries +the ampliation `V ⊗ 1` (here `LinearEquiv.conj V` on the first factor of the operator tensor) through +to conjugation by `V` of the result. -/ +theorem TensorProduct.partialTraceRight_map_conj (V : K ≃ₗ[R] K') + (S : Module.End R K ⊗[R] Module.End R D) : + TensorProduct.partialTraceRight + (TensorProduct.map (LinearEquiv.conj V).toLinearMap LinearMap.id S) + = (LinearEquiv.conj V) (TensorProduct.partialTraceRight S) := by + induction S using TensorProduct.induction_on with + | zero => simp + | tmul L Rr => simp only [TensorProduct.map_tmul, LinearMap.id_apply, + TensorProduct.partialTraceRight_tmul, map_smul, LinearEquiv.coe_coe] + | add S₁ S₂ h₁ h₂ => simp only [map_add, h₁, h₂] + +/-- Naturality of `endTensorEndAlgEquiv` under conjugation by `congr V 1`: it intertwines the +operator-level conjugation by `V ⊗ 1` with the tensor-level `conj V ⊗ id`. -/ +theorem TensorProduct.endTensorEndAlgEquiv_symm_conjAlgEquiv_congr (V : K ≃ₗ[R] K') + (S : Module.End R K ⊗[R] Module.End R D) : + (TensorProduct.endTensorEndAlgEquiv).symm + ((TensorProduct.congr V (LinearEquiv.refl R D)).conjAlgEquiv R + (TensorProduct.endTensorEndAlgEquiv S)) + = TensorProduct.map (LinearEquiv.conj V).toLinearMap LinearMap.id S := by + induction S using TensorProduct.induction_on with + | zero => simp + | tmul L Rr => + rw [TensorProduct.endTensorEndAlgEquiv_tmul, LinearEquiv.conjAlgEquiv_apply, + show (TensorProduct.congr V (LinearEquiv.refl R D)).toLinearMap + = TensorProduct.map V.toLinearMap LinearMap.id from by ext; simp, + show ((TensorProduct.congr V (LinearEquiv.refl R D)).symm.toLinearMap) + = TensorProduct.map V.symm.toLinearMap LinearMap.id from by + ext; simp [TensorProduct.congr_symm], + ← TensorProduct.map_comp, ← TensorProduct.map_comp, TensorProduct.map_tmul, LinearMap.id_apply, + AlgEquiv.symm_apply_eq, TensorProduct.endTensorEndAlgEquiv_tmul] + rfl + | add S₁ S₂ h₁ h₂ => simp only [map_add, h₁, h₂] + +/-- **Naturality of the partial trace.** Composing the factorisation `e : H ≃ₗ K ⊗ D` with a +relabelling `V ⊗ 1` of the retained factor conjugates the partial trace by `V`: +`Tr_D ((V ⊗ 1) ∘ e) = V ∘ (Tr_D e) ∘ V⁻¹`. Two factorisations differing by `V ⊗ 1` give unitarily +equivalent marginals — the operator content of factorisation uniqueness. -/ +theorem LinearMap.partialTrace_congr_conj (V : K ≃ₗ[R] K') (e : H ≃ₗ[R] K ⊗[R] D) + (T : Module.End R H) : + LinearMap.partialTrace (e ≪≫ₗ TensorProduct.congr V (LinearEquiv.refl R D)) T + = (LinearEquiv.conj V) (LinearMap.partialTrace e T) := by + rw [LinearMap.partialTrace_apply, LinearMap.partialTrace_apply] + have hcomp : (e ≪≫ₗ TensorProduct.congr V (LinearEquiv.refl R D)).conjAlgEquiv R T + = (TensorProduct.congr V (LinearEquiv.refl R D)).conjAlgEquiv R (e.conjAlgEquiv R T) := by + rw [LinearEquiv.conjAlgEquiv_apply, LinearEquiv.conjAlgEquiv_apply, + LinearEquiv.conjAlgEquiv_apply] + rfl + rw [hcomp, ← (TensorProduct.endTensorEndAlgEquiv).apply_symm_apply (e.conjAlgEquiv R T), + TensorProduct.endTensorEndAlgEquiv_symm_conjAlgEquiv_congr, TensorProduct.partialTraceRight_map_conj, + AlgEquiv.symm_apply_apply] + +/-- **The partial trace is invariant under a unitary relabelling of the traced-out factor.** +Composing `e : H ≃ₗ K ⊗ D` with `congr 1 U` (identity on the retained factor `K`, an isomorphism `U` +on the traced factor `D ≃ D'`) leaves the partial trace unchanged — the trace of the traced factor +is conjugation-invariant. This lets the `castIso`-relabelled factorisation `bcDirect` share its +partial trace with the canonical `BC`-marginal `restrict (decompᵢ (sdiff))`. -/ +theorem LinearMap.partialTrace_congr_right_id (e : H ≃ₗ[R] K ⊗[R] D) (U : D ≃ₗ[R] K') + (T : Module.End R H) : + LinearMap.partialTrace (e ≪≫ₗ TensorProduct.congr (LinearEquiv.refl R K) U) T + = LinearMap.partialTrace e T := by + rw [LinearMap.partialTrace_apply, LinearMap.partialTrace_apply, + LinearEquiv.conjAlgEquiv_trans e (TensorProduct.congr (LinearEquiv.refl R K) U) T, + ← (TensorProduct.endTensorEndAlgEquiv (R := R) (M := K) (N := D)).apply_symm_apply + (e.conjAlgEquiv R T)] + generalize (TensorProduct.endTensorEndAlgEquiv (R := R) (M := K) (N := D)).symm + (e.conjAlgEquiv R T) = W + induction W using TensorProduct.induction_on with + | zero => simp + | tmul Y Z => + rw [AlgEquiv.symm_apply_apply, TensorProduct.partialTraceRight_tmul, + TensorProduct.endTensorEndAlgEquiv_tmul, TensorProduct.congr_conjAlgEquiv_map, + ← TensorProduct.endTensorEndAlgEquiv_tmul, AlgEquiv.symm_apply_apply, + TensorProduct.partialTraceRight_tmul, + show U.conjAlgEquiv R Z = U.conj Z from rfl, LinearMap.trace_conj'] + congr 1 + | add W₁ W₂ h₁ h₂ => simp only [map_add, h₁, h₂] + +end Naturality + +/-! ### Factorisation uniqueness: extracting the relabelling isometry -/ + +section FactorizationUniqueness + +variable {K K' D : Type*} + [NormedAddCommGroup K] [InnerProductSpace ℂ K] [FiniteDimensional ℂ K] + [NormedAddCommGroup K'] [InnerProductSpace ℂ K'] [FiniteDimensional ℂ K'] + [NormedAddCommGroup D] [InnerProductSpace ℂ D] [FiniteDimensional ℂ D] + +omit [FiniteDimensional ℂ K] in +/-- A unitary `Φ : K ⊗ D ≃ₗᵢ K' ⊗ D` whose underlying map is an ampliation `V ⊗ 1` of a linear map +`V_lin` upgrades that `V_lin` to a **unitary** `V : K ≃ₗᵢ K'`: it is automatically an +isometric isomorphism. (`Φ = V ⊗ 1` with `Φ` unitary forces `V` unitary.) -/ +theorem exists_isometryEquiv_of_toLinearMap_eq_map [Nontrivial D] + (Φ : (K ⊗[ℂ] D) ≃ₗᵢ[ℂ] (K' ⊗[ℂ] D)) (V_lin : K →ₗ[ℂ] K') + (hΦ : Φ.toLinearEquiv.toLinearMap = TensorProduct.map V_lin LinearMap.id) : + ∃ V : K ≃ₗᵢ[ℂ] K', V.toLinearEquiv.toLinearMap = V_lin := by + obtain ⟨d₀, hd₀⟩ := exists_ne (0 : D) + have hdd : (inner ℂ d₀ d₀ : ℂ) ≠ 0 := by simp only [ne_eq, inner_self_eq_zero]; exact hd₀ + have hiso : ∀ k₁ k₂ : K, (inner ℂ (V_lin k₁) (V_lin k₂) : ℂ) = inner ℂ k₁ k₂ := by + intro k₁ k₂ + have h1 : (inner ℂ (Φ (k₁ ⊗ₜ[ℂ] d₀)) (Φ (k₂ ⊗ₜ[ℂ] d₀)) : ℂ) + = inner ℂ (k₁ ⊗ₜ[ℂ] d₀) (k₂ ⊗ₜ[ℂ] d₀) := Φ.inner_map_map _ _ + rw [show Φ (k₁ ⊗ₜ[ℂ] d₀) = V_lin k₁ ⊗ₜ[ℂ] d₀ by + rw [show Φ (k₁ ⊗ₜ[ℂ] d₀) = Φ.toLinearEquiv.toLinearMap (k₁ ⊗ₜ[ℂ] d₀) from rfl, hΦ]; simp, + show Φ (k₂ ⊗ₜ[ℂ] d₀) = V_lin k₂ ⊗ₜ[ℂ] d₀ by + rw [show Φ (k₂ ⊗ₜ[ℂ] d₀) = Φ.toLinearEquiv.toLinearMap (k₂ ⊗ₜ[ℂ] d₀) from rfl, hΦ]; simp, + TensorProduct.inner_tmul, TensorProduct.inner_tmul] at h1 + exact mul_right_cancel₀ hdd h1 + have hinj : Function.Injective V_lin := by + rw [← LinearMap.ker_eq_bot, LinearMap.ker_eq_bot'] + intro k hk + have := hiso k k + rw [hk] at this; simp only [inner_zero_left] at this + exact inner_self_eq_zero.mp this.symm + have hrank : Module.finrank ℂ K = Module.finrank ℂ K' := by + have := Φ.toLinearEquiv.finrank_eq + rw [Module.finrank_tensorProduct, Module.finrank_tensorProduct] at this + exact Nat.eq_of_mul_eq_mul_right Module.finrank_pos this + have hsurj : Function.Surjective V_lin := by + rw [← LinearMap.range_eq_top] + apply Submodule.eq_top_of_finrank_eq + rw [LinearMap.finrank_range_of_inj hinj, hrank] + let Ve : K ≃ₗ[ℂ] K' := LinearEquiv.ofBijective V_lin ⟨hinj, hsurj⟩ + refine ⟨{ Ve with norm_map' := fun k => ?_ }, rfl⟩ + rw [← Real.sqrt_sq (norm_nonneg (Ve k)), ← Real.sqrt_sq (norm_nonneg k)] + congr 1 + rw [← @inner_self_eq_norm_sq ℂ, ← @inner_self_eq_norm_sq ℂ] + exact congrArg Complex.re (hiso k k) + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [FiniteDimensional ℂ H] + +omit [FiniteDimensional ℂ H] in +/-- **Factorisation uniqueness.** Two unitary factorisations `e₁ : H ≃ₗᵢ K ⊗ D`, +`e₂ : H ≃ₗᵢ K' ⊗ D` that implement the *same* action of `End D` on `H` (`hcomm`: the transition +`e₁.symm.trans e₂` commutes with every `1 ⊗ f`) have partial traces over `D` that agree up to a +unitary `V : K ≃ₗᵢ K'`. The marginal of a state over a subsystem thus depends only on the subsystem, +not on the chosen factorisation of its complement. -/ +theorem factorization_uniqueness [Nontrivial D] + (e₁ : H ≃ₗᵢ[ℂ] (K ⊗[ℂ] D)) (e₂ : H ≃ₗᵢ[ℂ] (K' ⊗[ℂ] D)) + (hcomm : ∀ f : Module.End ℂ D, + (e₁.symm.trans e₂).toLinearEquiv.toLinearMap ∘ₗ TensorProduct.map LinearMap.id f + = TensorProduct.map LinearMap.id f ∘ₗ (e₁.symm.trans e₂).toLinearEquiv.toLinearMap) + (T : Module.End ℂ H) : + ∃ V : K ≃ₗᵢ[ℂ] K', + LinearMap.partialTrace e₂.toLinearEquiv T + = (LinearEquiv.conj V.toLinearEquiv) (LinearMap.partialTrace e₁.toLinearEquiv T) := by + set Φ : (K ⊗[ℂ] D) ≃ₗᵢ[ℂ] (K' ⊗[ℂ] D) := e₁.symm.trans e₂ with hΦdef + have hrank : Module.finrank ℂ K' = Module.finrank ℂ K := by + have := Φ.toLinearEquiv.finrank_eq + rw [Module.finrank_tensorProduct, Module.finrank_tensorProduct] at this + exact (Nat.eq_of_mul_eq_mul_right Module.finrank_pos this).symm + obtain ⟨W₀⟩ := + FiniteDimensional.nonempty_linearEquiv_of_finrank_eq (R := ℂ) (M := K') (M' := K) hrank + have hcomm2 : ∀ f : Module.End ℂ D, + (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) + ∘ₗ TensorProduct.map LinearMap.id f + = TensorProduct.map LinearMap.id f + ∘ₗ (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) := by + intro f + rw [LinearMap.comp_assoc, hcomm f, ← LinearMap.comp_assoc, ← LinearMap.comp_assoc] + congr 1 + rw [← TensorProduct.map_comp, ← TensorProduct.map_comp]; simp + obtain ⟨g, hg⟩ := LinearMap.exists_map_id_of_commute_map_one + (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) hcomm2 + have hVlin : Φ.toLinearEquiv.toLinearMap + = TensorProduct.map (W₀.symm.toLinearMap ∘ₗ g) LinearMap.id := by + have h2 : Φ.toLinearEquiv.toLinearMap = TensorProduct.map W₀.symm.toLinearMap LinearMap.id ∘ₗ + (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) := by + rw [← LinearMap.comp_assoc, ← TensorProduct.map_comp]; simp + rw [h2, hg, ← TensorProduct.map_comp]; simp + obtain ⟨V, hV⟩ := exists_isometryEquiv_of_toLinearMap_eq_map Φ _ hVlin + refine ⟨V, ?_⟩ + have hΦeq : Φ.toLinearEquiv = TensorProduct.congr V.toLinearEquiv (LinearEquiv.refl ℂ D) := by + apply LinearEquiv.toLinearMap_injective + rw [hVlin, ← hV]; ext; simp + have he₂ : e₂.toLinearEquiv = e₁.toLinearEquiv ≪≫ₗ Φ.toLinearEquiv := by + rw [hΦdef]; ext x; simp + rw [he₂, hΦeq, LinearMap.partialTrace_congr_conj] + +/-- Conjugating an operator by a unitary `V : K ≃ₗᵢ K'` and reading it in the `V`-image of an +orthonormal basis gives the *same matrix* as the original in the original basis. Hence the matrix — +and its von Neumann entropy — is unchanged by `conj V`. -/ +theorem toMatrixOrthonormal_conj_map {ι : Type*} [Fintype ι] [DecidableEq ι] + (V : K ≃ₗᵢ[ℂ] K') (b : OrthonormalBasis ι ℂ K) (X : Module.End ℂ K) : + LinearMap.toMatrixOrthonormal (b.map V) (LinearEquiv.conj V.toLinearEquiv X) + = LinearMap.toMatrixOrthonormal b X := by + ext i j + rw [LinearMap.toMatrixOrthonormal_apply_apply, LinearMap.toMatrixOrthonormal_apply_apply, + OrthonormalBasis.map_apply, OrthonormalBasis.map_apply, LinearEquiv.conj_apply_apply] + simp only [LinearIsometryEquiv.coe_toLinearEquiv] + rw [LinearIsometryEquiv.inner_map_map] + simp + +end FactorizationUniqueness + +/-! ### Reindexing the density matrix of a state -/ + +namespace LocalNet.Split + +variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] + (S : Split N ℋ) + +/-- Reindexing the orthonormal basis and then transporting the density matrix back along the same +equivalence is the identity: `(toDensityMatrixBasis (b.reindex e) hρ).mapEquiv e = +toDensityMatrixBasis b hρ`. Used to align the tensor-factorised basis with the `A × B × C` +positional index of `vonNeumannEntropy_SSA_product`. -/ +theorem toDensityMatrixBasis_reindex_mapEquiv {Λ : Finset sites} {ι ι' : Type*} + [Fintype ι] [DecidableEq ι] [Fintype ι'] [DecidableEq ι'] + (b : OrthonormalBasis ι ℂ (ℋ Λ)) (e : ι ≃ ι') {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + (S.toDensityMatrixBasis (b.reindex e) hρ).mapEquiv e = S.toDensityMatrixBasis b hρ := by + apply DensityMatrix.ext + rw [DensityMatrix.mapEquiv_toMatrix, S.toDensityMatrixBasis_toMatrix, + S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, S.toMatrixBasis_apply, + LinearMap.toMatrixOrthonormal_reindex] + ext a b' + simp [Matrix.submatrix_apply, Matrix.reindex_apply] + +/-- The canonical unitary transport `ℋ s ≃ₗᵢ ℋ t` along a propositional equality of regions +`s = t`. (Both action spaces are literally the same once `s = t` is substituted.) -/ +noncomputable def castEquiv {s t : Finset sites} (hst : s = t) : ℋ s ≃ₗᵢ[ℂ] ℋ t := by + rw [hst]; exact LinearIsometryEquiv.refl ℂ (ℋ t) + +/-- **The action is natural under `castEquiv`.** Transporting the operator `act s y` along the +region equality `s = t` (conjugating by `castEquiv`) yields `act t` of the transported operand. +This is the spatial half of the dependent-type coherence between a region and a propositionally +equal one, used to align the `act_incl_compl` action on `ΛABC ∖ (ΛABC ∖ ΛA)` with `act ΛA`. -/ +theorem castEquiv_conjAlgEquiv_act {s t : Finset sites} (hst : s = t) (x : N.algebra t) : + (castEquiv (ℋ := ℋ) hst).conjAlgEquiv ℂ (S.act s (hst.symm ▸ x)) = S.act t x := by + subst hst + simp only [castEquiv, eq_mpr_eq_cast, cast_eq] + rfl + +/-- The unitary identification `ℋ (ΛABC ∖ (ΛABC ∖ ΛA)) ≃ₗᵢ ℋ ΛA`, transporting the +complement-of-complement action space to the original sub-region's. Used to match the traced factor +of `decompᵢ` for the `BC` marginal (`ΛABC ∖ ΛA`) with `ΛA` in `factorization_uniqueness`. -/ +noncomputable def castIso {ΛA ΛABC : Finset sites} (h : ΛA ⊆ ΛABC) : + ℋ (ΛABC \ (ΛABC \ ΛA)) ≃ₗᵢ[ℂ] ℋ ΛA := + castEquiv (ℋ := ℋ) (by rw [Finset.sdiff_sdiff_self_left, Finset.inter_eq_right.mpr h]) + +/-- **The `A`-action through the nested factorisation `W`.** Reorganising `ℋ ΛABC` as +`(ℋ ΛA ⊗ ℋ (ΛAB ∖ ΛA)) ⊗ ℋ (ΛABC ∖ ΛAB)` (the unitary `W`), the embedded sub-region operator +`act ΛABC (incl x)` becomes the leftmost ampliation `(x ⊗ 1) ⊗ 1`. This pins the `A`-action in the +`(A ⊗ B) ⊗ C` picture and is the input to factorisation uniqueness for the `BC` marginal. -/ +theorem wReorg_conjAlgEquiv_act_incl {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) + (h_AB : ΛAB ⊆ ΛABC) (x : N.algebra ΛA) : + ((S.decompᵢ h_AB).trans + (TensorProduct.congrIsometry (S.decompᵢ h_A) + (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).toLinearEquiv.conjAlgEquiv ℂ + (S.act ΛABC (N.incl (h_A.trans h_AB) x)) + = TensorProduct.map (TensorProduct.map (S.act ΛA x) 1) 1 := by + rw [← N.incl_trans h_A h_AB, S.act_incl h_AB, S.act_incl h_A] + rw [show ((S.decompᵢ h_AB).trans + (TensorProduct.congrIsometry (S.decompᵢ h_A) + (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).toLinearEquiv + = (S.decompᵢ h_AB).toLinearEquiv.trans + (TensorProduct.congr (S.decompᵢ h_A).toLinearEquiv + (LinearEquiv.refl ℂ (ℋ (ΛABC \ ΛAB)))) from by + rw [LinearIsometryEquiv.toLinearEquiv_trans, TensorProduct.toLinearEquiv_congrIsometry]; rfl] + rw [LinearEquiv.conjAlgEquiv_trans, LinearMap.ampliate, S.decompᵢ_toLinearEquiv h_AB, + AlgEquiv.apply_symm_apply, TensorProduct.congr_conjAlgEquiv_map, LinearMap.ampliate, + S.decompᵢ_toLinearEquiv h_A, AlgEquiv.apply_symm_apply] + congr 1 + +/-- **Isotony is invariant under a propositional equality of regions.** If `s = t` as finsets, the +embeddings `incl (s ⊆ Λ)` and `incl (t ⊆ Λ)` agree once the operand is transported along `s = t`. +This discharges the dependent-type coherence between the complement-of-complement region +`ΛABC ∖ (ΛABC ∖ ΛA)` and `ΛA` in the `BC`-marginal factorisation uniqueness. -/ +theorem _root_.LocalNet.incl_cast {s t Λ : Finset sites} (hst : s = t) (hs : s ⊆ Λ) (ht : t ⊆ Λ) + (z : N.algebra s) : + N.incl hs z = N.incl ht (hst ▸ z) := by + subst hst; rfl + +/-- The reorganised unitary factorisation `ℋ ΛABC ≃ᵢ (ℋ B ⊗ ℋ C) ⊗ ℋ A` for the `BC` marginal: +factor out `ΛA` then `ΛAB ∖ ΛA`, reassociate, and move the `ΛA` factor to the end. This is the +factorisation `e₂` that reads the marginal of the `A × (B × C)` density matrix over the `A` factor; +the `ΛA` (traced-out) factor sits last so the partial trace over it lines up with `Matrix.traceRight` +of the reindexed density matrix. -/ +noncomputable def bcReorg {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) (h_AB : ΛAB ⊆ ΛABC) : + ℋ ΛABC ≃ₗᵢ[ℂ] (ℋ (ΛAB \ ΛA) ⊗[ℂ] ℋ (ΛABC \ ΛAB)) ⊗[ℂ] ℋ ΛA := + ((S.decompᵢ h_AB).trans + (TensorProduct.congrIsometry (S.decompᵢ h_A) + (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).trans + ((TensorProduct.assocIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)) (ℋ (ΛABC \ ΛAB))).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA) ⊗[ℂ] ℋ (ΛABC \ ΛAB)))) + +/-- **The `A`-action through the reorganised factorisation `bcReorg`** is the canonical ampliation +on the last factor: `bcReorg-conj (act ΛABC (incl x)) = 1 ⊗ act ΛA x`. Together with the +complementary `act_incl_compl` action of the `decompᵢ (sdiff)` factorisation, this is the input to +factorisation uniqueness for the `BC` marginal. -/ +theorem bcReorg_conjAlgEquiv_act_incl {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) + (h_AB : ΛAB ⊆ ΛABC) (x : N.algebra ΛA) : + (S.bcReorg h_A h_AB).toLinearEquiv.conjAlgEquiv ℂ (S.act ΛABC (N.incl (h_A.trans h_AB) x)) + = TensorProduct.map 1 (S.act ΛA x) := by + rw [bcReorg, LinearIsometryEquiv.toLinearEquiv_trans, LinearEquiv.conjAlgEquiv_trans, + S.wReorg_conjAlgEquiv_act_incl h_A h_AB, LinearIsometryEquiv.toLinearEquiv_trans, + LinearEquiv.conjAlgEquiv_trans, TensorProduct.toLinearEquiv_assocIsometry, + TensorProduct.assoc_conjAlgEquiv_map, TensorProduct.map_one, + TensorProduct.toLinearEquiv_commIsometry, TensorProduct.comm_conjAlgEquiv_map] + +/-- The direct unitary factorisation `ℋ ΛABC ≃ᵢ ℋ (ΛABC ∖ ΛA) ⊗ ℋ ΛA` for the `BC` marginal: factor +out `ΛA`'s complement directly (`decompᵢ (sdiff)`) and identify the complement-of-complement factor +with `ℋ ΛA` (`castIso`). This is the factorisation `e₁` whose partial trace is, by construction, the +`BC` marginal `restrict`; the traced-out factor is `ℋ ΛA`, matching `bcReorg`. -/ +noncomputable def bcDirect {ΛA ΛABC : Finset sites} (h : ΛA ⊆ ΛABC) : + ℋ ΛABC ≃ₗᵢ[ℂ] ℋ (ΛABC \ ΛA) ⊗[ℂ] ℋ ΛA := + (S.decompᵢ (Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)).trans + (TensorProduct.congrIsometry (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛA))) + (castIso (ℋ := ℋ) h)) + +/-- **The `A`-action through the direct factorisation `bcDirect`** is the canonical ampliation on +the last factor: `bcDirect-conj (act ΛABC (incl x)) = 1 ⊗ act ΛA x`. Proved via `act_incl_compl` +(the complement acts canonically on its factor), `incl_cast`/`castEquiv_conjAlgEquiv_act` (the +complement-of-complement region is `ΛA`). With `bcReorg_conjAlgEquiv_act_incl` this shows both +factorisations implement the *same* `ΛA`-action, the hypothesis of factorisation uniqueness. -/ +theorem bcDirect_conjAlgEquiv_act_incl {ΛA ΛABC : Finset sites} (h : ΛA ⊆ ΛABC) (x : N.algebra ΛA) : + (S.bcDirect h).toLinearEquiv.conjAlgEquiv ℂ (S.act ΛABC (N.incl h x)) + = TensorProduct.map 1 (S.act ΛA x) := by + have hΛ : ΛABC \ (ΛABC \ ΛA) = ΛA := by + rw [Finset.sdiff_sdiff_self_left, Finset.inter_eq_right.mpr h] + rw [LocalNet.incl_cast hΛ.symm h Finset.sdiff_subset x, + S.act_incl_compl (Λ := ΛABC \ ΛA) Finset.sdiff_subset (hΛ.symm ▸ x)] + rw [bcDirect, LinearIsometryEquiv.toLinearEquiv_trans, LinearEquiv.conjAlgEquiv_trans, + S.decompᵢ_toLinearEquiv, LinearMap.coampliate, AlgEquiv.apply_symm_apply, + TensorProduct.toLinearEquiv_congrIsometry, TensorProduct.congr_conjAlgEquiv_map, + castIso, S.castEquiv_conjAlgEquiv_act, map_one] + +/-- **The nested tensor-product basis reassociates to the `bcReorg` factorisation.** The orthonormal +basis of `ℋ ΛABC` built by factoring `ΛA ⊆ ΛAB ⊆ ΛABC` and reindexing `((κA × κB) × κC)` to +`(κA × (κB × κC))` equals the basis pulled back along the `A`-first factorisation +`(decompᵢ h_AB) ≫ congr (decompᵢ h_A) 1 ≫ assoc`. This rewrites the density matrix `ρ_ABC` so that +its `A`-marginal (`ptLeft`) corresponds to the operator partial trace along `bcReorg`. -/ +theorem tensorBasis_reindex_prodAssoc {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) + (h_AB : ΛAB ⊆ ΛABC) {κA κB κC : Type*} [Fintype κA] [Fintype κB] [Fintype κC] + (bA : OrthonormalBasis κA ℂ (ℋ ΛA)) (bB : OrthonormalBasis κB ℂ (ℋ (ΛAB \ ΛA))) + (bC : OrthonormalBasis κC ℂ (ℋ (ΛABC \ ΛAB))) : + ((((bA.tensorProduct bB).map (S.decompᵢ h_A).symm).tensorProduct bC).map + (S.decompᵢ h_AB).symm).reindex (Equiv.prodAssoc κA κB κC) + = (bA.tensorProduct (bB.tensorProduct bC)).map + (((S.decompᵢ h_AB).trans (TensorProduct.congrIsometry (S.decompᵢ h_A) + (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).trans + (TensorProduct.assocIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)) (ℋ (ΛABC \ ΛAB)))).symm := by + apply DFunLike.ext + rintro ⟨a, b, c⟩ + simp only [OrthonormalBasis.reindex_apply, OrthonormalBasis.map_apply, + OrthonormalBasis.tensorProduct_apply, Equiv.prodAssoc_symm_apply, + LinearIsometryEquiv.symm_trans, LinearIsometryEquiv.trans_apply, + TensorProduct.assocIsometry_symm_apply, TensorProduct.congrIsometry_symm, + TensorProduct.congrIsometry_apply, TensorProduct.assoc_symm_tmul, TensorProduct.congr_tmul] + rfl + +/-- **The `ΛA`-marginal entropy via the factorised basis equals the representation-free marginal +entropy.** For a state `σ` on `ℋ ΛAB`, tracing out the `ΛA`-index (`ptLeft`) of its density matrix +in the orthonormal basis pulled back from `ℋ ΛA ⊗ ℋ (ΛAB ∖ ΛA)` gives the von Neumann entropy of the +abstract marginal `restrict (sdiff) σ`. Proved by factorisation uniqueness comparing the +complement factorisation `bcDirect h_A` (whose partial trace is `restrict`) with the canonical +`decompᵢ h_A ≫ comm`. This is the building block for the middle-region (`B`) marginal of SSA. -/ +theorem vonNeumannEntropy_ptLeft_decompBasis [∀ Λ, Nontrivial (ℋ Λ)] + {ΛA ΛAB : Finset sites} (h_A : ΛA ⊆ ΛAB) {κA κB : Type*} [Fintype κA] [DecidableEq κA] + [Fintype κB] [DecidableEq κB] (bA : OrthonormalBasis κA ℂ (ℋ ΛA)) + (bB : OrthonormalBasis κB ℂ (ℋ (ΛAB \ ΛA))) {σ : N.algebra ΛAB} (hσ : S.IsDensity σ) : + Matrix.vonNeumannEntropy + (S.toDensityMatrixBasis ((bA.tensorProduct bB).map (S.decompᵢ h_A).symm) hσ).ptLeft + = S.entropy (S.restrict (Finset.sdiff_subset : ΛAB \ ΛA ⊆ ΛAB) σ) := by + have hcommB : ∀ f : Module.End ℂ (ℋ ΛA), + ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap + ∘ₗ TensorProduct.map LinearMap.id f + = TensorProduct.map LinearMap.id f + ∘ₗ ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap := by + intro f + obtain ⟨x, rfl⟩ : ∃ x, S.act ΛA x = f := ⟨(S.act ΛA).symm f, by simp⟩ + have h1 := S.bcDirect_conjAlgEquiv_act_incl h_A x + have h2 : ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)))).toLinearEquiv.conjAlgEquiv ℂ + (S.act ΛAB (N.incl h_A x)) = TensorProduct.map 1 (S.act ΛA x) := by + rw [S.act_incl h_A, LinearIsometryEquiv.toLinearEquiv_trans, LinearEquiv.conjAlgEquiv_trans, + LinearMap.ampliate, S.decompᵢ_toLinearEquiv, AlgEquiv.apply_symm_apply, + TensorProduct.toLinearEquiv_commIsometry, TensorProduct.comm_conjAlgEquiv_map] + simp only [← Module.End.one_eq_id] + have hΨM : ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.conjAlgEquiv ℂ + (TensorProduct.map 1 (S.act ΛA x)) = TensorProduct.map 1 (S.act ΛA x) := by + conv_lhs => rw [← h1] + rw [show ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv + = (S.bcDirect h_A).toLinearEquiv.symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)))).toLinearEquiv from rfl, + LinearEquiv.conjAlgEquiv_trans, ← LinearEquiv.symm_conjAlgEquiv, AlgEquiv.symm_apply_apply, h2] + rw [LinearEquiv.conjAlgEquiv_apply] at hΨM + calc ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap + ∘ₗ TensorProduct.map 1 (S.act ΛA x) + = (((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap + ∘ₗ TensorProduct.map 1 (S.act ΛA x) + ∘ₗ ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) + (ℋ (ΛAB \ ΛA))))).toLinearEquiv.symm.toLinearMap) + ∘ₗ ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap := by + rw [LinearMap.comp_assoc, LinearMap.comp_assoc, ← LinearMap.comp_assoc _ _ + ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap, + LinearEquiv.comp_coe, LinearEquiv.self_trans_symm, LinearEquiv.refl_toLinearMap, + LinearMap.comp_id] + _ = TensorProduct.map 1 (S.act ΛA x) + ∘ₗ ((S.bcDirect h_A).symm.trans + ((S.decompᵢ h_A).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap := by + rw [hΨM] + obtain ⟨W, hW⟩ := factorization_uniqueness (S.bcDirect h_A) + ((S.decompᵢ h_A).trans (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)))) hcommB (S.act ΛAB σ) + have hptdB : LinearMap.partialTrace (S.bcDirect h_A).toLinearEquiv (S.act ΛAB σ) + = S.act (ΛAB \ ΛA) (S.restrict Finset.sdiff_subset σ) := by + rw [LocalNet.Split.bcDirect, LinearIsometryEquiv.toLinearEquiv_trans, S.decompᵢ_toLinearEquiv, + TensorProduct.toLinearEquiv_congrIsometry, + show (LinearIsometryEquiv.refl ℂ (ℋ (ΛAB \ ΛA))).toLinearEquiv + = LinearEquiv.refl ℂ (ℋ (ΛAB \ ΛA)) from rfl, + LinearMap.partialTrace_congr_right_id, S.restrict_apply, AlgEquiv.apply_symm_apply] + have hbmap : (bB.map W.symm).map W = bB := by + apply DFunLike.ext; intro i; simp [OrthonormalBasis.map_apply] + rw [show (S.toDensityMatrixBasis ((bA.tensorProduct bB).map (S.decompᵢ h_A).symm) hσ).ptLeft + = S.toDensityMatrixBasis (bB.map W.symm) (S.restrict_isDensity Finset.sdiff_subset hσ) from ?_, + S.vonNeumannEntropy_toDensityMatrixBasis] + apply DensityMatrix.ext + rw [DensityMatrix.ptLeft_toMatrix, S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, + S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, LinearMap.traceLeft_toMatrixOrthonormal, + hW] + conv_lhs => rw [← hbmap] + rw [toMatrixOrthonormal_conj_map, hptdB] + +/-- **Strong subadditivity of the von Neumann entropy on an abstract split net.** For a faithful +operator-algebraic split net `LocalNet.Split` over finite-dimensional action spaces, and a state +`ρ` on a region `ΛABC` with a nested decomposition `ΛA ⊆ ΛAB ⊆ ΛABC`, the entropies of the marginals +obey +`S(ABC) + S(B) ≤ S(AB) + S(BC)`, +where `B = ΛAB ∖ ΛA`, `BC = ΛABC ∖ ΛA`, and each marginal is the representation-free `restrict`. +This is the AQFT form of strong subadditivity: it is assembled entirely on the abstract net (no +matrix model), by reading each marginal in a tensor-factorised orthonormal basis, using factorisation +uniqueness (the partial trace depends only on the subsystem, not the chosen factorisation of its +complement — the tensor commutant theorem plus the spatial split data `act_incl`/`act_incl_compl`), +and transporting the analytic core `DensityMatrix.vonNeumannEntropy_SSA_product` to the net. -/ +theorem vonNeumannEntropy_SSA [∀ Λ, Nontrivial (ℋ Λ)] + {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) (h_AB : ΛAB ⊆ ΛABC) + {ρ : N.algebra ΛABC} (hρ : S.IsDensity ρ) : + S.entropy ρ + S.entropy (S.restrict ((Finset.sdiff_subset : ΛAB \ ΛA ⊆ ΛAB).trans h_AB) ρ) + ≤ S.entropy (S.restrict h_AB ρ) + + S.entropy (S.restrict (Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC) ρ) := by + haveI : Nonempty (Fin (Module.finrank ℂ (ℋ ΛA))) := ⟨⟨0, Module.finrank_pos⟩⟩ + haveI : Nonempty (Fin (Module.finrank ℂ (ℋ (ΛAB \ ΛA)))) := ⟨⟨0, Module.finrank_pos⟩⟩ + haveI : Nonempty (Fin (Module.finrank ℂ (ℋ (ΛABC \ ΛAB)))) := ⟨⟨0, Module.finrank_pos⟩⟩ + set bA := stdOrthonormalBasis ℂ (ℋ ΛA) with hbA + set bB := stdOrthonormalBasis ℂ (ℋ (ΛAB \ ΛA)) with hbB + set bC := stdOrthonormalBasis ℂ (ℋ (ΛABC \ ΛAB)) with hbC + set ρ_ABC := S.toDensityMatrixBasis + (((((bA.tensorProduct bB).map (S.decompᵢ h_A).symm).tensorProduct bC).map + (S.decompᵢ h_AB).symm).reindex (Equiv.prodAssoc _ _ _)) hρ with hρ_ABC + have key := DensityMatrix.vonNeumannEntropy_SSA_product ρ_ABC + ((ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight) ρ_ABC.ptLeft ρ_ABC.ptLeft.ptRight rfl rfl rfl + have hABC : Matrix.vonNeumannEntropy ρ_ABC = S.entropy ρ := by + rw [hρ_ABC, S.vonNeumannEntropy_toDensityMatrixBasis] + have hmar : (ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight + = S.toDensityMatrixBasis ((bA.tensorProduct bB).map (S.decompᵢ h_A).symm) + (S.restrict_isDensity h_AB hρ) := by + rw [hρ_ABC, S.toDensityMatrixBasis_reindex_mapEquiv] + apply DensityMatrix.ext + rw [DensityMatrix.ptRight_toMatrix, S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, + S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, LinearMap.traceRight_toMatrixOrthonormal] + congr 1 + rw [S.restrict_apply, AlgEquiv.apply_symm_apply, S.decompᵢ_toLinearEquiv] + have hAB : Matrix.vonNeumannEntropy (ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight + = S.entropy (S.restrict h_AB ρ) := by rw [hmar, S.vonNeumannEntropy_toDensityMatrixBasis] + have hcomm : ∀ f : Module.End ℂ (ℋ ΛA), + ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap + ∘ₗ TensorProduct.map LinearMap.id f + = TensorProduct.map LinearMap.id f + ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans + (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap := by + intro f + obtain ⟨x, rfl⟩ : ∃ x, S.act ΛA x = f := ⟨(S.act ΛA).symm f, by simp⟩ + have h1 := S.bcDirect_conjAlgEquiv_act_incl (h_A.trans h_AB) x + have h2 := S.bcReorg_conjAlgEquiv_act_incl h_A h_AB x + simp only [← Module.End.one_eq_id] + have hΨM : ((S.bcDirect (h_A.trans h_AB)).symm.trans + (S.bcReorg h_A h_AB)).toLinearEquiv.conjAlgEquiv ℂ + (TensorProduct.map 1 (S.act ΛA x)) = TensorProduct.map 1 (S.act ΛA x) := by + conv_lhs => rw [← h1] + rw [show ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv + = (S.bcDirect (h_A.trans h_AB)).toLinearEquiv.symm.trans (S.bcReorg h_A h_AB).toLinearEquiv + from rfl, LinearEquiv.conjAlgEquiv_trans, ← LinearEquiv.symm_conjAlgEquiv, + AlgEquiv.symm_apply_apply, h2] + rw [LinearEquiv.conjAlgEquiv_apply] at hΨM + calc ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap + ∘ₗ TensorProduct.map 1 (S.act ΛA x) + = (((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap + ∘ₗ TensorProduct.map 1 (S.act ΛA x) + ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans + (S.bcReorg h_A h_AB)).toLinearEquiv.symm.toLinearMap) + ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans + (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap := by + rw [LinearMap.comp_assoc, LinearMap.comp_assoc, ← LinearMap.comp_assoc _ _ + ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap, + LinearEquiv.comp_coe, LinearEquiv.self_trans_symm, LinearEquiv.refl_toLinearMap, + LinearMap.comp_id] + _ = TensorProduct.map 1 (S.act ΛA x) + ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans + (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap := by + rw [hΨM] + have hBC : Matrix.vonNeumannEntropy ρ_ABC.ptLeft + = S.entropy (S.restrict (Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC) ρ) := by + rw [hρ_ABC] + obtain ⟨V, hV⟩ := factorization_uniqueness (S.bcDirect (h_A.trans h_AB)) (S.bcReorg h_A h_AB) + hcomm (S.act ΛABC ρ) + have hptd : LinearMap.partialTrace (S.bcDirect (h_A.trans h_AB)).toLinearEquiv (S.act ΛABC ρ) + = S.act (ΛABC \ ΛA) (S.restrict Finset.sdiff_subset ρ) := by + rw [LocalNet.Split.bcDirect, LinearIsometryEquiv.toLinearEquiv_trans, S.decompᵢ_toLinearEquiv, + TensorProduct.toLinearEquiv_congrIsometry, + show (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛA))).toLinearEquiv + = LinearEquiv.refl ℂ (ℋ (ΛABC \ ΛA)) from rfl, + LinearMap.partialTrace_congr_right_id, S.restrict_apply, AlgEquiv.apply_symm_apply] + have hbmap : ((bB.tensorProduct bC).map V.symm).map V = bB.tensorProduct bC := by + apply DFunLike.ext; intro i; simp [OrthonormalBasis.map_apply] + rw [show (S.toDensityMatrixBasis _ hρ).ptLeft = S.toDensityMatrixBasis + ((bB.tensorProduct bC).map V.symm) (S.restrict_isDensity Finset.sdiff_subset hρ) from ?_, + S.vonNeumannEntropy_toDensityMatrixBasis] + apply DensityMatrix.ext + rw [DensityMatrix.ptLeft_toMatrix, S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, + S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, + S.tensorBasis_reindex_prodAssoc h_A h_AB bA bB bC, LinearMap.traceLeft_toMatrixOrthonormal, + show (((S.decompᵢ h_AB).trans (TensorProduct.congrIsometry (S.decompᵢ h_A) + (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).trans + (TensorProduct.assocIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)) (ℋ (ΛABC \ ΛAB)))).trans + (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA) ⊗[ℂ] ℋ (ΛABC \ ΛAB))) + = S.bcReorg h_A h_AB from by rw [LocalNet.Split.bcReorg, LinearIsometryEquiv.trans_assoc], + hV] + conv_lhs => rw [← hbmap] + rw [toMatrixOrthonormal_conj_map, hptd] + have hB : Matrix.vonNeumannEntropy ρ_ABC.ptLeft.ptRight + = S.entropy (S.restrict ((Finset.sdiff_subset : ΛAB \ ΛA ⊆ ΛAB).trans h_AB) ρ) := by + rw [show ρ_ABC.ptLeft.ptRight = (ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight.ptLeft from ?_, + hmar, S.vonNeumannEntropy_ptLeft_decompBasis h_A bA bB (S.restrict_isDensity h_AB hρ), + S.restrict_restrict] + apply DensityMatrix.ext + rw [DensityMatrix.ptRight_toMatrix, DensityMatrix.ptLeft_toMatrix, DensityMatrix.ptLeft_toMatrix, + DensityMatrix.ptRight_toMatrix, DensityMatrix.mapEquiv_toMatrix] + exact (Matrix.traceLeft_traceRight_submatrix_prodAssoc _).symm + rw [hABC, hB, hAB, hBC] at key + exact key + +end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitTrace.lean b/QuantumSystem/Analysis/Entropy/SplitTrace.lean new file mode 100644 index 0000000..b886047 --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/SplitTrace.lean @@ -0,0 +1,124 @@ +module + +public import Mathlib.Analysis.InnerProductSpace.Positive +public import QuantumSystem.Algebra.LocalNet.TensorDecomposition + +/-! +# Trace on a split net and its preservation under the marginal + +The first brick of the **representation-free quantum-information layer** built on the split +property (`LocalNet.Split`). The split structure identifies each local algebra with the type I +factor `End ℂ (ℋ Λ)` of operators on a finite-dimensional action space, which carries the +canonical trace `LinearMap.trace`. This file: + +* records the general fact that the partial trace along a tensor decomposition preserves the + trace (`LinearMap.trace_partialTrace`, via the operator factorisation `partialTraceRight`); +* defines the trace `LocalNet.Split.trace` on the local algebra of a split net; +* proves it is preserved by the marginal `LocalNet.Split.restrict` (`trace_restrict`). + +These are the building blocks for density operators, von Neumann entropy and strong +subadditivity stated directly on the abstract split net, with no matrix index substrate. +-/ + +@[expose] public section + +open scoped TensorProduct + +namespace TensorProduct + +variable {R : Type*} [CommRing R] {M N : Type*} + [AddCommGroup M] [Module R M] [Module.Finite R M] [Module.Free R M] + [AddCommGroup N] [Module R N] [Module.Finite R N] [Module.Free R N] + +/-- The partial trace over the second factor relates to the full trace through the operator +tensor decomposition: `trace_M (partialTraceRight S) = trace_{M ⊗ N} (endTensorEndAlgEquiv S)`. +On a pure operator tensor both sides are `trace Y * trace Z`. -/ +theorem trace_partialTraceRight (S : Module.End R M ⊗[R] Module.End R N) : + LinearMap.trace R M (partialTraceRight S) = + LinearMap.trace R (M ⊗[R] N) (endTensorEndAlgEquiv S) := by + induction S using TensorProduct.induction_on with + | zero => simp + | tmul Y Z => + rw [partialTraceRight_tmul, endTensorEndAlgEquiv_tmul, LinearMap.trace_tensorProduct', + map_smul, smul_eq_mul] + ring + | add S₁ S₂ h₁ h₂ => simp only [map_add, h₁, h₂] + +end TensorProduct + +namespace LinearMap + +open scoped TensorProduct + +variable {𝕜 ℋ A B : Type*} [Field 𝕜] + [AddCommGroup ℋ] [Module 𝕜 ℋ] + [AddCommGroup A] [Module 𝕜 A] [Module.Finite 𝕜 A] [Module.Free 𝕜 A] + [AddCommGroup B] [Module 𝕜 B] [Module.Finite 𝕜 B] [Module.Free 𝕜 B] + +/-- **The partial trace preserves the trace**: tracing out the second factor of a decomposition +`e : ℋ ≃ₗ A ⊗ B` and then taking the trace over `A` recovers the trace over `ℋ`. -/ +theorem trace_partialTrace (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (ρ : Module.End 𝕜 ℋ) : + LinearMap.trace 𝕜 A (LinearMap.partialTrace e ρ) = LinearMap.trace 𝕜 ℋ ρ := by + rw [LinearMap.partialTrace_apply, TensorProduct.trace_partialTraceRight, + AlgEquiv.apply_symm_apply] + exact LinearMap.trace_conj' ρ e + +end LinearMap + +namespace LocalNet.Split + +variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] + (S : Split N ℋ) + +/-- The **trace** on a local algebra of a split net: the canonical operator trace on the action +space `ℋ Λ`, transported along the type I identification `act Λ`. -/ +noncomputable def trace (Λ : Finset sites) : N.algebra Λ →ₗ[ℂ] ℂ := + LinearMap.trace ℂ (ℋ Λ) ∘ₗ (S.act Λ).toLinearMap + +theorem trace_apply (Λ : Finset sites) (X : N.algebra Λ) : + S.trace Λ X = LinearMap.trace ℂ (ℋ Λ) (S.act Λ X) := + rfl + +/-- **The marginal preserves the trace**: `trace (restrict h M) = trace M`. The split partial +trace is trace-preserving, the property that makes it the Schrödinger-picture dual of the +isotony embedding. -/ +theorem trace_restrict {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (M : N.algebra Λ') : + S.trace Λ (S.restrict h M) = S.trace Λ' M := by + rw [trace_apply, trace_apply, restrict_apply, AlgEquiv.apply_symm_apply, + LinearMap.trace_partialTrace] + +/-- The trace is **cyclic**: `trace (A * B) = trace (B * A)` (it is the operator trace through the +type I identification `act`, transported from `LinearMap.trace_mul_comm`). -/ +theorem trace_mul_comm {Λ : Finset sites} (A B : N.algebra Λ) : + S.trace Λ (A * B) = S.trace Λ (B * A) := by + rw [trace_apply, trace_apply, map_mul (S.act Λ), map_mul (S.act Λ), LinearMap.trace_mul_comm] + +/-- **Heisenberg / trace duality** between the isotony embedding `incl` (Heisenberg picture) and the +marginal `restrict` (Schrödinger picture): `trace (ρ · incl h X) = trace (restrict h ρ · X)`. The +marginal `restrict h` is the predual of the inclusion `incl h`. Derived purely from +`restrict_incl_mul` and `trace_restrict` (no tensor data), so it holds for the abstract net. -/ +theorem trace_mul_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (ρ : N.algebra Λ') (X : N.algebra Λ) : + S.trace Λ' (ρ * N.incl h X) = S.trace Λ (S.restrict h ρ * X) := by + have key := congrArg (S.trace Λ) (S.restrict_incl_mul h X ρ) + rw [S.trace_restrict h (N.incl h X * ρ), S.trace_mul_comm (N.incl h X) ρ, + S.trace_mul_comm X (S.restrict h ρ)] at key + exact key + +/-- A **density operator** of the split net at region `Λ`: an element of the local algebra whose +operator image `act Λ ρ` is positive (the Loewner order on `End ℂ (ℋ Λ)`) and whose trace is one. +Since `act` is a `*`-isomorphism (`act_star`), positivity of `act Λ ρ` is the genuine C⋆-positivity +of `ρ`; this is the representation-free analogue of a density matrix, stated with no index basis. -/ +def IsDensity {Λ : Finset sites} (ρ : N.algebra Λ) : Prop := + 0 ≤ S.act Λ ρ ∧ S.trace Λ ρ = 1 + +theorem IsDensity.trace_eq_one {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + S.trace Λ ρ = 1 := + hρ.2 + +theorem IsDensity.nonneg {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + 0 ≤ S.act Λ ρ := + hρ.1 + +end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitTransport.lean b/QuantumSystem/Analysis/Entropy/SplitTransport.lean new file mode 100644 index 0000000..e0c5a68 --- /dev/null +++ b/QuantumSystem/Analysis/Entropy/SplitTransport.lean @@ -0,0 +1,374 @@ +module + +public import Mathlib.Analysis.InnerProductSpace.Trace +public import QuantumSystem.Analysis.Entropy.SplitEntropy +public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy + +/-! +# Matrix transport for a split net + +The **transport bridge** that carries the representation-free split-net quantum information back to +the matrix theory: for a region `Λ`, an orthonormal basis of the action space `ℋ Λ` realises the +local algebra as a matrix algebra, + + `Split.toMatrix Λ : N.algebra Λ ≃⋆ₐ[ℂ] Matrix (Fin (finrank ℂ (ℋ Λ))) … ℂ`, + +a genuine `*`-isomorphism (`act` is a `*`-iso by `act_star`, and `LinearMap.toMatrixOrthonormal` is +a `*`-iso for an orthonormal basis). Through it, positivity, trace, density and von Neumann entropy +on the split net coincide with their matrix counterparts, so the deep matrix results +(non-negativity, strong subadditivity, …) transport to the abstract net. +-/ + +@[expose] public section + +open scoped Matrix ComplexOrder TensorProduct + +namespace TensorProduct + +variable {ι A B : Type*} [Fintype ι] + [NormedAddCommGroup A] [InnerProductSpace ℂ A] [FiniteDimensional ℂ A] + [NormedAddCommGroup B] [InnerProductSpace ℂ B] [FiniteDimensional ℂ B] + +/-- The diagonal quadratic form of the partial trace over the second factor, expanded over an +orthonormal basis `w` of `B`: `⟪partialTraceRight S a, a⟫ = ∑ₖ ⟪(S as operator) (a ⊗ wₖ), a ⊗ wₖ⟫`. +This is the bridge that makes `partialTraceRight` manifestly positivity-preserving. -/ +lemma inner_partialTraceRight (w : OrthonormalBasis ι ℂ B) + (S : Module.End ℂ A ⊗[ℂ] Module.End ℂ B) (a a' : A) : + inner ℂ (partialTraceRight S a') a + = ∑ k, inner ℂ (endTensorEndAlgEquiv S (a' ⊗ₜ[ℂ] w k)) (a ⊗ₜ[ℂ] w k) := by + induction S using TensorProduct.induction_on with + | zero => simp + | tmul Y Z => + rw [partialTraceRight_tmul, endTensorEndAlgEquiv_tmul, LinearMap.smul_apply, inner_smul_left] + simp only [TensorProduct.map_tmul, TensorProduct.inner_tmul, ← Finset.mul_sum] + rw [mul_comm] + congr 1 + rw [LinearMap.trace_eq_sum_inner Z w, starRingEnd_apply, star_sum] + refine Finset.sum_congr rfl fun k _ => ?_ + rw [← starRingEnd_apply, inner_conj_symm] + | add S₁ S₂ h₁ h₂ => + simp only [map_add, LinearMap.add_apply, inner_add_left, h₁, h₂, Finset.sum_add_distrib] + +end TensorProduct + +namespace LinearMap + +open scoped ComplexOrder + +variable {ℋ A B : Type*} + [NormedAddCommGroup ℋ] [InnerProductSpace ℂ ℋ] [FiniteDimensional ℂ ℋ] + [NormedAddCommGroup A] [InnerProductSpace ℂ A] [FiniteDimensional ℂ A] + [NormedAddCommGroup B] [InnerProductSpace ℂ B] [FiniteDimensional ℂ B] + +omit [FiniteDimensional ℂ ℋ] in +/-- **The partial trace preserves positivity.** Along a *unitary* tensor factorisation +`e : ℋ ≃ₗᵢ A ⊗ B`, the partial trace of a positive operator is positive — the partial trace is a +quantum channel. The quadratic form expands (`TensorProduct.inner_partialTraceRight`) into a sum of +the quadratic form of `T` at the unit-vectors `e.symm (a ⊗ wₖ)`, each non-negative. -/ +theorem isPositive_partialTrace (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) {T : Module.End ℂ ℋ} + (hT : T.IsPositive) : (LinearMap.partialTrace e.toLinearEquiv T).IsPositive := by + rw [LinearMap.isPositive_iff_complex] + intro a + set w := stdOrthonormalBasis ℂ B with hw + have key : inner ℂ (LinearMap.partialTrace e.toLinearEquiv T a) a = + ((∑ k, RCLike.re (inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k))) : ℝ) : ℂ) := by + rw [LinearMap.partialTrace_apply, TensorProduct.inner_partialTraceRight w, + AlgEquiv.apply_symm_apply, Complex.ofReal_sum] + refine Finset.sum_congr rfl fun k _ => ?_ + rw [LinearEquiv.conjAlgEquiv_apply_apply, + show inner ℂ (e.toLinearEquiv (T (e.toLinearEquiv.symm (a ⊗ₜ[ℂ] w k)))) (a ⊗ₜ[ℂ] w k) + = inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k)) from by + change inner ℂ (e (T (e.symm (a ⊗ₜ[ℂ] w k)))) (a ⊗ₜ[ℂ] w k) + = inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k)) + rw [← e.inner_map_map (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k)), + e.apply_symm_apply], + (((LinearMap.isPositive_iff_complex T).mp hT _).1)] + rw [key] + have hre : RCLike.re ((∑ k, RCLike.re (inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) + (e.symm (a ⊗ₜ[ℂ] w k))) : ℝ) : ℂ) + = ∑ k, RCLike.re (inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k))) := + RCLike.ofReal_re _ + rw [hre] + exact ⟨rfl, Finset.sum_nonneg fun k _ => ((LinearMap.isPositive_iff_complex T).mp hT _).2⟩ + +/-- The **Kraus operators** `Vⱼ : A →ₗ ℋ`, `a ↦ e.symm (a ⊗ wⱼ)`, of the partial trace along a +unitary factorisation `e : ℋ ≃ₗᵢ A ⊗ B`, where `w` is the standard orthonormal basis of `B`. -/ +noncomputable def ptKraus (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) (j : Fin (Module.finrank ℂ B)) : + A →ₗ[ℂ] ℋ := + e.symm.toLinearEquiv.toLinearMap ∘ₗ (TensorProduct.mk ℂ A B).flip (stdOrthonormalBasis ℂ B j) + +omit [FiniteDimensional ℂ ℋ] [FiniteDimensional ℂ A] in +@[simp] theorem ptKraus_apply (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) (j : Fin (Module.finrank ℂ B)) (a : A) : + ptKraus e j a = e.symm (a ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j) := + rfl + +/-- **Kraus form of the partial trace**: along a unitary factorisation `e`, the partial trace is a +sum of compressions `Tr_B T = ∑ⱼ Vⱼ⋆ T Vⱼ`. This is the Kraus/Stinespring decomposition exhibiting +the partial trace as a completely positive map. -/ +theorem partialTrace_eq_sum_kraus (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) (T : Module.End ℂ ℋ) : + LinearMap.partialTrace e.toLinearEquiv T + = ∑ j, LinearMap.adjoint (ptKraus e j) ∘ₗ T ∘ₗ ptKraus e j := by + ext a' + refine ext_inner_right ℂ fun a => ?_ + rw [LinearMap.partialTrace_apply, TensorProduct.inner_partialTraceRight (stdOrthonormalBasis ℂ B), + AlgEquiv.apply_symm_apply, LinearMap.sum_apply, sum_inner] + refine Finset.sum_congr rfl fun j _ => ?_ + rw [LinearMap.comp_apply, LinearMap.comp_apply, LinearMap.adjoint_inner_left, ptKraus_apply, + ptKraus_apply, LinearEquiv.conjAlgEquiv_apply_apply] + rw [show e.toLinearEquiv (T (e.toLinearEquiv.symm (a' ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j))) + = e (T (e.symm (a' ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j))) from rfl, + ← e.inner_map_map (T (e.symm (a' ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j))) + (e.symm (a ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j)), e.apply_symm_apply] + +omit [FiniteDimensional ℂ A] [FiniteDimensional ℂ B] in +/-- The matrix trace of the matrix of `T` in an orthonormal basis `b` is the operator trace of `T` +(independent of the choice of orthonormal basis). -/ +theorem trace_toMatrixOrthonormal {ι : Type*} [Fintype ι] [DecidableEq ι] + (b : OrthonormalBasis ι ℂ ℋ) (T : Module.End ℂ ℋ) : + (LinearMap.toMatrixOrthonormal b T).trace = LinearMap.trace ℂ ℋ T := by + rw [LinearMap.trace_eq_sum_inner T b, Matrix.trace] + refine Finset.sum_congr rfl fun i _ => ?_ + rw [Matrix.diag_apply, LinearMap.toMatrixOrthonormal_apply_apply] + +end LinearMap + +namespace LocalNet.Split + +variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} + [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] + [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] + (S : Split N ℋ) + +/-- The type I identification `act Λ` packaged as a `*`-isomorphism, using `act_star`. -/ +noncomputable def actₛ (Λ : Finset sites) : N.algebra Λ ≃⋆ₐ[ℂ] Module.End ℂ (ℋ Λ) := + { S.act Λ with map_smul' := map_smul (S.act Λ), map_star' := S.act_star } + +@[simp] theorem actₛ_apply (Λ : Finset sites) (x : N.algebra Λ) : + S.actₛ Λ x = S.act Λ x := + rfl + +/-- The **matrix representation** of the local algebra at `Λ`, a `*`-isomorphism onto the matrix +algebra on the index `Fin (finrank ℂ (ℋ Λ))` obtained from the standard orthonormal basis of the +action space. The composite of the type I identification `actₛ` with the orthonormal matrix +representation `LinearMap.toMatrixOrthonormal`. -/ +noncomputable def toMatrix (Λ : Finset sites) : + N.algebra Λ ≃⋆ₐ[ℂ] Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ))) ℂ := + (S.actₛ Λ).trans (LinearMap.toMatrixOrthonormal (stdOrthonormalBasis ℂ (ℋ Λ))) + +theorem toMatrix_apply (Λ : Finset sites) (x : N.algebra Λ) : + S.toMatrix Λ x = + LinearMap.toMatrixOrthonormal (stdOrthonormalBasis ℂ (ℋ Λ)) (S.act Λ x) := + rfl + +/-- **Trace transport**: the split trace coincides with the matrix trace of the transported +operator. -/ +theorem trace_eq_matrixTrace (Λ : Finset sites) (ρ : N.algebra Λ) : + S.trace Λ ρ = (S.toMatrix Λ ρ).trace := by + rw [trace_apply, LinearMap.trace_eq_sum_inner (S.act Λ ρ) (stdOrthonormalBasis ℂ (ℋ Λ)), + Matrix.trace] + refine Finset.sum_congr rfl fun i _ => ?_ + rw [Matrix.diag_apply, toMatrix_apply, LinearMap.toMatrixOrthonormal_apply_apply] + +/-- **Positivity transport**: the transported matrix is positive semidefinite iff the operator +`act Λ ρ` is positive (Loewner). This is `LinearMap.posSemidef_toMatrix_iff` for the orthonormal +basis, through `act`. -/ +theorem posSemidef_toMatrix_iff (Λ : Finset sites) (ρ : N.algebra Λ) : + (S.toMatrix Λ ρ).PosSemidef ↔ 0 ≤ S.act Λ ρ := by + rw [toMatrix_apply, LinearMap.nonneg_iff_isPositive] + exact LinearMap.posSemidef_toMatrix_iff (stdOrthonormalBasis ℂ (ℋ Λ)) + +/-- **Density transport**: a state of the split net (`IsDensity`) maps to a genuine density matrix +under the matrix representation. This is the bridge object through which the matrix quantum +information (von Neumann entropy, strong subadditivity, …) is pulled back to the split net. -/ +noncomputable def toDensityMatrix {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + DensityMatrix (Fin (Module.finrank ℂ (ℋ Λ))) where + toMatrix := S.toMatrix Λ ρ + posSemidef := (S.posSemidef_toMatrix_iff Λ ρ).mpr hρ.nonneg + trace_eq_one := by rw [← S.trace_eq_matrixTrace]; exact hρ.trace_eq_one + +@[simp] theorem toDensityMatrix_toMatrix {Λ : Finset sites} {ρ : N.algebra Λ} + (hρ : S.IsDensity ρ) : (S.toDensityMatrix hρ).toMatrix = S.toMatrix Λ ρ := + rfl + +include S in +/-- The local algebra of a split net is finite-dimensional (it is `*`-isomorphic to the operator +algebra on the finite-dimensional action space). -/ +theorem finiteDimensional_algebra (Λ : Finset sites) : FiniteDimensional ℂ (N.algebra Λ) := + (S.act Λ).symm.toLinearEquiv.finiteDimensional + +/-- The matrix representation `Split.toMatrix Λ` is continuous (a linear map of +finite-dimensional spaces). -/ +theorem continuous_toMatrix (Λ : Finset sites) : Continuous (S.toMatrix Λ) := by + haveI := S.finiteDimensional_algebra Λ + let L : N.algebra Λ →ₗ[ℂ] + Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ))) ℂ := + { toFun := S.toMatrix Λ, map_add' := map_add _, map_smul' := map_smul _ } + exact L.continuous_of_finiteDimensional + +/-- A state of the split net is self-adjoint (positive operators are self-adjoint, and `act` is a +`*`-isomorphism). -/ +theorem isSelfAdjoint_of_isDensity {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + IsSelfAdjoint ρ := by + have h1 : IsSelfAdjoint (S.act Λ ρ) := + ((LinearMap.nonneg_iff_isPositive _).mp hρ.nonneg).isSelfAdjoint + apply (S.act Λ).injective + rw [S.act_star] + exact h1 + +/-- **Entropy transport**: the split-net von Neumann entropy of a state coincides with the matrix +von Neumann entropy of its transported density matrix. The continuous functional calculus commutes +with the `*`-isomorphism `toMatrix` (`StarAlgHomClass.map_cfc`). -/ +theorem entropy_eq_vonNeumannEntropy {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + S.entropy ρ = Matrix.vonNeumannEntropy (S.toDensityMatrix hρ) := by + haveI : IsScalarTower ℝ ℂ (N.algebra Λ) := IsScalarTower.complexToReal + have hsa : IsSelfAdjoint ρ := S.isSelfAdjoint_of_isDensity hρ + have hsa' : IsSelfAdjoint (S.toMatrix Λ ρ) := + show star (S.toMatrix Λ ρ) = S.toMatrix Λ ρ by rw [← map_star, hsa] + rw [entropy_def, trace_eq_matrixTrace, Matrix.vonNeumannEntropy_eq_cfc_re, + toDensityMatrix_toMatrix, + StarAlgHomClass.map_cfc (S.toMatrix Λ) Real.negMulLog ρ + Real.continuous_negMulLog.continuousOn (S.continuous_toMatrix Λ) hsa hsa'] + +/-- **Von Neumann entropy of a split-net state is non-negative.** Transported from the matrix +result `Matrix.vonNeumannEntropy_nonneg`. -/ +theorem entropy_nonneg {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + 0 ≤ S.entropy ρ := by + rw [S.entropy_eq_vonNeumannEntropy hρ] + exact Matrix.vonNeumannEntropy_nonneg _ + +/-- The **matrix representation in an arbitrary orthonormal basis** `b` of the action space, a +`*`-isomorphism `N.algebra Λ ≃⋆ₐ Matrix ι`. The von Neumann entropy of the resulting density matrix +is independent of `b` (`vonNeumannEntropy_toDensityMatrixBasis`); this is the freedom of orthonormal +basis used to transport tensor-factorised marginals. -/ +noncomputable def toMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] + (b : OrthonormalBasis ι ℂ (ℋ Λ)) : N.algebra Λ ≃⋆ₐ[ℂ] Matrix ι ι ℂ := + (S.actₛ Λ).trans (LinearMap.toMatrixOrthonormal b) + +theorem toMatrixBasis_apply {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] + (b : OrthonormalBasis ι ℂ (ℋ Λ)) (x : N.algebra Λ) : + S.toMatrixBasis b x = LinearMap.toMatrixOrthonormal b (S.act Λ x) := + rfl + +theorem trace_eq_matrixTrace_basis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] + (b : OrthonormalBasis ι ℂ (ℋ Λ)) (ρ : N.algebra Λ) : + S.trace Λ ρ = (S.toMatrixBasis b ρ).trace := by + rw [toMatrixBasis_apply, LinearMap.trace_toMatrixOrthonormal, trace_apply] + +theorem continuous_toMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] + (b : OrthonormalBasis ι ℂ (ℋ Λ)) : Continuous (S.toMatrixBasis b) := by + haveI := S.finiteDimensional_algebra Λ + let L : N.algebra Λ →ₗ[ℂ] Matrix ι ι ℂ := + { toFun := S.toMatrixBasis b, map_add' := map_add _, map_smul' := map_smul _ } + exact L.continuous_of_finiteDimensional + +/-- The density matrix of a state in an arbitrary orthonormal basis `b` of the action space. -/ +noncomputable def toDensityMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] + (b : OrthonormalBasis ι ℂ (ℋ Λ)) {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + DensityMatrix ι where + toMatrix := S.toMatrixBasis b ρ + posSemidef := by + rw [toMatrixBasis_apply] + exact (LinearMap.posSemidef_toMatrix_iff b).mpr + ((LinearMap.nonneg_iff_isPositive _).mp hρ.nonneg) + trace_eq_one := by rw [← S.trace_eq_matrixTrace_basis b]; exact hρ.trace_eq_one + +@[simp] theorem toDensityMatrixBasis_toMatrix {Λ : Finset sites} {ι : Type*} [Fintype ι] + [DecidableEq ι] (b : OrthonormalBasis ι ℂ (ℋ Λ)) {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + (S.toDensityMatrixBasis b hρ).toMatrix = S.toMatrixBasis b ρ := + rfl + +/-- **Basis-independence of the von Neumann entropy**: the matrix von Neumann entropy of a state's +density matrix is the same in any orthonormal basis of the action space, and equals the +representation-free split-net entropy `S.entropy`. This is the freedom needed to compute marginal +entropies in a *tensor-factorised* orthonormal basis. -/ +theorem vonNeumannEntropy_toDensityMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] + [DecidableEq ι] (b : OrthonormalBasis ι ℂ (ℋ Λ)) {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : + Matrix.vonNeumannEntropy (S.toDensityMatrixBasis b hρ) = S.entropy ρ := by + haveI : IsScalarTower ℝ ℂ (N.algebra Λ) := IsScalarTower.complexToReal + have hsa : IsSelfAdjoint ρ := S.isSelfAdjoint_of_isDensity hρ + have hsa' : IsSelfAdjoint (S.toMatrixBasis b ρ) := + show star (S.toMatrixBasis b ρ) = S.toMatrixBasis b ρ by rw [← map_star, hsa] + rw [entropy_def, S.trace_eq_matrixTrace_basis b, Matrix.vonNeumannEntropy_eq_cfc_re, + toDensityMatrixBasis_toMatrix, + StarAlgHomClass.map_cfc (S.toMatrixBasis b) Real.negMulLog ρ + Real.continuous_negMulLog.continuousOn (S.continuous_toMatrixBasis b) hsa hsa'] + +/-- **The marginal of a state is a state.** Restricting a density operator to a sub-region yields a +density operator: the marginal preserves positivity (the partial trace along the *unitary* +factorisation `decompᵢ` is positivity-preserving, `LinearMap.isPositive_partialTrace`) and the +trace (`trace_restrict`). This is the representation-free statement that `restrict` is a quantum +channel on states. -/ +theorem restrict_isDensity {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') {ρ : N.algebra Λ'} + (hρ : S.IsDensity ρ) : S.IsDensity (S.restrict h ρ) := by + refine ⟨?_, ?_⟩ + · rw [LinearMap.nonneg_iff_isPositive, restrict_apply, AlgEquiv.apply_symm_apply] + have hpt := LinearMap.isPositive_partialTrace (S.decompᵢ h) + ((LinearMap.nonneg_iff_isPositive _).mp hρ.nonneg) + rwa [S.decompᵢ_toLinearEquiv h] at hpt + · rw [S.trace_restrict h ρ] + exact hρ.trace_eq_one + +/-- **Non-degeneracy of the trace pairing** on a local algebra: if `trace (A · X) = trace (B · X)` +for every `X`, then `A = B`. The trace form on the type I factor is non-degenerate +(`Matrix.ext_iff_trace_mul_right` through the matrix representation `toMatrix`). -/ +theorem trace_nondeg {Λ : Finset sites} {A B : N.algebra Λ} + (hAB : ∀ X, S.trace Λ (A * X) = S.trace Λ (B * X)) : A = B := by + apply (S.toMatrix Λ).injective + rw [Matrix.ext_iff_trace_mul_right] + intro Y + have hX := hAB ((S.toMatrix Λ).symm Y) + simp only [trace_eq_matrixTrace, map_mul, StarAlgEquiv.apply_symm_apply] at hX + exact hX + +/-- **Iterated marginalisation equals direct marginalisation**: +`restrict h₂ (restrict h₁ ρ) = restrict (h₂.trans h₁) ρ`. This is the coherence that strong +subadditivity needs — and it is **free**: it follows from the Heisenberg/trace duality +`trace_mul_incl` together with the net's functoriality `incl_trans`, with no associativity axiom on +the tensor factorisations. (The marginal is the predual of `incl`, and inclusions compose.) -/ +theorem restrict_restrict {Λ'' Λ Λ' : Finset sites} (h₁ : Λ ⊆ Λ') (h₂ : Λ'' ⊆ Λ) + (ρ : N.algebra Λ') : + S.restrict h₂ (S.restrict h₁ ρ) = S.restrict (h₂.trans h₁) ρ := by + apply S.trace_nondeg + intro X + rw [← S.trace_mul_incl h₂ (S.restrict h₁ ρ) X, ← S.trace_mul_incl (h₂.trans h₁) ρ X, + ← S.trace_mul_incl h₁ ρ (N.incl h₂ X), N.incl_trans h₂ h₁ X] + +/-- The **matrix Kraus operators** of the transported marginal: `Kⱼ = ⟨the matrix of the adjoint of +the partial-trace Kraus operator `Vⱼ` of `decompᵢ h`⟩`, in the standard orthonormal bases. -/ +noncomputable def restrictKraus {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') + (j : Fin (Module.finrank ℂ (ℋ (Λ' \ Λ)))) : + Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ'))) ℂ := + LinearMap.toMatrix (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis + (LinearMap.adjoint (LinearMap.ptKraus (S.decompᵢ h) j)) + +/-- **Matrix Kraus form of the marginal**: under the matrix representation, `restrict h` acts as +`M ↦ ∑ⱼ Kⱼ M Kⱼᴴ`. Transports the operator Kraus form `partialTrace_eq_sum_kraus`; exhibits the +transported marginal as a completely positive map. -/ +theorem toMatrix_restrict_eq_sum_kraus {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (ρ : N.algebra Λ') : + S.toMatrix Λ (S.restrict h ρ) + = ∑ j, S.restrictKraus h j * S.toMatrix Λ' ρ * (S.restrictKraus h j)ᴴ := by + have hact : S.act Λ (S.restrict h ρ) + = LinearMap.partialTrace (S.decompᵢ h).toLinearEquiv (S.act Λ' ρ) := by + rw [restrict_apply, AlgEquiv.apply_symm_apply, S.decompᵢ_toLinearEquiv h] + -- `toMatrixOrthonormal` is the matrix in the standard ON basis (clean `LinearMap.toMatrix` form). + have htmo : ∀ {Λ₀ : Finset sites} (g : Module.End ℂ (ℋ Λ₀)), + LinearMap.toMatrixOrthonormal (stdOrthonormalBasis ℂ (ℋ Λ₀)) g + = LinearMap.toMatrix (stdOrthonormalBasis ℂ (ℋ Λ₀)).toBasis + (stdOrthonormalBasis ℂ (ℋ Λ₀)).toBasis g := fun g => rfl + -- `(restrictKraus h j)ᴴ` is the matrix of the Kraus operator `Vⱼ` itself. + have hKt : ∀ j, (S.restrictKraus h j)ᴴ + = LinearMap.toMatrix (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis + (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (LinearMap.ptKraus (S.decompᵢ h) j) := by + intro j + rw [restrictKraus, LinearMap.toMatrix_adjoint, Matrix.conjTranspose_conjTranspose] + rw [toMatrix_apply, hact, LinearMap.partialTrace_eq_sum_kraus, map_sum] + refine Finset.sum_congr rfl fun j _ => ?_ + rw [hKt j, restrictKraus, toMatrix_apply] + simp only [htmo] + rw [LinearMap.toMatrix_comp (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis + (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis, + LinearMap.toMatrix_comp (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis + (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis, + Matrix.mul_assoc] + +end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean deleted file mode 100644 index f50f8cf..0000000 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityLocalNet.lean +++ /dev/null @@ -1,526 +0,0 @@ -module - -public import QuantumSystem.Analysis.Entropy.MutualInfoProduct -public import QuantumSystem.Analysis.Entropy.Regularize -public import QuantumSystem.Analysis.Matrix.KroneckerPartialTraceBridge - -/-! -# Strong subadditivity of the von Neumann entropy (SiteIndexSystem form) - -For a quantum system on a `SiteIndexSystem L`, the public theorem in this file is stated -in a **common-region-explicit** form. Given regions - -- `ΛAB ⊆ ΛABC`, -- `ΛBC ⊆ ΛABC`, -- `ΛB ⊆ ΛABC`, -- `ΛA ⊆ ΛAB`, -- `ΛAB \ ΛA = ΛB`, -- `ΛABC \ ΛA = ΛBC`, - -the **strong subadditivity** inequality states: - - `S(ρ ↾ ΛAB) + S(ρ ↾ ΛBC) ≥ S(ρ) + S(ρ ↾ ΛB)` - -This avoids encoding the theorem through positional subsystem names such as -`A/B/C` or a distinguished three-site tuple. The familiar three-site statement - - `S(ρ ↾ {a, b}) + S(ρ ↾ {b, c}) ≥ S(ρ) + S(ρ ↾ {b})` - -is recovered by instantiating - -- `ΛABC = {a, b, c}`, -- `ΛAB = {a, b}`, -- `ΛBC = {b, c}`, -- `ΛB = {b}`, -- `ΛA = {a}`. - -This file first establishes the **mutual-information identity** in product-type form, - - `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B)`, - -for a PosDef bipartite density matrix `ρ_AB : DensityMatrix (n × m)` whose canonical -partial traces coincide with PosDef factor states `ρ_A` and `ρ_B`. It then uses this -identity together with the data-processing inequality to prove SSA in the -AQFT-natural form: - -1. The bipartite **mutual-information identity** (`relativeEntropy_kronecker_marginals_product`) - applied twice — once for the `(ΛA vs ΛABC \ ΛA)` bipartition of the full system, - once for the `(ΛA vs ΛAB \ ΛA)` bipartition of the `ΛAB`-marginal. -2. The **data-processing inequality** for relative entropy - (`Matrix.relativeEntropy_channel_le`) applied to the SiteIndexSystem - `Matrix.QuantumChannel.restrict` channel for the inclusion `ΛAB ⊆ ΛABC`. - -## Main results - -* `Matrix.relativeEntropy_kronecker_marginals_product` — product-type mutual-information - identity. -* `DensityMatrix.vonNeumannEntropy_SSA_localNet` — SSA for arbitrary states on a - `SiteIndexSystem`, with the common region and split equalities explicit. - -The same inequality on a plain tensor product `A × B × C` is the companion -`DensityMatrix.vonNeumannEntropy_SSA_product` (`StrongSubadditivityProduct.lean`). - -## References - -* Nielsen, Chuang, *Quantum Computation and Quantum Information* §11.3 — quantum mutual - information `I(A:B) = S(ρ_A) + S(ρ_B) − S(ρ_AB)` and the relative-entropy identity - `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = I(A:B)`. --/ - -@[expose] public section - -/-! ### Strong subadditivity (SiteIndexSystem form, PosDef case) - -The main theorem. We use the bipartite mutual-information identity twice -(for `(A vs BC)` and for `(A vs B)` within `ρ ↾ {A, B}`) and the data-processing -inequality on the SiteIndexSystem `restrict` channel for `{A, B} ⊆ univ`. -/ - -namespace DensityMatrix - -open scoped Kronecker MatrixOrder ComplexOrder -open scoped Matrix.QuantumInfo -open scoped SiteIndexSystem.QuantumInfo - -variable {L : SiteIndexSystem} - -/-! #### Split-explicit nested-region SSA - -The next theorem is the region-level core of the three-site wrapper below. It is -parameterised by nested inclusions `ΛA ⊆ ΛAB ⊆ ΛABC`; the common/middle region is the -explicit complement `ΛAB \ ΛA`, and the other side is `ΛABC \ ΛA`. --/ - -/-- **Strong subadditivity (PosDef case, split-explicit nested-region form).** - -Given nested regions `ΛA ⊆ ΛAB ⊆ ΛABC`, write the middle/common region as -`ΛAB \ ΛA` and the complementary side as `ΛABC \ ΛA`. For a PosDef state `ρ_ABC` on -`ΛABC`, assuming the relevant marginals are PosDef, strong subadditivity is - -`S(ρ_ABC ↾ ΛAB) + S(ρ_ABC ↾ (ΛABC \ ΛA)) ≥ S(ρ_ABC) + S(ρ_ABC ↾ (ΛAB \ ΛA))`. - -This statement contains the split subset in the hypotheses and does not rely on -site names such as `a b c` or product-factor names such as `A/B`. -/ -private lemma vonNeumannEntropy_SSA_localNet_posDef_nested - {L : SiteIndexSystem} {ΛA ΛAB ΛABC : Finset L.sites} - (h_AB : ΛAB ⊆ ΛABC) (h_A : ΛA ⊆ ΛAB) - (ρ_ABC : L.densityMatrix ΛABC) - (h_ABC_pos : ρ_ABC.toMatrix.PosDef) - (h_A_pos : (ρ_ABC ↾[h_A.trans h_AB]).toMatrix.PosDef) - (h_AB_pos : (ρ_ABC ↾[h_AB]).toMatrix.PosDef) - (h_BC_pos : (ρ_ABC ↾[(Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)]).toMatrix.PosDef) - (h_B_pos : (ρ_ABC ↾[(Finset.sdiff_subset_sdiff h_AB (le_refl ΛA)).trans Finset.sdiff_subset]).toMatrix.PosDef) : - S(ρ_ABC ↾ ΛAB) + - S(ρ_ABC ↾[(Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)]) ≥ - S(ρ_ABC) + - S(ρ_ABC ↾[(Finset.sdiff_subset_sdiff h_AB (le_refl ΛA)).trans Finset.sdiff_subset]) := by - classical - set h_B_in_BC : (ΛAB \ ΛA) ⊆ (ΛABC \ ΛA) := - Finset.sdiff_subset_sdiff h_AB (le_refl ΛA) with hh_B_in_BC - set ρ_A : DensityMatrix (L.regionIdx ΛA) := - ρ_ABC ↾[h_A.trans h_AB] with hh_ρ_A - set ρ_AB : DensityMatrix (L.regionIdx ΛAB) := - ρ_ABC ↾[h_AB] with hh_ρ_AB - set ρ_BC : DensityMatrix (L.regionIdx (ΛABC \ ΛA)) := - ρ_ABC ↾[(Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)] with hh_ρ_BC - set ρ_B : DensityMatrix (L.regionIdx (ΛAB \ ΛA)) := - ρ_ABC ↾[h_B_in_BC.trans Finset.sdiff_subset] with hh_ρ_B - have hρ_A : ρ_A.toMatrix.PosDef := h_A_pos - have hρ_AB : ρ_AB.toMatrix.PosDef := h_AB_pos - have hρ_BC : ρ_BC.toMatrix.PosDef := h_BC_pos - have hρ_B : ρ_B.toMatrix.PosDef := h_B_pos - -- Bipartite views of `ρ` and `ρ_AB` via the explicit split subset. - set ρ_pt : DensityMatrix (L.regionIdx ΛA × L.regionIdx (ΛABC \ ΛA)) := - ρ_ABC.mapEquiv (L.combineIdx (h_A.trans h_AB)) with hρ_pt_def - have hρ_pt : ρ_pt.toMatrix.PosDef := h_ABC_pos.mapEquiv _ - set ρ_AB_pt : DensityMatrix (L.regionIdx ΛA × L.regionIdx (ΛAB \ ΛA)) := - ρ_AB.mapEquiv (L.combineIdx h_A) with hρ_AB_pt_def - have hρ_AB_pt : ρ_AB_pt.toMatrix.PosDef := hρ_AB.mapEquiv _ - have hρ_pt_sub : ρ_pt.toMatrix = - ρ_ABC.toMatrix.submatrix (L.combineIdx (h_A.trans h_AB)) - (L.combineIdx (h_A.trans h_AB)) := by - simp [hρ_pt_def, DensityMatrix.mapEquiv_toMatrix] - have hρ_AB_pt_sub : ρ_AB_pt.toMatrix = - ρ_AB.toMatrix.submatrix (L.combineIdx h_A) (L.combineIdx h_A) := by - simp [hρ_AB_pt_def, DensityMatrix.mapEquiv_toMatrix] - -- Product reference state for the full split and its lift back to `ΛABC`. - set σ_pt : DensityMatrix (L.regionIdx ΛA × L.regionIdx (ΛABC \ ΛA)) := - ρ_A ⊗ ρ_BC with hσ_pt_def - have hσ_pt : σ_pt.toMatrix.PosDef := by - rw [hσ_pt_def, DensityMatrix.kronecker_toMatrix] - exact hρ_A.kronecker hρ_BC - set σ_full : L.densityMatrix ΛABC := - σ_pt.mapEquiv (L.combineIdx (h_A.trans h_AB)).symm with hσ_full_def - have hσ_full : σ_full.toMatrix.PosDef := hσ_pt.mapEquiv _ - -- Mutual-information identity for the full split. - have h_ptA_ρ_pt : tr₂(ρ_pt.toMatrix) = ρ_A.toMatrix := by - ext x x' - rw [hρ_pt_sub, ← Matrix.restrict_eq_partialTrace_combineIdx] - rfl - have h_ptBC_ρ_pt : tr₁(ρ_pt.toMatrix) = ρ_BC.toMatrix := by - ext y y' - rw [hρ_pt_sub, ← Matrix.restrict_compl_eq_partialTrace_combineIdx - (h_A.trans h_AB)] - rfl - have h_mut_full : - D(ρ_pt ∥ σ_pt) = -S(ρ_pt) + S(ρ_A) + S(ρ_BC) := - Matrix.relativeEntropy_kronecker_marginals_product ρ_pt ρ_A hρ_A ρ_BC hρ_BC - h_ptA_ρ_pt h_ptBC_ρ_pt - -- Mutual-information identity for the `ΛA ⊆ ΛAB` split. - have h_ptA_AB : tr₂(ρ_AB_pt.toMatrix) = ρ_A.toMatrix := by - ext x x' - rw [hρ_AB_pt_sub, ← Matrix.restrict_eq_partialTrace_combineIdx] - change ((ρ_ABC ↾[h_AB]) ↾[h_A]).toMatrix x x' = - (ρ_ABC ↾[h_A.trans h_AB]).toMatrix x x' - rw [DensityMatrix.restrict_restrict] - have h_ptB_AB : tr₁(ρ_AB_pt.toMatrix) = ρ_B.toMatrix := by - ext y y' - rw [hρ_AB_pt_sub, ← Matrix.restrict_compl_eq_partialTrace_combineIdx h_A] - change ((ρ_ABC ↾[h_AB]) ↾[(Finset.sdiff_subset : - ΛAB \ ΛA ⊆ ΛAB)]).toMatrix y y' = - (ρ_ABC ↾[h_B_in_BC.trans Finset.sdiff_subset]).toMatrix y y' - rw [DensityMatrix.restrict_restrict] - have h_mut_AB : - D(ρ_AB_pt ∥ ρ_A ⊗ ρ_B) = -S(ρ_AB_pt) + S(ρ_A) + S(ρ_B) := - Matrix.relativeEntropy_kronecker_marginals_product ρ_AB_pt ρ_A hρ_A ρ_B hρ_B - h_ptA_AB h_ptB_AB - -- DPI for restriction from `ΛABC` to `ΛAB`. - set Φ : Matrix.QuantumChannel (L.regionIdx ΛABC) (L.regionIdx ΛAB) := - Matrix.QuantumChannel.restrict h_AB with hΦ_def - have h_Φρ_mat : ((Φ : Matrix.QuantumChannel _ _) ρ_ABC).toMatrix = ρ_AB.toMatrix := by - change (ρ_ABC ↾[h_AB]).toMatrix = ρ_AB.toMatrix - rfl - have h_Φρ_pos : ((Φ : Matrix.QuantumChannel _ _) ρ_ABC).toMatrix.PosDef := h_Φρ_mat ▸ hρ_AB - -- Restricting the lifted product state gives the product of the restricted factors. - have h_Φσ_mat : - ((Φ : Matrix.QuantumChannel _ _) σ_full).toMatrix = - (ρ_A ⊗ ρ_B).toMatrix.submatrix - (L.combineIdx h_A).symm (L.combineIdx h_A).symm := by - change Matrix.restrict h_AB σ_full.toMatrix = _ - ext s s' - rw [show s = (L.combineIdx h_A) - ((L.combineIdx h_A).symm s) from - ((L.combineIdx h_A).apply_symm_apply s).symm, - show s' = (L.combineIdx h_A) - ((L.combineIdx h_A).symm s') from - ((L.combineIdx h_A).apply_symm_apply s').symm] - set p := (L.combineIdx h_A).symm s with hp - set p' := (L.combineIdx h_A).symm s' with hp' - rw [Matrix.restrict_apply, Matrix.submatrix_apply] - simp only [Equiv.symm_apply_apply] - simp_rw [Matrix.combineIdx_assoc_eq h_AB h_A] - have h_σ_full_apply : ∀ (x x' : L.regionIdx ΛA) - (y y' : L.regionIdx (ΛABC \ ΛA)), - σ_full.toMatrix - (L.combineIdx (h_A.trans h_AB) (x, y)) - (L.combineIdx (h_A.trans h_AB) (x', y')) = - σ_pt.toMatrix (x, y) (x', y') := by - intro x x' y y' - simp [hσ_full_def, DensityMatrix.mapEquiv_toMatrix, - Matrix.submatrix_apply, Equiv.symm_apply_apply] - simp_rw [h_σ_full_apply] - rw [hσ_pt_def, DensityMatrix.kronecker_toMatrix] - simp only [Matrix.kronecker_apply] - rw [← Finset.mul_sum] - rw [DensityMatrix.kronecker_toMatrix, Matrix.kronecker_apply] - congr 1 - rw [show ρ_B.toMatrix p.2 p'.2 = Matrix.restrict h_B_in_BC ρ_BC.toMatrix p.2 p'.2 - from by - change Matrix.restrict (h_B_in_BC.trans Finset.sdiff_subset) ρ_ABC.toMatrix p.2 p'.2 = - Matrix.restrict h_B_in_BC (Matrix.restrict Finset.sdiff_subset ρ_ABC.toMatrix) p.2 p'.2 - rw [Matrix.restrict_restrict], - Matrix.restrict_eq_partialTrace_combineIdx h_B_in_BC, - Matrix.partialTrace_refl_apply] - have h_compl_eq : (ΛABC \ ΛA) \ (ΛAB \ ΛA) = ΛABC \ ΛAB := by - ext x - simp only [Finset.mem_sdiff] - constructor - · rintro ⟨⟨hxABC, hxA⟩, hx_not_BminusA⟩ - exact ⟨hxABC, fun hxAB => hx_not_BminusA ⟨hxAB, hxA⟩⟩ - · rintro ⟨hxABC, hxAB⟩ - exact ⟨⟨hxABC, fun hxA => hxAB (h_A hxA)⟩, - fun hxBminusA => hxAB hxBminusA.1⟩ - rw [← (L.regionIdxCongr h_compl_eq.symm).sum_comp - (fun b => ρ_BC.toMatrix.submatrix (L.combineIdx h_B_in_BC) (L.combineIdx h_B_in_BC) - (p.2, b) (p'.2, b))] - refine Finset.sum_congr rfl fun γ _ => ?_ - have hR_eq : ∀ (z : L.regionIdx (ΛAB \ ΛA)), - Matrix.restrictAssocEquiv h_AB h_A (z, γ) = - L.combineIdx h_B_in_BC (z, L.regionIdxCongr h_compl_eq.symm γ) := by - intro z - funext ⟨v, hv⟩ - by_cases hv_in_AB : v ∈ ΛAB - · have hv_in_combine : v ∈ ΛAB \ ΛA := - Finset.mem_sdiff.mpr ⟨hv_in_AB, (Finset.mem_sdiff.mp hv).2⟩ - rw [SiteIndexSystem.combineIdx_apply_mem h_B_in_BC _ _ ⟨v, hv⟩ hv_in_combine] - exact dif_pos hv_in_AB - · have hv_not_in_combine : v ∉ ΛAB \ ΛA := fun h_in => - hv_in_AB (Finset.mem_sdiff.mp h_in).1 - have hv_compl : v ∈ ΛABC \ ΛAB := - Finset.mem_sdiff.mpr ⟨(Finset.mem_sdiff.mp hv).1, hv_in_AB⟩ - have hv_compl_compl : v ∈ (ΛABC \ ΛA) \ (ΛAB \ ΛA) := - Finset.mem_sdiff.mpr ⟨hv, hv_not_in_combine⟩ - rw [SiteIndexSystem.combineIdx_apply_not_mem h_B_in_BC _ _ ⟨v, hv⟩ hv_not_in_combine, - show L.regionIdxCongr h_compl_eq.symm γ ⟨v, hv_compl_compl⟩ = γ ⟨v, hv_compl⟩ - from SiteIndexSystem.regionIdxCongr_apply (L := L) h_compl_eq.symm γ hv_compl hv_compl_compl] - exact dif_neg hv_in_AB - rw [hR_eq p.2, hR_eq p'.2] - rfl - have h_Φσ_pos : ((Φ : Matrix.QuantumChannel _ _) σ_full).toMatrix.PosDef := by - rw [h_Φσ_mat] - have h_kron_pos : (ρ_A ⊗ ρ_B).toMatrix.PosDef := by - rw [DensityMatrix.kronecker_toMatrix] - exact hρ_A.kronecker hρ_B - exact h_kron_pos.mapEquiv _ - have h_dpi : - D((Φ : Matrix.QuantumChannel _ _) ρ_ABC ∥ (Φ : Matrix.QuantumChannel _ _) σ_full) ≤ - D(ρ_ABC ∥ σ_full) := - Matrix.relativeEntropy_channel_le Φ ρ_ABC σ_full - have h_dpi_lhs : - D((Φ : Matrix.QuantumChannel _ _) ρ_ABC ∥ (Φ : Matrix.QuantumChannel _ _) σ_full) = - D(ρ_AB_pt ∥ ρ_A ⊗ ρ_B) := by - have h_Φρ_dm : (Φ : Matrix.QuantumChannel _ _) ρ_ABC = - ρ_AB_pt.mapEquiv (L.combineIdx h_A).symm := by - apply DensityMatrix.ext - rw [h_Φρ_mat, DensityMatrix.mapEquiv_toMatrix, hρ_AB_pt_sub, - Matrix.submatrix_submatrix] - simp - have h_Φσ_dm : (Φ : Matrix.QuantumChannel _ _) σ_full = - (ρ_A ⊗ ρ_B).mapEquiv (L.combineIdx h_A).symm := by - apply DensityMatrix.ext - exact h_Φσ_mat - rw [h_Φρ_dm, h_Φσ_dm] - have h_kron_pos : (ρ_A ⊗ ρ_B).toMatrix.PosDef := by - rw [DensityMatrix.kronecker_toMatrix] - exact hρ_A.kronecker hρ_B - exact Matrix.relativeEntropy_mapEquiv_posDef _ _ hρ_AB_pt h_kron_pos _ - have h_ρ_eq_pt : ρ_ABC = ρ_pt.mapEquiv (L.combineIdx (h_A.trans h_AB)).symm := by - apply DensityMatrix.ext - rw [DensityMatrix.mapEquiv_toMatrix, hρ_pt_sub, Matrix.submatrix_submatrix] - simp - have h_σ_full_eq_pt : - σ_full = σ_pt.mapEquiv (L.combineIdx (h_A.trans h_AB)).symm := rfl - have h_dpi_rhs : D(ρ_ABC ∥ σ_full) = D(ρ_pt ∥ σ_pt) := by - rw [h_ρ_eq_pt, h_σ_full_eq_pt] - exact Matrix.relativeEntropy_mapEquiv_posDef _ _ hρ_pt hσ_pt _ - have h_Sρ_eq : S(ρ_ABC) = S(ρ_pt) := by - rw [h_ρ_eq_pt] - exact Matrix.vonNeumannEntropy_mapEquiv_posDef _ hρ_pt _ - have h_SρAB_eq : S(ρ_AB) = S(ρ_AB_pt) := by - rw [show ρ_AB = ρ_AB_pt.mapEquiv (L.combineIdx h_A).symm from by - apply DensityMatrix.ext - rw [DensityMatrix.mapEquiv_toMatrix, hρ_AB_pt_sub, Matrix.submatrix_submatrix] - simp] - exact Matrix.vonNeumannEntropy_mapEquiv_posDef _ hρ_AB_pt _ - rw [h_dpi_lhs, h_dpi_rhs] at h_dpi - rw [h_mut_AB, h_mut_full] at h_dpi - rw [h_Sρ_eq, h_SρAB_eq] - have h_real : - -S(ρ_AB_pt) + S(ρ_A) + S(ρ_B) ≤ - -S(ρ_pt) + S(ρ_A) + S(ρ_BC) := by - exact_mod_cast h_dpi - linarith - -/-! #### Finset-equality bridges for the user-facing wrapper - -For two `Λ ⊆ Λ_total` and `Λ' ⊆ Λ_total` Subset proofs whose Finsets are propositionally -equal (`Λ = Λ'`), the partial-trace `restrict h ρ` and `restrict h' ρ` are essentially -identical: their entropies and PosDef status agree. Discharged by `subst h_eq` plus -proof-irrelevance for `Subset`. Used in `vonNeumannEntropy_SSA_localNet_posDef` to bridge -user-facing `S(restrict h_BC ρ)` (with `{b,c}`) to the bipartite-natural form -`S(restrict sdiff_subset ρ)` (with `{a,b,c} \ {a}`). -/ - -private lemma vonNeumannEntropy_restrict_finset_eq - {L : SiteIndexSystem} {Λ Λ' Λ_total : Finset L.sites} (h_eq : Λ = Λ') - (h : Λ ⊆ Λ_total) (h' : Λ' ⊆ Λ_total) (ρ : L.densityMatrix Λ_total) : - S(ρ ↾[h]) = S(ρ ↾[h']) := by - subst h_eq - rfl - -private lemma posDef_restrict_finset_eq - {L : SiteIndexSystem} {Λ Λ' Λ_total : Finset L.sites} (h_eq : Λ = Λ') - (h : Λ ⊆ Λ_total) (h' : Λ' ⊆ Λ_total) (ρ : L.densityMatrix Λ_total) : - (ρ ↾[h]).toMatrix.PosDef ↔ (ρ ↾[h']).toMatrix.PosDef := by - subst h_eq - rfl - -/-- **Strong subadditivity (PosDef case, common-region-explicit form).** - -This is the public region-level wrapper around -`vonNeumannEntropy_SSA_localNet_posDef_nested`. The theorem does not infer the common region from -the names `a b c` or from a product-factor order. Instead it receives explicit data: - -* `ΛAB ⊆ ΛABC`, the first two-block marginal, -* `ΛA ⊆ ΛAB`, the split used inside `ΛAB`, -* `ΛBC ⊆ ΛABC`, the other two-block marginal, -* `ΛB ⊆ ΛABC`, the common/middle marginal, -* `ΛAB \ ΛA = ΛB`, identifying the common region, -* `ΛABC \ ΛA = ΛBC`, identifying the side obtained by tracing out `ΛA`. - -Under PosDef hypotheses for the displayed marginals, the conclusion is exactly -`S(ρ_ABC ↾ ΛAB) + S(ρ_ABC ↾ ΛBC) ≥ S(ρ_ABC) + S(ρ_ABC ↾ ΛB)`. -/ -private lemma vonNeumannEntropy_SSA_localNet_posDef - {L : SiteIndexSystem} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} - (h_AB_total : ΛAB ⊆ ΛABC) (h_A_in_AB : ΛA ⊆ ΛAB) - (h_BC_total : ΛBC ⊆ ΛABC) (h_B_total : ΛB ⊆ ΛABC) - (h_B_eq : ΛAB \ ΛA = ΛB) (h_BC_eq : ΛABC \ ΛA = ΛBC) - (ρ_ABC : L.densityMatrix ΛABC) - (h_ABC_pos : ρ_ABC.toMatrix.PosDef) - (h_A_pos : (ρ_ABC ↾[h_A_in_AB.trans h_AB_total]).toMatrix.PosDef) - (h_AB_pos : (ρ_ABC ↾[h_AB_total]).toMatrix.PosDef) - (h_BC_pos : (ρ_ABC ↾[h_BC_total]).toMatrix.PosDef) - (h_B_pos : (ρ_ABC ↾[h_B_total]).toMatrix.PosDef) : - S(ρ_ABC ↾[h_AB_total]) + S(ρ_ABC ↾[h_BC_total]) ≥ - S(ρ_ABC) + S(ρ_ABC ↾[h_B_total]) := by - classical - let h_B_nested : (ΛAB \ ΛA) ⊆ ΛABC := - (Finset.sdiff_subset_sdiff h_AB_total (le_refl ΛA)).trans Finset.sdiff_subset - have h_BC_pos_nested : - (ρ_ABC ↾[(Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)]).toMatrix.PosDef := - posDef_restrict_finset_eq h_BC_eq.symm h_BC_total Finset.sdiff_subset ρ_ABC |>.mp h_BC_pos - have h_B_pos_nested : (ρ_ABC ↾[h_B_nested]).toMatrix.PosDef := - posDef_restrict_finset_eq h_B_eq.symm h_B_total h_B_nested ρ_ABC |>.mp h_B_pos - have h_nested := vonNeumannEntropy_SSA_localNet_posDef_nested h_AB_total h_A_in_AB ρ_ABC h_ABC_pos - h_A_pos h_AB_pos h_BC_pos_nested h_B_pos_nested - have h_S_BC : S(ρ_ABC ↾[h_BC_total]) = - S(ρ_ABC ↾[(Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)]) := - vonNeumannEntropy_restrict_finset_eq h_BC_eq.symm - h_BC_total Finset.sdiff_subset ρ_ABC - have h_S_B : S(ρ_ABC ↾[h_B_total]) = S(ρ_ABC ↾[h_B_nested]) := - vonNeumannEntropy_restrict_finset_eq h_B_eq.symm h_B_total h_B_nested ρ_ABC - rwa [← h_S_BC, ← h_S_B] at h_nested - - -/-- **Strong subadditivity (common-region-explicit form, no PosDef hypothesis).** - -PosDef-free version of `vonNeumannEntropy_SSA_localNet_posDef`. Given the geometric data of a -common-region split - -* `ΛAB ⊆ ΛABC`, `ΛA ⊆ ΛAB`, `ΛBC ⊆ ΛABC`, `ΛB ⊆ ΛABC`, -* `ΛAB \ ΛA = ΛB`, `ΛABC \ ΛA = ΛBC`, - -and `[Nonempty (L.regionIdx ΛABC)]` (which propagates to every sub-region by -`regionIdx_nonempty_of_subset`), strong subadditivity holds for every density matrix -`ρ_ABC : L.densityMatrix ΛABC`: - - `S(ρ_ABC ↾ ΛAB) + S(ρ_ABC ↾ ΛBC) ≥ S(ρ_ABC) + S(ρ_ABC ↾ ΛB)`. - -The proof regularises `ρ` to the PosDef state `(1 - ε) ρ + ε · π_ΛABC` for `ε ∈ (0, 1]`, -applies `vonNeumannEntropy_SSA_localNet_posDef`, and passes to the limit `ε → 0⁺` -via the eigenvalue continuity formulas in `Regularize.lean`. -/ -theorem vonNeumannEntropy_SSA_localNet - {L : SiteIndexSystem} {ΛA ΛB ΛAB ΛBC ΛABC : Finset L.sites} - (h_AB : ΛAB ⊆ ΛABC) (h_A : ΛA ⊆ ΛAB) - (h_BC : ΛBC ⊆ ΛABC) (h_B : ΛB ⊆ ΛABC) - (h_B_eq : ΛAB \ ΛA = ΛB) (h_BC_eq : ΛABC \ ΛA = ΛBC) - [Nonempty (L.regionIdx ΛABC)] - (ρ_ABC : L.densityMatrix ΛABC) : - S(ρ_ABC ↾[h_AB]) + S(ρ_ABC ↾[h_BC]) ≥ - S(ρ_ABC) + S(ρ_ABC ↾[h_B]) := by - -- Sub-region Nonempty instances, derived from `Nonempty (regionIdx ΛABC)`. - haveI : Nonempty (L.regionIdx ΛAB) := L.regionIdx_nonempty_of_subset h_AB - haveI : Nonempty (L.regionIdx ΛBC) := L.regionIdx_nonempty_of_subset h_BC - haveI : Nonempty (L.regionIdx ΛB) := L.regionIdx_nonempty_of_subset h_B - haveI : Nonempty (L.regionIdx ΛA) := - L.regionIdx_nonempty_of_subset (h_A.trans h_AB) - -- Marginals and eigenvalue-formula functions. - set ρ_AB := ρ_ABC ↾[h_AB] with hρ_AB - set ρ_BC := ρ_ABC ↾[h_BC] with hρ_BC - set ρ_B := ρ_ABC ↾[h_B] with hρ_B - let f_AB : ℝ → ℝ := fun ε => - ∑ i, Real.negMulLog ((1 - ε) * ρ_AB.isHermitian.eigenvalues i + - ε / Fintype.card (L.regionIdx ΛAB)) - let f_BC : ℝ → ℝ := fun ε => - ∑ i, Real.negMulLog ((1 - ε) * ρ_BC.isHermitian.eigenvalues i + - ε / Fintype.card (L.regionIdx ΛBC)) - let f_full : ℝ → ℝ := fun ε => - ∑ i, Real.negMulLog ((1 - ε) * ρ_ABC.isHermitian.eigenvalues i + - ε / Fintype.card (L.regionIdx ΛABC)) - let f_B : ℝ → ℝ := fun ε => - ∑ i, Real.negMulLog ((1 - ε) * ρ_B.isHermitian.eigenvalues i + - ε / Fintype.card (L.regionIdx ΛB)) - -- For ε ∈ (0, 1]: regularised state and its 4 marginals are PosDef, so the PosDef - -- common-region SSA applies. - have h_ineq_pos : ∀ ε : ℝ, 0 < ε → ε ≤ 1 → - f_full ε + f_B ε ≤ f_AB ε + f_BC ε := by - intro ε hε_pos hε_le - have hρ_reg_pos : - (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).toMatrix.PosDef := - DensityMatrix.regularize_posDef ρ_ABC hε_pos hε_le - have h_AB_eq_reg := - regularize_restrict_toMatrix h_AB ρ_ABC hε_pos.le hε_le - have h_BC_eq_reg := - regularize_restrict_toMatrix h_BC ρ_ABC hε_pos.le hε_le - have h_A_eq_reg := - regularize_restrict_toMatrix (h_A.trans h_AB) ρ_ABC hε_pos.le hε_le - have h_B_eq_reg := - regularize_restrict_toMatrix h_B ρ_ABC hε_pos.le hε_le - have hAB_reg_pos : - ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) ↾[h_AB]).toMatrix.PosDef - := by - change (Matrix.restrict h_AB - (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).toMatrix).PosDef - rw [h_AB_eq_reg]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le - have hBC_reg_pos : - ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) ↾[h_BC]).toMatrix.PosDef - := by - change (Matrix.restrict h_BC - (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).toMatrix).PosDef - rw [h_BC_eq_reg]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le - have hA_reg_pos : - ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) - ↾[h_A.trans h_AB]).toMatrix.PosDef := by - change (Matrix.restrict (h_A.trans h_AB) - (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).toMatrix).PosDef - rw [h_A_eq_reg]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le - have hB_reg_pos : - ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) ↾[h_B]).toMatrix.PosDef - := by - change (Matrix.restrict h_B - (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).toMatrix).PosDef - rw [h_B_eq_reg]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le - have h_ssa := vonNeumannEntropy_SSA_localNet_posDef - h_AB h_A h_BC h_B h_B_eq h_BC_eq - (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) - hρ_reg_pos hA_reg_pos hAB_reg_pos hBC_reg_pos hB_reg_pos - have h_AB_dm := regularize_restrict h_AB ρ_ABC hε_pos.le hε_le - have h_BC_dm := regularize_restrict h_BC ρ_ABC hε_pos.le hε_le - have h_B_dm := regularize_restrict h_B ρ_ABC hε_pos.le hε_le - rw [h_AB_dm, h_BC_dm, h_B_dm] at h_ssa - have ef_AB := - Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_AB hε_pos.le hε_le - have ef_BC := - Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_BC hε_pos.le hε_le - have ef_full := - Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_ABC hε_pos.le hε_le - have ef_B := - Matrix.vonNeumannEntropy_regularize_eq_negMulLog_sum ρ_B hε_pos.le hε_le - rw [ef_AB, ef_BC, ef_full, ef_B] at h_ssa - exact h_ssa - have h_cont_AB : Filter.Tendsto f_AB (nhds 0) (nhds S(ρ_AB)) := - Matrix.tendsto_negMulLog_regularize_sum_zero ρ_AB - have h_cont_BC : Filter.Tendsto f_BC (nhds 0) (nhds S(ρ_BC)) := - Matrix.tendsto_negMulLog_regularize_sum_zero ρ_BC - have h_cont_full : Filter.Tendsto f_full (nhds 0) (nhds S(ρ_ABC)) := - Matrix.tendsto_negMulLog_regularize_sum_zero ρ_ABC - have h_cont_B : Filter.Tendsto f_B (nhds 0) (nhds S(ρ_B)) := - Matrix.tendsto_negMulLog_regularize_sum_zero ρ_B - have h_within : ∀ᶠ ε in nhdsWithin (0 : ℝ) (Set.Ioi 0), - f_full ε + f_B ε ≤ f_AB ε + f_BC ε := by - rw [eventually_nhdsWithin_iff] - have h_le_one : ∀ᶠ ε in nhds (0 : ℝ), ε ≤ 1 := - Filter.eventually_of_mem (IsOpen.mem_nhds isOpen_Iio (by norm_num : (0 : ℝ) < 1)) <| by - intros ε hε - exact le_of_lt hε - filter_upwards [h_le_one] with ε hε_le_one hε_pos - exact h_ineq_pos ε hε_pos hε_le_one - have h_LHS_lim : - Filter.Tendsto (fun ε => f_AB ε + f_BC ε) (nhdsWithin (0 : ℝ) (Set.Ioi 0)) - (nhds (S(ρ_AB) + S(ρ_BC))) := - (h_cont_AB.add h_cont_BC).mono_left nhdsWithin_le_nhds - have h_RHS_lim : - Filter.Tendsto (fun ε => f_full ε + f_B ε) (nhdsWithin (0 : ℝ) (Set.Ioi 0)) - (nhds (S(ρ_ABC) + S(ρ_B))) := - (h_cont_full.add h_cont_B).mono_left nhdsWithin_le_nhds - exact le_of_tendsto_of_tendsto h_RHS_lim h_LHS_lim h_within - -end DensityMatrix diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean index 8295b8f..d18f714 100644 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean @@ -4,21 +4,21 @@ public import QuantumSystem.Analysis.Channel.PartialTrace public import QuantumSystem.Analysis.Entropy.MutualInfoProduct /-! -# Strong subadditivity of the von Neumann entropy (product form, `SiteIndexSystem`-free) +# Strong subadditivity of the von Neumann entropy (product form) This file proves strong subadditivity (SSA) directly on plain product index types `A × B × C`, with marginals taken by the positional partial traces `Matrix.traceLeft` / -`Matrix.traceRight`. It uses NO `SiteIndexSystem`, `regionIdx`, `combineIdx`, `restrict`, or -three-site net: the proof is the bare finite-dimensional quantum-information argument +`Matrix.traceRight`. It is representation-free — no net structure — the proof is the bare +finite-dimensional quantum-information argument 1. the mutual-information identity `Matrix.relativeEntropy_kronecker_marginals_product` (applied to the `(A : B×C)` and `(A : B)` bipartitions), and 2. the data-processing inequality `Matrix.relativeEntropy_channel_le` for the trace-out-`C` channel `Matrix.QuantumChannel.traceOutC`. -The `SiteIndexSystem`/AQFT companion — the same inequality stated over a lattice system -with overlapping regions — is `DensityMatrix.vonNeumannEntropy_SSA_localNet` -(`StrongSubadditivityLocalNet.lean`). +The AQFT companion — the same inequality stated representation-free over an abstract operator- +algebraic split net with nested regions — is `LocalNet.Split.vonNeumannEntropy_SSA` +(`SplitSSA.lean`), which transports this product-form result to the net. ## Main results diff --git a/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean b/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean deleted file mode 100644 index 2d2d89e..0000000 --- a/QuantumSystem/Analysis/Matrix/KroneckerPartialTraceBridge.lean +++ /dev/null @@ -1,84 +0,0 @@ -module - -public import QuantumSystem.Analysis.Entropy.KroneckerProduct -public import QuantumSystem.Analysis.Matrix.PartialTrace - -/-! -# SiteIndexSystem bridge: restriction as an equivalence-indexed partial trace - -These lemmas identify the `SiteIndexSystem` restriction `Matrix.restrict` with the equivalence-indexed -partial trace `Matrix.partialTrace` of the reindexed matrix induced by `SiteIndexSystem.combineIdx`. -They are factored out of `Analysis/Entropy/KroneckerProduct.lean` so that the Kronecker-product -and product-type partial-trace API there stays `SiteIndexSystem`-free. --/ - -@[expose] public section - -namespace Matrix - -open scoped Kronecker MatrixOrder ComplexOrder - -/-! ### SiteIndexSystem bridge - -These lemmas identify `Matrix.restrict` on a `SiteIndexSystem` with the equivalence-indexed -partial trace of the reindexed matrix induced by `SiteIndexSystem.combineIdx`. -/ - -section LocalNetBridge - -variable {L : SiteIndexSystem} - -/-- Combining via `h : Λ ⊆ Λ_total` agrees with combining via the complementary split, -after transporting the remaining factor along `Λ_total \ (Λ_total \ Λ) = Λ`. -/ -private lemma combineIdx_swap_apply - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (x : L.regionIdx Λ) (y : L.regionIdx (Λ_total \ Λ)) : - L.combineIdx h (x, y) = - L.combineIdx Finset.sdiff_subset - (y, L.regionIdxCongr (sdiff_sdiff_eq_self h).symm x) := by - have h_eq : Λ_total \ (Λ_total \ Λ) = Λ := sdiff_sdiff_eq_self h - funext ⟨s, hs⟩ - by_cases hsΛ : s ∈ Λ - · have hns_compl : s ∉ Λ_total \ Λ := fun h_in => (Finset.mem_sdiff.mp h_in).2 hsΛ - have hs_recast : s ∈ Λ_total \ (Λ_total \ Λ) := by - rw [h_eq] - exact hsΛ - rw [SiteIndexSystem.combineIdx_apply_mem h _ _ ⟨s, hs⟩ hsΛ, - SiteIndexSystem.combineIdx_apply_not_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hns_compl, - SiteIndexSystem.regionIdxCongr_apply (L := L) h_eq.symm x hsΛ hs_recast] - · have hs_compl : s ∈ Λ_total \ Λ := Finset.mem_sdiff.mpr ⟨hs, hsΛ⟩ - rw [SiteIndexSystem.combineIdx_apply_not_mem h _ _ ⟨s, hs⟩ hsΛ, - SiteIndexSystem.combineIdx_apply_mem Finset.sdiff_subset _ _ ⟨s, hs⟩ hs_compl] - -/-- Restriction to `Λ` equals the partial trace of the reindexed matrix induced by -`combineIdx h`, retaining the `Λ` factor. -/ -theorem restrict_eq_partialTrace_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.localAlgebra Λ_total) (x x' : L.regionIdx Λ) : - Matrix.restrict h ρ x x' = - Matrix.partialTrace - (A := L.regionIdx Λ) (B := L.regionIdx (Λ_total \ Λ)) - (Equiv.refl (L.regionIdx Λ × L.regionIdx (Λ_total \ Λ))) - (ρ.submatrix (L.combineIdx h) (L.combineIdx h)) x x' := by - rw [Matrix.partialTrace_refl_apply, Matrix.restrict_apply] - simp [Matrix.submatrix_apply] - -/-- Restriction to the complement of `Λ` equals the partial trace of the reindexed matrix -induced by `combineIdx h`, retaining the complementary factor. -/ -theorem restrict_compl_eq_partialTrace_combineIdx - {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.localAlgebra Λ_total) (y y' : L.regionIdx (Λ_total \ Λ)) : - Matrix.restrict Finset.sdiff_subset ρ y y' = - Matrix.partialTrace - (A := L.regionIdx (Λ_total \ Λ)) (B := L.regionIdx Λ) - (Equiv.prodComm (L.regionIdx Λ) (L.regionIdx (Λ_total \ Λ))) - (ρ.submatrix (L.combineIdx h) (L.combineIdx h)) y y' := by - rw [Matrix.partialTrace_prodComm_apply, Matrix.restrict_apply] - rw [← (L.regionIdxCongr (sdiff_sdiff_eq_self h).symm).sum_comp - (fun z => ρ (L.combineIdx Finset.sdiff_subset (y, z)) - (L.combineIdx Finset.sdiff_subset (y', z)))] - refine Finset.sum_congr rfl fun x _ => ?_ - rw [Matrix.submatrix_apply, combineIdx_swap_apply h x y, combineIdx_swap_apply h x y'] - -end LocalNetBridge - -end Matrix diff --git a/QuantumSystem/Analysis/Matrix/PartialTrace.lean b/QuantumSystem/Analysis/Matrix/PartialTrace.lean deleted file mode 100644 index ce46e05..0000000 --- a/QuantumSystem/Analysis/Matrix/PartialTrace.lean +++ /dev/null @@ -1,439 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.MatrixModel.Isotony -public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace - -/-! -# Partial trace as restriction (matrix-level) - -The **restriction** (Schrödinger-picture partial trace) on the matrix algebra of a local -net. Given regions `Λ ⊆ Λ_total` of a `SiteIndexSystem`, the restriction of a matrix on -`𝔄(Λ_total)` to `𝔄(Λ)` is defined as the partial trace over the complementary region -`Λ_total \ Λ`. This is the Schrödinger-picture dual of the algebra -inclusion `𝔄(Λ) ↪ 𝔄(Λ_total)`. There is no positional ("left/right") concept — the -operation is parameterised by the region itself. - -The matrix-level operation `Matrix.restrict` is defined as a linear map factoring through -`SiteIndexSystem.combineIdx` (which factors `regionIdx Λ_total ≃ regionIdx Λ × regionIdx (Λ_total \ Λ)`). -The bundled quantum-channel structure, Kraus operators, trace preservation, and -Heisenberg-picture duality are also provided. - -## Main definitions - -* `Matrix.restrict` — linear restriction map (matrix-level partial trace) -* `Matrix.restrictKraus` — Kraus operators indexed by the complementary region -* `Matrix.QuantumChannel.restrict` — bundled quantum channel -* `DensityMatrix.restrict` — restriction applied to density matrices -* `ρ ↾ Λ` — paper-style notation for `DensityMatrix.restrict` - -## Main results - -* `Matrix.restrict_eq_sum_kraus` — Kraus form -* `Matrix.isCompletelyPositive_restrict`, `Matrix.isTracePreserving_restrict`, - `Matrix.isQuantumChannel_restrict` — channel properties -* `Matrix.restrict_restrict` — iterated marginalisation = direct marginalisation -* `Matrix.trace_mul_includeAlgebra` — Heisenberg-picture trace identity - -## References - -* Sorce 2024 (`https://arxiv.org/abs/2408.07994`) -* Verch 2025 (`https://arxiv.org/abs/2507.00900`) -* Naaijkens 2012 (`https://repository.ubn.ru.nl/handle/2066/92737`) --/ - -@[expose] public section - -namespace Matrix - -variable {L : SiteIndexSystem} - -/-! ### Linear restriction map -/ - -/-- **Restriction of a matrix to a sub-region** (Schrödinger-picture partial trace). - Sums over indices of the complementary region `Λ_total \ Λ`. -/ -noncomputable def restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - L.localAlgebra Λ_total →ₗ[ℂ] L.localAlgebra Λ where - toFun M := Matrix.of fun a a' => - ∑ b : L.regionIdx (Λ_total \ Λ), - M (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) - map_add' M N := by - ext a a' - simp only [Matrix.of_apply, Matrix.add_apply, Finset.sum_add_distrib] - map_smul' c M := by - ext a a' - simp only [Matrix.of_apply, Matrix.smul_apply, smul_eq_mul, - RingHom.id_apply, Finset.mul_sum] - -@[simp] lemma restrict_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) (a a' : L.regionIdx Λ) : - restrict h M a a' = - ∑ b : L.regionIdx (Λ_total \ Λ), - M (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) := rfl - -/-- **`restrict` is a partial trace over the right tensor factor.** Transporting the matrix -along the factorisation `combineIdx h : regionIdx Λ × regionIdx (Λ_total \ Λ) ≃ regionIdx Λ_total` -turns the region restriction into `Matrix.traceRight`, which traces out the complement factor. -This bridges the region-parameterised partial trace to the positional `traceLeft`/`traceRight` -form. -/ -theorem restrict_eq_traceRight_reindex {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) : - restrict h M = (M.reindex (L.combineIdx h).symm (L.combineIdx h).symm).traceRight := by - ext a a' - simp [restrict_apply, Matrix.traceRight_apply, Matrix.reindex_apply] - -/-! ### Trace preservation -/ - -/-- `Tr(restrict h M) = Tr M`: the restriction preserves the global trace. -/ -theorem trace_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) : - Tr (restrict h M) = Tr M := by - unfold Matrix.trace - simp_rw [Matrix.diag_apply, restrict_apply] - -- LHS: ∑ a, ∑ b, M (combineIdx (a,b)) (combineIdx (a,b)) - -- RHS: ∑ s : regionIdx Λ_total, M s s - -- Step 1: combine the double sum into a sum over the product type - rw [show (∑ a : L.regionIdx Λ, ∑ b : L.regionIdx (Λ_total \ Λ), - M ((L.combineIdx h) (a, b)) ((L.combineIdx h) (a, b))) = - ∑ p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ), - M ((L.combineIdx h) p) ((L.combineIdx h) p) from - (Fintype.sum_prod_type - (fun p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ) => - M ((L.combineIdx h) p) ((L.combineIdx h) p))).symm] - -- Step 2: reindex via combineIdx - exact (L.combineIdx h).sum_comp (fun s => M s s) - -theorem isTracePreserving_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - IsTracePreserving (restrict (L := L) h) := - trace_restrict h - -/-! ### Kraus operators and complete positivity -/ - -/-- Kraus operator for `restrict h`, indexed by `b : regionIdx (Λ_total \ Λ)`: - `K_b a a_total = [a_total = combineIdx h (a, b)]`. -/ -noncomputable def restrictKraus {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (b : L.regionIdx (Λ_total \ Λ)) : - Matrix (L.regionIdx Λ) (L.regionIdx Λ_total) ℂ := - Matrix.of fun a a_total => - if a_total = L.combineIdx h (a, b) then (1 : ℂ) else 0 - -private lemma restrictKraus_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (b : L.regionIdx (Λ_total \ Λ)) (a : L.regionIdx Λ) (a_total : L.regionIdx Λ_total) : - restrictKraus h b a a_total = - if a_total = L.combineIdx h (a, b) then (1 : ℂ) else 0 := rfl - -/-- Entry-wise: `(K_b * M * K_bᴴ) a a' = M (combineIdx (a, b)) (combineIdx (a', b))`. -/ -private lemma restrictKraus_mul_mul_apply {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) (b : L.regionIdx (Λ_total \ Λ)) - (a a' : L.regionIdx Λ) : - ((restrictKraus h b * M : Matrix (L.regionIdx Λ) (L.regionIdx Λ_total) ℂ) * - (restrictKraus h b)ᴴ : L.localAlgebra Λ) a a' = - M (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) := by - rw [Matrix.mul_apply] - simp_rw [Matrix.mul_apply, Matrix.conjTranspose_apply] - -- Outer sum: ∑ p, (K_b * M)(a, p) * star (K_b a' p) - -- = ∑ p, (∑ q, K_b a q * M q p) * star (K_b a' p) - -- K_b a' p = 1 iff p = combineIdx (a', b), so outer sum collapses at p = combineIdx (a', b) - rw [Finset.sum_eq_single (L.combineIdx h (a', b))] - · -- inner sum collapses at q = combineIdx (a, b) - rw [Finset.sum_eq_single (L.combineIdx h (a, b))] - · simp [restrictKraus_apply] - · intro q _ hq - simp only [restrictKraus_apply] - rw [if_neg hq]; ring - · simp - · intro p _ hp - simp only [restrictKraus_apply, apply_ite (star · : ℂ → ℂ), - star_one, star_zero] - rw [if_neg hp] - simp - · simp - -/-- Kraus form of the restriction. -/ -theorem restrict_eq_sum_kraus {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) : - restrict h M = - ∑ b : L.regionIdx (Λ_total \ Λ), - ((restrictKraus h b * M : Matrix (L.regionIdx Λ) (L.regionIdx Λ_total) ℂ) * - (restrictKraus h b)ᴴ : L.localAlgebra Λ) := by - ext a a' - rw [restrict_apply, Matrix.sum_apply] - refine Finset.sum_congr rfl fun b _ => ?_ - exact (restrictKraus_mul_mul_apply h M b a a').symm - -theorem isCompletelyPositive_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - IsCompletelyPositive (restrict (L := L) h) := by - classical - refine ⟨Fintype.card (L.regionIdx (Λ_total \ Λ)), - fun i => restrictKraus h ((Fintype.equivFin (L.regionIdx (Λ_total \ Λ))).symm i), ?_⟩ - intro M - rw [restrict_eq_sum_kraus] - -- Reindex the regionIdx-sum via (equivFin _).symm : Fin r ≃ regionIdx - exact ((Fintype.equivFin (L.regionIdx (Λ_total \ Λ))).symm.sum_comp - (fun b : L.regionIdx (Λ_total \ Λ) => - ((restrictKraus h b * M : Matrix (L.regionIdx Λ) (L.regionIdx Λ_total) ℂ) * - (restrictKraus h b)ᴴ : L.localAlgebra Λ))).symm - -theorem isQuantumChannel_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - IsQuantumChannel (restrict (L := L) h) where - completelyPositive := isCompletelyPositive_restrict h - tracePreserving := isTracePreserving_restrict h - -/-- Restriction as a bundled `QuantumChannel`. -/ -noncomputable def QuantumChannel.restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - Matrix.QuantumChannel (L.regionIdx Λ_total) (L.regionIdx Λ) := - ⟨Matrix.restrict h, isQuantumChannel_restrict h⟩ - -/-! ### Basic algebraic identities for `restrict` -/ - -/-- `restrict h 1 = card • 1`: restricting the identity matrix scales by the cardinality - of the traced-out region. AQFT analogue of `partialTraceRight 1 = card • 1`. -/ -lemma restrict_one {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) : - restrict h (1 : L.localAlgebra Λ_total) = - (Fintype.card (L.regionIdx (Λ_total \ Λ)) : ℂ) • (1 : L.localAlgebra Λ) := by - ext a a' - simp only [restrict_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply] - by_cases hab : a = a' - · subst hab - simp [Finset.card_univ, Finset.sum_const] - · rw [if_neg hab, mul_zero] - refine Finset.sum_eq_zero fun b _ => ?_ - rw [if_neg] - intro hcontra - exact hab ((Prod.mk.injEq _ _ _ _).mp ((L.combineIdx h).injective hcontra) |>.1) - -/-- `restrict h (c • M) = c • restrict h M` (linearity over `ℂ`). -/ -lemma restrict_smul {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) (c : ℂ) - (M : L.localAlgebra Λ_total) : - restrict h (c • M) = c • restrict h M := - (Matrix.restrict h).map_smul c M - -/-- `restrict h` distributes over addition. -/ -private lemma restrict_add {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M N : L.localAlgebra Λ_total) : - restrict h (M + N) = restrict h M + restrict h N := - (Matrix.restrict h).map_add M N - -/-! ### Iterated restriction (transitivity of marginalisation) - -Restricting first to an intermediate region and then to a sub-sub-region equals -restricting directly: `restrict h₂ (restrict h₁ M) = restrict (h₂.trans h₁) M`. -/ - -/-- For `Λ' ⊆ Λ ⊆ Λ_total`, the index combiner factors through the intermediate - region: starting from `(a', γ', β'') ∈ regionIdx Λ' × regionIdx (Λ \ Λ') × - regionIdx (Λ_total \ Λ)`, combining `(a', γ')` to give `regionIdx Λ` and then - pairing with `β''` agrees with combining `(a', γ' & β'')` directly to give - `regionIdx Λ_total`. This is the key identity behind `restrict_restrict`. -/ -lemma combineIdx_assoc_aux - {Λ' Λ Λ_total : Finset L.sites} (h₁ : Λ ⊆ Λ_total) (h₂ : Λ' ⊆ Λ) - (a' : L.regionIdx Λ') (γ : L.regionIdx (Λ \ Λ')) - (β : L.regionIdx (Λ_total \ Λ)) - (s : ↥Λ_total) : - L.combineIdx h₁ (L.combineIdx h₂ (a', γ), β) s = - if hsΛ : s.val ∈ Λ then - if hsΛ' : s.val ∈ Λ' then a' ⟨s.val, hsΛ'⟩ - else γ ⟨s.val, Finset.mem_sdiff.mpr ⟨hsΛ, hsΛ'⟩⟩ - else β ⟨s.val, Finset.mem_sdiff.mpr ⟨s.property, hsΛ⟩⟩ := by - by_cases hsΛ : s.val ∈ Λ - · rw [SiteIndexSystem.combineIdx_apply_mem h₁ _ _ s hsΛ, dif_pos hsΛ] - by_cases hsΛ' : s.val ∈ Λ' - · rw [SiteIndexSystem.combineIdx_apply_mem h₂ _ _ ⟨s.val, hsΛ⟩ hsΛ', dif_pos hsΛ'] - · rw [SiteIndexSystem.combineIdx_apply_not_mem h₂ _ _ ⟨s.val, hsΛ⟩ hsΛ', dif_neg hsΛ'] - · rw [SiteIndexSystem.combineIdx_apply_not_mem h₁ _ _ s hsΛ, dif_neg hsΛ] - -/-- Splitting a `regionIdx (Λ_total \ Λ')` into its `(Λ \ Λ')` and `(Λ_total \ Λ)` parts. - Used by `restrict_restrict` to convert iterated marginalisation into a single one, - and by callers (e.g. SSA) that need to commute `combineIdx h₁ ∘ combineIdx h₂` with - `combineIdx (h₂.trans h₁)` (see `combineIdx_assoc_eq`). -/ -def restrictAssocEquiv {Λ' Λ Λ_total : Finset L.sites} - (h₁ : Λ ⊆ Λ_total) (h₂ : Λ' ⊆ Λ) : - L.regionIdx (Λ \ Λ') × L.regionIdx (Λ_total \ Λ) ≃ L.regionIdx (Λ_total \ Λ') where - toFun gb := fun ⟨s, hs⟩ => - if hsΛ : s ∈ Λ then - gb.1 ⟨s, Finset.mem_sdiff.mpr ⟨hsΛ, (Finset.mem_sdiff.mp hs).2⟩⟩ - else - gb.2 ⟨s, Finset.mem_sdiff.mpr ⟨(Finset.mem_sdiff.mp hs).1, hsΛ⟩⟩ - invFun δ := - (fun ⟨s, hs⟩ => δ ⟨s, Finset.mem_sdiff.mpr - ⟨h₁ (Finset.mem_sdiff.mp hs).1, (Finset.mem_sdiff.mp hs).2⟩⟩, - fun ⟨s, hs⟩ => δ ⟨s, Finset.mem_sdiff.mpr - ⟨(Finset.mem_sdiff.mp hs).1, fun h_in_Λ' => - (Finset.mem_sdiff.mp hs).2 (h₂ h_in_Λ')⟩⟩) - left_inv := by - rintro ⟨γ, β⟩ - ext1 - · funext ⟨s, hs⟩ - have h_in_Λ : s ∈ Λ := (Finset.mem_sdiff.mp hs).1 - simp [h_in_Λ] - · funext ⟨s, hs⟩ - have h_not_Λ : s ∉ Λ := (Finset.mem_sdiff.mp hs).2 - simp [h_not_Λ] - right_inv := by - intro δ - funext ⟨s, hs⟩ - by_cases h_in_Λ : s ∈ Λ <;> simp [h_in_Λ] - -/-- **`combineIdx` associativity**: For nested subsets `Λ' ⊆ Λ ⊆ Λ_total`, combining - `(combineIdx h₂ (a', γ), β)` via the outer subset agrees with combining - `(a', restrictAssocEquiv (γ, β))` via the composed subset `h₂.trans h₁`. - AQFT analogue of the tensor-product associativity - `(ℋ_Λ' ⊗ ℋ_{Λ\Λ'}) ⊗ ℋ_{Λ_total\Λ} ≃ ℋ_Λ' ⊗ (ℋ_{Λ\Λ'} ⊗ ℋ_{Λ_total\Λ})`. -/ -lemma combineIdx_assoc_eq {Λ' Λ Λ_total : Finset L.sites} - (h₁ : Λ ⊆ Λ_total) (h₂ : Λ' ⊆ Λ) (a' : L.regionIdx Λ') - (γ : L.regionIdx (Λ \ Λ')) (β : L.regionIdx (Λ_total \ Λ)) : - L.combineIdx h₁ (L.combineIdx h₂ (a', γ), β) = - L.combineIdx (h₂.trans h₁) (a', restrictAssocEquiv h₁ h₂ (γ, β)) := by - funext s - rw [combineIdx_assoc_aux h₁ h₂] - by_cases hsΛ' : s.val ∈ Λ' - · have hsΛ : s.val ∈ Λ := h₂ hsΛ' - rw [SiteIndexSystem.combineIdx_apply_mem (h₂.trans h₁) _ _ s hsΛ', - dif_pos hsΛ, dif_pos hsΛ'] - · rw [SiteIndexSystem.combineIdx_apply_not_mem (h₂.trans h₁) _ _ s hsΛ'] - by_cases hsΛ : s.val ∈ Λ - · rw [dif_pos hsΛ, dif_neg hsΛ'] - simp [restrictAssocEquiv, hsΛ] - · rw [dif_neg hsΛ] - simp [restrictAssocEquiv, hsΛ] - -/-- **Iterated restriction equals direct restriction**: - `restrict h₂ (restrict h₁ M) = restrict (h₂.trans h₁) M`. - - Marginalising first to `Λ` then to `Λ' ⊆ Λ` agrees with marginalising directly to `Λ'`. - AQFT statement of the partial-trace transitivity property. -/ -theorem restrict_restrict {Λ' Λ Λ_total : Finset L.sites} - (h₁ : Λ ⊆ Λ_total) (h₂ : Λ' ⊆ Λ) (M : L.localAlgebra Λ_total) : - restrict h₂ (restrict h₁ M) = restrict (h₂.trans h₁) M := by - ext a' a'' - rw [restrict_apply] - -- Reindex RHS sum via restrictAssocEquiv to a sum over the product type. - rw [show restrict (h₂.trans h₁) M a' a'' = - ∑ p : L.regionIdx (Λ \ Λ') × L.regionIdx (Λ_total \ Λ), - M (L.combineIdx (h₂.trans h₁) (a', restrictAssocEquiv h₁ h₂ p)) - (L.combineIdx (h₂.trans h₁) (a'', restrictAssocEquiv h₁ h₂ p)) from by - rw [restrict_apply] - exact ((restrictAssocEquiv h₁ h₂).sum_comp _).symm] - -- Convert the product sum to nested sums. - rw [Fintype.sum_prod_type] - -- Pointwise: rewrite the inner sums via combineIdx_assoc_eq. - refine Finset.sum_congr rfl fun γ _ => ?_ - refine Finset.sum_congr rfl fun β _ => ?_ - congr 1 - · exact combineIdx_assoc_eq h₁ h₂ a' γ β - · exact combineIdx_assoc_eq h₁ h₂ a'' γ β - -/-! ### Heisenberg-picture duality - -The matrix-level dual of the restriction: tracing `ρ` against an embedded observable -`includeAlgebra h X` equals tracing the marginal `restrict h ρ` against `X`. -/ - -/-- **Heisenberg-picture trace identity**: -`Tr(ρ · includeAlgebra h X) = Tr((restrict h ρ) · X)`. -This is the AQFT-natural form of `trace_mul_kronecker_one`. -/ -theorem trace_mul_includeAlgebra {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.localAlgebra Λ_total) (X : L.localAlgebra Λ) : - Tr (ρ * L.includeAlgebra h X) = Tr ((restrict h ρ) * X) := by - -- RHS expansion: ∑ a, ∑ a', ∑ b, ρ(combine (a,b), combine (a',b)) · X a' a - have rhs_expand : - Tr ((restrict h ρ) * X) = - ∑ a : L.regionIdx Λ, ∑ a' : L.regionIdx Λ, ∑ b : L.regionIdx (Λ_total \ Λ), - ρ (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) * X a' a := by - unfold Matrix.trace - simp_rw [Matrix.diag_apply, Matrix.mul_apply, restrict_apply, Finset.sum_mul] - -- LHS: reindex outer sum via combineIdx, expand mul - have lhs_expand : - Tr (ρ * L.includeAlgebra h X) = - ∑ a : L.regionIdx Λ, ∑ b : L.regionIdx (Λ_total \ Λ), - ∑ a' : L.regionIdx Λ, - ρ (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) * X a' a := by - unfold Matrix.trace - -- Reindex Tr over Λ_total via combineIdx⁻¹: ∑ s, M s s = ∑ (a,b), M (combine (a,b)) (combine (a,b)) - rw [show (∑ s : L.regionIdx Λ_total, (ρ * L.includeAlgebra h X).diag s) = - ∑ p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ), - (ρ * L.includeAlgebra h X).diag (L.combineIdx h p) from - ((L.combineIdx h).sum_comp _).symm] - rw [Fintype.sum_prod_type] - -- Goal: ∑ a, ∑ b, (ρ * includeAlgebra h X).diag (combineIdx (a, b)) = ... - refine Finset.sum_congr rfl fun a _ => Finset.sum_congr rfl fun b _ => ?_ - -- Expand mul, then reindex inner sum (over s' : regionIdx Λ_total) via combineIdx - rw [Matrix.diag_apply, Matrix.mul_apply, - show (∑ s' : L.regionIdx Λ_total, - ρ (L.combineIdx h (a, b)) s' * - L.includeAlgebra h X s' (L.combineIdx h (a, b))) = - ∑ p : L.regionIdx Λ × L.regionIdx (Λ_total \ Λ), - ρ (L.combineIdx h (a, b)) (L.combineIdx h p) * - L.includeAlgebra h X (L.combineIdx h p) (L.combineIdx h (a, b)) from - ((L.combineIdx h).sum_comp _).symm] - rw [Fintype.sum_prod_type] - -- Now: ∑ a', ∑ b', ρ ... * (includeAlgebra h X) (combineIdx (a', b')) (combineIdx (a, b)) - -- After applying `includeAlgebra_apply_combineIdx`, the b'-sum collapses on b' = b. - refine Finset.sum_congr rfl fun a' _ => ?_ - rw [show (∑ b' : L.regionIdx (Λ_total \ Λ), - ρ (L.combineIdx h (a, b)) (L.combineIdx h (a', b')) * - L.includeAlgebra h X (L.combineIdx h (a', b')) (L.combineIdx h (a, b))) = - ρ (L.combineIdx h (a, b)) (L.combineIdx h (a', b)) * X a' a from by - rw [Finset.sum_eq_single b] - · rw [SiteIndexSystem.includeAlgebra_apply_combineIdx]; simp - · intro b' _ hb' - rw [SiteIndexSystem.includeAlgebra_apply_combineIdx, if_neg hb'] - ring - · simp] - -- Combine: LHS = ∑ a, ∑ b, ∑ a', ... = ∑ a, ∑ a', ∑ b, ... = RHS - rw [lhs_expand, rhs_expand] - refine Finset.sum_congr rfl fun a _ => ?_ - rw [Finset.sum_comm] - -end Matrix - -namespace DensityMatrix - -variable {L : SiteIndexSystem} - -/-- Restriction of a density matrix to a sub-region (= partial trace over the complement). -/ -noncomputable def restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.densityMatrix Λ_total) : L.densityMatrix Λ := - (Matrix.QuantumChannel.restrict h : Matrix.QuantumChannel _ _) ρ - -@[simp] lemma restrict_toMatrix {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (ρ : L.densityMatrix Λ_total) : - (restrict h ρ).toMatrix = Matrix.restrict h ρ.toMatrix := rfl - -/-- **Iterated restriction equals direct restriction** (density-matrix form). - Marginalising first to `Λ` then to `Λ' ⊆ Λ` agrees with marginalising directly to `Λ'`. -/ -theorem restrict_restrict {Λ' Λ Λ_total : Finset L.sites} - (h₁ : Λ ⊆ Λ_total) (h₂ : Λ' ⊆ Λ) (ρ : L.densityMatrix Λ_total) : - restrict h₂ (restrict h₁ ρ) = restrict (h₂.trans h₁) ρ := by - apply DensityMatrix.ext - rw [restrict_toMatrix, restrict_toMatrix, restrict_toMatrix, - Matrix.restrict_restrict] - -end DensityMatrix - -/-! ## Paper notation: `ρ ↾ Λ` - -`ρ ↾ Λ` is the **restriction of a density matrix to a sub-region** — equivalently, the -partial trace over the complementary region. This is the AQFT-natural -form of partial trace: parameterised by the region `Λ` rather than by left/right position. - -The subset proof is auto-resolved by trying, in order: `Finset.subset_univ _` -(marginalising from the full system), `Finset.Subset.refl _` (identity), then `decide` -(explicit closed finsets). For complex hypotheses, write `DensityMatrix.restrict h ρ` directly. - -For raw `Matrix`-level work, use `Matrix.restrict h M` (no notation provided to keep `↾` -unambiguous on the density-matrix surface). -/ - -namespace SiteIndexSystem -namespace QuantumInfo - -scoped syntax:65 term:65 " ↾ " term:66 : term -scoped syntax:65 term:65 " ↾[" term "]" : term - -scoped macro_rules - | `($ρ ↾ $Λ) => - `(DensityMatrix.restrict (Λ := $Λ) - (by first | exact Finset.subset_univ _ | exact Finset.Subset.refl _ - | decide - | assumption) $ρ) - | `($ρ ↾[$h]) => `(DensityMatrix.restrict $h $ρ) - -end QuantumInfo -end SiteIndexSystem diff --git a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean b/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean deleted file mode 100644 index b457b8f..0000000 --- a/QuantumSystem/Analysis/Matrix/PartialTraceOperator.lean +++ /dev/null @@ -1,92 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.MatrixModel.TensorDecomposition -public import QuantumSystem.Analysis.Matrix.PartialTrace -public import Mathlib.Analysis.InnerProductSpace.Trace - -/-! -# The partial trace is the operator form of `restrict` - -Completing the operator-level tensor decomposition (`SiteIndexSystem.tensorEquiv`, -`SiteIndexSystem.opEquiv_includeAlgebra`), this file shows that the marginal `Matrix.restrict` is, under -the operator identifications, exactly the **partial trace** over the complementary Hilbert-space -factor: tracing out `ℋ (Λ_total \ Λ)`. - -`opEquiv_restrict`: `opEquiv Λ (restrict h M) = LinearMap.partialTrace (regionBipartition h) -(opEquiv Λ_total M)`, with the traced-out subspace `ℋ (Λ_total \ Λ)` named explicitly by -`regionBipartition h` (defined in `TensorDecomposition`). - -Together with `opEquiv_includeAlgebra` (isotony as the ampliation `LinearMap.ampliate`), this is the -Schrödinger/Heisenberg pair witnessing that `combineIdx` is a genuine tensor factorisation of -operators on Hilbert spaces. --/ - -@[expose] public section - -open WithLp -open scoped TensorProduct Matrix - -namespace SiteIndexSystem - -variable (L : SiteIndexSystem) - -/-- Matrix entries of `(opEquiv Λ).symm T`: the `(i, j)` entry is the `i`-coordinate of the image -of the `j`-th standard basis vector under the operator `T`. (Internal helper.) -/ -private lemma opEquiv_symm_apply_apply (Λ : Finset L.sites) (T : Module.End ℂ (L.ℋ Λ)) - (i j : L.regionIdx Λ) : - (L.opEquiv Λ).symm T i j = ofLp (T (EuclideanSpace.single j (1 : ℂ))) i := by - have hh := L.ofLp_opEquiv Λ ((L.opEquiv Λ).symm T) (EuclideanSpace.single j (1 : ℂ)) - rw [AlgEquiv.apply_symm_apply, PiLp.ofLp_single] at hh - simpa [Matrix.mulVec_single_one, Matrix.col_apply] using (congrFun hh i).symm - -/-- Internal: `restrict` as the `End A ⊗ End B`-level partial trace against the operator tensor -decomposition `tensorEquiv`. The public, explicit-subspace form is `opEquiv_restrict` below. -/ -private theorem opEquiv_restrict_aux {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) : - L.opEquiv Λ (Matrix.restrict h M) - = TensorProduct.partialTraceRight ((L.tensorEquiv h).symm (L.opEquiv Λ_total M)) := by - suffices H : ∀ T : Module.End ℂ (L.ℋ Λ) ⊗[ℂ] Module.End ℂ (L.ℋ (Λ_total \ Λ)), - L.opEquiv Λ (Matrix.restrict h ((L.opEquiv Λ_total).symm (L.tensorEquiv h T))) - = TensorProduct.partialTraceRight T by - have key := H ((L.tensorEquiv h).symm (L.opEquiv Λ_total M)) - rwa [AlgEquiv.apply_symm_apply, AlgEquiv.symm_apply_apply] at key - intro T - induction T using TensorProduct.induction_on with - | zero => simp - | add T₁ T₂ hT₁ hT₂ => - have hadd : ∀ A B : L.localAlgebra Λ_total, - Matrix.restrict h (A + B) = Matrix.restrict h A + Matrix.restrict h B := by - intro A B; ext a a'; simp [Matrix.restrict_apply, Finset.sum_add_distrib] - simp only [map_add, hadd, hT₁, hT₂] - | tmul Y Z => - rw [TensorProduct.partialTraceRight_tmul] - have htrace : LinearMap.trace ℂ (L.ℋ (Λ_total \ Λ)) Z - = ∑ b : L.regionIdx (Λ_total \ Λ), ofLp (Z (EuclideanSpace.single b (1 : ℂ))) b := by - rw [LinearMap.trace_eq_sum_inner Z (EuclideanSpace.basisFun (L.regionIdx (Λ_total \ Λ)) ℂ)] - refine Finset.sum_congr rfl fun b _ => ?_ - rw [EuclideanSpace.basisFun_apply, EuclideanSpace.inner_single_left, map_one, one_mul] - refine (EuclideanSpace.basisFun (L.regionIdx Λ) ℂ).toBasis.ext fun a' => ?_ - rw [OrthonormalBasis.coe_toBasis, EuclideanSpace.basisFun_apply] - apply WithLp.ofLp_injective (p := 2) - funext a - rw [ofLp_opEquiv, PiLp.ofLp_single, Matrix.mulVec_single_one, Matrix.col_apply, - Matrix.restrict_apply] - simp only [L.opEquiv_symm_apply_apply, tensorEquiv_tmul_apply, - L.combineIdx_tensorEquiv_symm_single, TensorProduct.map_tmul, - EuclideanSpace.ofLp_tensorEquiv_tmul, Equiv.symm_apply_apply, LinearMap.smul_apply] - rw [← Finset.mul_sum, ← htrace] - simp [mul_comm] - -/-- **`restrict` is the partial trace** that explicitly traces out `ℋ (Λ_total \ Λ)`, via the named -bipartition `regionBipartition h`. The operator analogue of `Matrix.partialTrace (e : X ≃ A × B)` -applied to the AQFT marginal: combined with `opEquiv_includeAlgebra` (isotony as the ampliation) -and `LinearMap.partialTrace_ampliate_mul`, it gives the `𝔄(Λ)`-module ("pull-out") law of the -conditional expectation `𝔄(Λ_total) → 𝔄(Λ)`. -/ -theorem opEquiv_restrict {Λ Λ_total : Finset L.sites} (h : Λ ⊆ Λ_total) - (M : L.localAlgebra Λ_total) : - L.opEquiv Λ (Matrix.restrict h M) - = LinearMap.partialTrace (L.regionBipartition h) (L.opEquiv Λ_total M) := by - rw [L.opEquiv_restrict_aux, LinearMap.partialTrace_apply] - congr 1 - -end SiteIndexSystem diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean index 33f27c1..ae3588f 100644 --- a/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean @@ -1,9 +1,12 @@ module +public import Mathlib.Algebra.Algebra.Subalgebra.Centralizer +public import Mathlib.Algebra.Central.End +public import Mathlib.Data.Complex.Basic public import Mathlib.LinearAlgebra.Trace /-! -# Tensor product of endomorphism algebras and the partial trace +# Tensor product of endomorphism algebras, partial trace, and the commutant For finite-dimensional free modules `M`, `N` over a commutative ring `R`, the canonical algebra homomorphism `Module.endTensorEndAlgHom : End R M ⊗ End R N →ₐ End R (M ⊗ N)` is an isomorphism. @@ -11,8 +14,25 @@ This file packages it as an `AlgEquiv` and uses it to define the **partial trace factor `partialTraceRight : End R (M ⊗ N) →ₗ End R M`, characterised on operator tensors by `Y ⊗ Z ↦ (trace Z) • Y`. +It also records the **commutant of `End A ⊗ 1`**: for finite-dimensional `ℂ`-spaces `A`, `B`, an +operator on `A ⊗ B` commuting with every ampliation `f ⊗ 1` is itself an ampliation `1 ⊗ g` of the +second factor (equivalently, the commutant of `B(A) ⊗ 1` is `1 ⊗ B(B)`). This is the +operator-algebraic uniqueness underlying the fact that a partial trace depends only on the subsystem +traced out, not on the chosen factorisation of its complement; it is assembled from Mathlib's +`Subalgebra.centralizer_coe_range_includeLeft_eq_center_tensorProduct` together with the centrality +of `End ℂ A` (`Algebra.IsCentral`), so that `Z(End ℂ A) = ℂ·1`. + These are the abstract, basis-free ingredients of the tensor factorisation of operator algebras on (finite-dimensional) Hilbert spaces. + +## Main statements + +* `TensorProduct.endTensorEndAlgEquiv` — the algebra isomorphism `End R M ⊗ End R N ≃ End R (M ⊗ N)`. +* `LinearMap.partialTrace` — the partial trace along an explicit decomposition `e : ℋ ≃ A ⊗ B`. +* `Algebra.TensorProduct.exists_includeRight_of_commute_includeLeft` — algebra form of the commutant: + in `End A ⊗ End B`, an element commuting with all `includeLeft f` is `includeRight g`. +* `LinearMap.exists_map_one_of_commute_map_id` — operator form: `T : End (A ⊗ B)` commuting with + all `f ⊗ 1` equals `1 ⊗ g`. -/ @[expose] public section @@ -112,6 +132,11 @@ theorem partialTrace_apply (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (ρ : Module.End noncomputable def ampliate (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Module.End 𝕜 A) : Module.End 𝕜 ℋ := (e.conjAlgEquiv 𝕜).symm (TensorProduct.map M 1) +/-- **Co-ampliation along `e`**: lift an operator `M` on the *complementary* factor `B` to `ℋ`, +acting as the identity on `A` and as `M` on `B` (i.e. `1 ⊗ M` transported by `e`). -/ +noncomputable def coampliate (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Module.End 𝕜 B) : Module.End 𝕜 ℋ := + (e.conjAlgEquiv 𝕜).symm (TensorProduct.map 1 M) + private theorem endTensorEndAlgEquiv_symm_map_one (M : Module.End 𝕜 A) : (TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm (TensorProduct.map M 1) = M ⊗ₜ[𝕜] 1 := by @@ -129,3 +154,167 @@ theorem partialTrace_ampliate_mul (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Modu endTensorEndAlgEquiv_symm_map_one, TensorProduct.partialTraceRight_includeLeft_mul] end LinearMap + +/-! ### The commutant of `End A ⊗ 1` in `End (A ⊗ B)` -/ + +namespace Algebra.TensorProduct + +variable {A B : Type*} [AddCommGroup A] [Module ℂ A] [Module.Finite ℂ A] [Module.Free ℂ A] + [AddCommGroup B] [Module ℂ B] [Module.Finite ℂ B] [Module.Free ℂ B] + +omit [Module.Finite ℂ A] [Module.Finite ℂ B] [Module.Free ℂ B] in +/-- **Commutant of `End A ⊗ 1`, algebra form.** An element of `End ℂ A ⊗ End ℂ B` that commutes +with every `includeLeft f = f ⊗ 1` is of the form `includeRight g = 1 ⊗ g`. -/ +theorem exists_includeRight_of_commute_includeLeft + (S : Module.End ℂ A ⊗[ℂ] Module.End ℂ B) + (hS : ∀ f : Module.End ℂ A, + (Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) f) * S + = S * Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) f) : + ∃ g, S = Algebra.TensorProduct.includeRight g := by + -- Every element of `(⊥ : Subalgebra) ⊗ End B` is `1 ⊗ g`. + have hext : ∀ x : (⊥ : Subalgebra ℂ (Module.End ℂ A)) ⊗[ℂ] Module.End ℂ B, + ∃ g, Algebra.TensorProduct.map (⊥ : Subalgebra ℂ (Module.End ℂ A)).val + (AlgHom.id ℂ (Module.End ℂ B)) x = Algebra.TensorProduct.includeRight g := by + intro x + induction x with + | zero => exact ⟨0, by simp⟩ + | tmul a' g => + obtain ⟨c, hc⟩ := Algebra.mem_bot.mp a'.2 + refine ⟨c • g, ?_⟩ + simp only [Algebra.TensorProduct.map_tmul, AlgHom.id_apply, + Algebra.TensorProduct.includeRight_apply] + rw [show (Subalgebra.val ⊥) a' = algebraMap ℂ (Module.End ℂ A) c from hc.symm, + Algebra.algebraMap_eq_smul_one, TensorProduct.smul_tmul] + | add x y hx hy => + obtain ⟨g₁, h₁⟩ := hx; obtain ⟨g₂, h₂⟩ := hy + exact ⟨g₁ + g₂, by rw [map_add, h₁, h₂, ← map_add]⟩ + -- `S` lies in the centralizer of `range includeLeft`, which (by centrality of `End A`) is + -- `range includeRight`. + have hmem : S ∈ Subalgebra.centralizer ℂ + (↑(Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B)).range : Set _) := by + rw [Subalgebra.mem_centralizer_iff] + rintro s ⟨f, rfl⟩ + exact hS f + rw [Subalgebra.centralizer_coe_range_includeLeft_eq_center_tensorProduct, + Algebra.IsCentral.center_eq_bot, AlgHom.mem_range] at hmem + obtain ⟨x, hx⟩ := hmem + obtain ⟨g, hg⟩ := hext x + exact ⟨g, by rw [← hx, hg]⟩ + +omit [Module.Finite ℂ A] [Module.Free ℂ A] [Module.Finite ℂ B] [Module.Free ℂ B] in +/-- **Commutant of `1 ⊗ End B`, algebra form.** An element of `End ℂ A ⊗ End ℂ B` that commutes +with every `includeRight g = 1 ⊗ g` is of the form `includeLeft f = f ⊗ 1`. -/ +theorem exists_includeLeft_of_commute_includeRight + (S : Module.End ℂ A ⊗[ℂ] Module.End ℂ B) + (hS : ∀ g : Module.End ℂ B, + (Algebra.TensorProduct.includeRight (R := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) g) * S + = S * Algebra.TensorProduct.includeRight (R := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) g) : + ∃ f, S = Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) f := by + have hext : ∀ x : Module.End ℂ A ⊗[ℂ] (⊥ : Subalgebra ℂ (Module.End ℂ B)), + ∃ f, Algebra.TensorProduct.map (AlgHom.id ℂ (Module.End ℂ A)) + (⊥ : Subalgebra ℂ (Module.End ℂ B)).val x + = Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) f := by + intro x + induction x with + | zero => exact ⟨0, by simp⟩ + | tmul a b' => + obtain ⟨c, hc⟩ := Algebra.mem_bot.mp b'.2 + refine ⟨c • a, ?_⟩ + simp only [Algebra.TensorProduct.map_tmul, AlgHom.id_apply, + Algebra.TensorProduct.includeLeft_apply] + rw [show (Subalgebra.val ⊥) b' = algebraMap ℂ (Module.End ℂ B) c from hc.symm, + Algebra.algebraMap_eq_smul_one, TensorProduct.tmul_smul, TensorProduct.smul_tmul'] + | add x y hx hy => + obtain ⟨f₁, h₁⟩ := hx; obtain ⟨f₂, h₂⟩ := hy + exact ⟨f₁ + f₂, by rw [map_add, h₁, h₂, ← map_add]⟩ + have hmem : S ∈ Subalgebra.centralizer ℂ + (↑(Algebra.TensorProduct.includeRight (R := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B)).range : Set _) := by + rw [Subalgebra.mem_centralizer_iff] + rintro s ⟨g, rfl⟩ + exact hS g + rw [Subalgebra.centralizer_range_includeRight_eq_center_tensorProduct, + Algebra.IsCentral.center_eq_bot, AlgHom.mem_range] at hmem + obtain ⟨x, hx⟩ := hmem + obtain ⟨f, hf⟩ := hext x + exact ⟨f, by rw [← hx, hf]⟩ + +end Algebra.TensorProduct + +namespace LinearMap + +variable {A B : Type*} [AddCommGroup A] [Module ℂ A] [Module.Finite ℂ A] [Module.Free ℂ A] + [AddCommGroup B] [Module ℂ B] [Module.Finite ℂ B] [Module.Free ℂ B] + +/-- **Commutant of `End A ⊗ 1`, operator form.** An operator `T : End (A ⊗ B)` commuting with every +ampliation `f ⊗ 1 = TensorProduct.map f 1` is an ampliation `1 ⊗ g = TensorProduct.map 1 g` of the +second factor. -/ +theorem exists_map_one_of_commute_map_id + (T : Module.End ℂ (A ⊗[ℂ] B)) + (hT : ∀ f : Module.End ℂ A, + T ∘ₗ TensorProduct.map f LinearMap.id = TensorProduct.map f LinearMap.id ∘ₗ T) : + ∃ g : Module.End ℂ B, T = TensorProduct.map LinearMap.id g := by + have hcomm : ∀ f : Module.End ℂ A, + Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) f * TensorProduct.endTensorEndAlgEquiv.symm T + = TensorProduct.endTensorEndAlgEquiv.symm T + * Algebra.TensorProduct.includeLeft (R := ℂ) (S := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) f := by + intro f + have key : TensorProduct.endTensorEndAlgEquiv (Algebra.TensorProduct.includeLeft + (R := ℂ) (S := ℂ) (A := Module.End ℂ A) (B := Module.End ℂ B) f) + = TensorProduct.map f (LinearMap.id : Module.End ℂ B) := by + rw [Algebra.TensorProduct.includeLeft_apply, TensorProduct.endTensorEndAlgEquiv_tmul, + Module.End.one_eq_id] + apply TensorProduct.endTensorEndAlgEquiv.injective + rw [map_mul, map_mul, AlgEquiv.apply_symm_apply, key] + exact (hT f).symm + obtain ⟨g, hg⟩ := + Algebra.TensorProduct.exists_includeRight_of_commute_includeLeft + (TensorProduct.endTensorEndAlgEquiv.symm T) hcomm + refine ⟨g, ?_⟩ + have heq := congrArg TensorProduct.endTensorEndAlgEquiv hg + rw [AlgEquiv.apply_symm_apply, Algebra.TensorProduct.includeRight_apply, + TensorProduct.endTensorEndAlgEquiv_tmul] at heq + exact heq + +/-- **Commutant of `1 ⊗ End B`, operator form.** An operator `T : End (A ⊗ B)` commuting with every +`1 ⊗ g = TensorProduct.map 1 g` is an ampliation `f ⊗ 1 = TensorProduct.map f 1` of the first +factor. -/ +theorem exists_map_id_of_commute_map_one + (T : Module.End ℂ (A ⊗[ℂ] B)) + (hT : ∀ g : Module.End ℂ B, + T ∘ₗ TensorProduct.map LinearMap.id g = TensorProduct.map LinearMap.id g ∘ₗ T) : + ∃ f : Module.End ℂ A, T = TensorProduct.map f LinearMap.id := by + have hcomm : ∀ g : Module.End ℂ B, + Algebra.TensorProduct.includeRight (R := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) g * TensorProduct.endTensorEndAlgEquiv.symm T + = TensorProduct.endTensorEndAlgEquiv.symm T + * Algebra.TensorProduct.includeRight (R := ℂ) (A := Module.End ℂ A) + (B := Module.End ℂ B) g := by + intro g + have key : TensorProduct.endTensorEndAlgEquiv (Algebra.TensorProduct.includeRight + (R := ℂ) (A := Module.End ℂ A) (B := Module.End ℂ B) g) + = TensorProduct.map (LinearMap.id : Module.End ℂ A) g := by + rw [Algebra.TensorProduct.includeRight_apply, TensorProduct.endTensorEndAlgEquiv_tmul, + Module.End.one_eq_id] + apply TensorProduct.endTensorEndAlgEquiv.injective + rw [map_mul, map_mul, AlgEquiv.apply_symm_apply, key] + exact (hT g).symm + obtain ⟨f, hf⟩ := + Algebra.TensorProduct.exists_includeLeft_of_commute_includeRight + (TensorProduct.endTensorEndAlgEquiv.symm T) hcomm + refine ⟨f, ?_⟩ + have heq := congrArg TensorProduct.endTensorEndAlgEquiv hf + rw [AlgEquiv.apply_symm_apply, Algebra.TensorProduct.includeLeft_apply, + TensorProduct.endTensorEndAlgEquiv_tmul, Module.End.one_eq_id] at heq + exact heq + +end LinearMap diff --git a/QuantumSystem/Notation.lean b/QuantumSystem/Notation.lean index 852d7a8..f56a49e 100644 --- a/QuantumSystem/Notation.lean +++ b/QuantumSystem/Notation.lean @@ -17,12 +17,6 @@ Notations and abbreviations for quantum information theory. | `S(ρ)` | `Matrix.vonNeumannEntropy ρ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/VonNeumannEntropy.lean` | | `D(ρ ∥ σ)` | `Matrix.relativeEntropy ρ σ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/RelativeEntropy.lean` | | `⟪X, Y⟫_HS` | `Matrix.hsInnerProduct X Y` | `open scoped Matrix.QuantumInfo` | `Analysis/Matrix/LiebConcavity.lean` | -| `ρ ↾ Λ` | `DensityMatrix.restrict (by …) ρ` | `open scoped SiteIndexSystem.QuantumInfo` | `Analysis/Matrix/PartialTrace.lean` | - -`ρ ↾ Λ` is the AQFT-style **restriction of a density matrix to a sub-region** — -equivalently, the partial trace over the complementary region. -The subset proof `Λ ⊆ Λ_total` is auto-resolved by `Finset.subset_univ _`, `Finset.Subset.refl _`, or `decide`. -For complex hypotheses, write `DensityMatrix.restrict h ρ` directly. ## `Tr` syntax From 6fde6d2faf81346809c7d8c6070de62413c1dfd6 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 17:51:14 +0000 Subject: [PATCH 028/113] chore: remove incomplete modules --- QuantumSystem.lean | 6 - .../Algebra/LocalNet/TensorDecomposition.lean | 142 ---- .../Analysis/Entropy/SplitEntropy.lean | 45 -- .../Entropy/SplitRelativeEntropy.lean | 101 --- QuantumSystem/Analysis/Entropy/SplitSSA.lean | 713 ------------------ .../Analysis/Entropy/SplitTrace.lean | 124 --- .../Analysis/Entropy/SplitTransport.lean | 374 --------- 7 files changed, 1505 deletions(-) delete mode 100644 QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean delete mode 100644 QuantumSystem/Analysis/Entropy/SplitEntropy.lean delete mode 100644 QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean delete mode 100644 QuantumSystem/Analysis/Entropy/SplitSSA.lean delete mode 100644 QuantumSystem/Analysis/Entropy/SplitTrace.lean delete mode 100644 QuantumSystem/Analysis/Entropy/SplitTransport.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 231c7df..49dd05b 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -20,7 +20,6 @@ public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful public import QuantumSystem.Algebra.LocalNet.Covariance public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra -public import QuantumSystem.Algebra.LocalNet.TensorDecomposition public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal @@ -28,11 +27,6 @@ public import QuantumSystem.Analysis.Channel.PartialTrace public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.MutualInfoProduct public import QuantumSystem.Analysis.Entropy.RelativeEntropy -public import QuantumSystem.Analysis.Entropy.SplitEntropy -public import QuantumSystem.Analysis.Entropy.SplitRelativeEntropy -public import QuantumSystem.Analysis.Entropy.SplitSSA -public import QuantumSystem.Analysis.Entropy.SplitTrace -public import QuantumSystem.Analysis.Entropy.SplitTransport public import QuantumSystem.Analysis.Entropy.StrongSubadditivityProduct public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy public import QuantumSystem.Analysis.Matrix.Effros diff --git a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean b/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean deleted file mode 100644 index 8e30f3e..0000000 --- a/QuantumSystem/Algebra/LocalNet/TensorDecomposition.lean +++ /dev/null @@ -1,142 +0,0 @@ -module - -public import QuantumSystem.Algebra.LocalNet.Net -public import QuantumSystem.ForMathlib.LinearAlgebra.Trace -public import Mathlib.Analysis.InnerProductSpace.Adjoint -public import Mathlib.Analysis.InnerProductSpace.TensorProduct - -/-! -# The split property and the tensor decomposition of a local net - -This file implements the **split property** for an abstract local net `LocalNet` and derives, -*without committing to any particular representation*, the **tensor factorisation of the action -space** and the **partial trace** that it induces. - -In the operator-algebraic literature the split property of an inclusion `𝔄(Λ) ⊆ 𝔄(Λ')` is the -existence of an intermediate type I factor `𝔄(Λ) ⊆ N ⊆ 𝔄(Λ')`; in its spatial / standard form -(Doplicher–Longo standard split inclusion, Fewster 2016 eqns (12)–(13), Matsui 2011 eqns -(2.1)–(2.2)) this is equivalent to a factorisation of the Hilbert space the algebra acts on, -`ℋ Λ' ≅ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)`, under which `𝔄(Λ)` acts as `B(ℋ Λ) ⊗ 1`. We take this spatial form as -the definition: a `Split` structure assigns to each region a finite-dimensional action space -`ℋ Λ`, identifies `𝔄(Λ)` with the type I factor `End ℂ (ℋ Λ)` (`act`), and presents each isotony -embedding `incl h` as the **ampliation** `X ↦ X ⊗ 1` along a tensor factorisation `decomp h` -(`act_incl`). - -From this hypothesis we derive the consequences that the literature uses: - -* `Split.decomp` is the tensor factorisation of the action space itself; -* `Split.partialTrace` is the partial trace on the action space (trace out the complementary - factor), reusing `LinearMap.partialTrace` from `ForMathlib.LinearAlgebra.Trace`; -* `Split.restrict` transports it to a marginal map `𝔄(Λ') →ₗ 𝔄(Λ)` on the algebra; -* `Split.restrict_incl_mul` is the conditional-expectation / partial-trace pull-out - `restrict (incl x * y) = x * restrict y`, the algebraic heart of statistical independence. - -None of this requires von Neumann algebra theory: the partial trace and the ampliation are the -purely linear-algebraic operators of `ForMathlib.LinearAlgebra.Trace`, parameterised by the -explicit decomposition `decomp h`. The split factorisation is carried as spatial data on the -abstract net (`act`/`decomp`/`act_incl`/`act_incl_compl`), not committed to any concrete model. - -## References - -* Matsui 2011 (`https://arxiv.org/abs/1109.5778`) §2, eqns (2.1)–(2.4). -* Fewster 2016 (`https://arxiv.org/abs/1601.06936`) eqns (12)–(13). --/ - -@[expose] public section - -open scoped TensorProduct - -namespace LocalNet - -variable {sites : Type*} [DecidableEq sites] - -/-- A **split structure** on a local net `N` over a family of finite-dimensional action spaces -`ℋ`: the spatial form of the split property. Each local algebra is identified with the type I -factor of operators on its action space (`act : 𝔄(Λ) ≃ₐ End ℂ (ℋ Λ)`), and each isotony -embedding is the ampliation `X ↦ X ⊗ 1` along a tensor factorisation of the action space -`decomp h : ℋ Λ' ≃ₗ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)` (`act_incl`). This is the Doplicher–Longo standard split -inclusion (Fewster 2016 eqns (12)–(13)) / Matsui 2011 eqn (2.2) read as a hypothesis: it holds for -some nets and fails for others, and there is no universal proof, so it is carried as data. -/ -structure Split (N : LocalNet sites) (ℋ : Finset sites → Type*) - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] where - /-- Each local algebra `𝔄(Λ)` is the type I factor `End ℂ (ℋ Λ)` of operators on its action - space, `*`-isomorphically (the `*`-structure is recorded by `act_star`). -/ - act : ∀ Λ, N.algebra Λ ≃ₐ[ℂ] Module.End ℂ (ℋ Λ) - /-- `act` is a `*`-isomorphism: it intertwines the C⋆-involution of `𝔄(Λ)` with the adjoint on - `End ℂ (ℋ Λ)`. Together with `act` this is the spatial split property's type I identification - `𝔄(Λ) ≅ B(ℋ Λ)` as C⋆-algebras (not merely as algebras). -/ - act_star : ∀ {Λ : Finset sites} (x : N.algebra Λ), act Λ (star x) = star (act Λ x) - /-- The **tensor factorisation of the action space** `ℋ Λ' ≅ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)` for an - inclusion `Λ ⊆ Λ'`. This is the spatial content of the split property. -/ - decomp : ∀ {Λ Λ' : Finset sites}, Λ ⊆ Λ' → (ℋ Λ' ≃ₗ[ℂ] ℋ Λ ⊗[ℂ] ℋ (Λ' \ Λ)) - /-- The factorisation is a **unitary** (norm-preserving): the Hilbert space splits *isometrically* - as `ℋ Λ' ≅ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)`. This is what makes the induced marginal a quantum channel - (the partial trace of a positive operator stays positive); see `decompᵢ`. -/ - decomp_norm : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : ℋ Λ'), ‖decomp h x‖ = ‖x‖ - /-- **Isotony is the ampliation**: under the identification `act`, the isotony embedding - `incl h` acts as `X ↦ X ⊗ 1` along the factorisation `decomp h` (Matsui eqn (2.2)). -/ - act_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), - act Λ' (N.incl h x) = LinearMap.ampliate (decomp h) (act Λ x) - /-- **The complementary region acts on the complementary factor**: under the identification - `act`, the isotony embedding of the complement `Λ' ∖ Λ` acts as `Y ↦ 1 ⊗ Y` along the - factorisation `decomp h`. This is the second half of the spatial split property (Fewster 2016 - eqns (12)–(13)): the standard split inclusion factorises `ℋ Λ'` so that *both* `𝔄(Λ)` and - `𝔄(Λ' ∖ Λ)` act canonically on their respective tensor factors. It is genuine spatial data: - the bare net axioms and `act_incl` pin the complement action only up to an inner unitary on - the complementary factor (Skolem–Noether), and this field fixes that gauge to the canonical - one, as the standard-form factorisation does. -/ - act_incl_compl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ' \ Λ)), - act Λ' (N.incl Finset.sdiff_subset y) = LinearMap.coampliate (decomp h) (act (Λ' \ Λ) y) - -namespace Split - -variable {N : LocalNet sites} {ℋ : Finset sites → Type*} - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] - (S : Split N ℋ) - -/-- The tensor factorisation `decomp h` as a **unitary** (`LinearIsometryEquiv`), using the -norm-preservation witness `decomp_norm`. This is the Hilbert-space tensor isometry -`U : ℋ Λ' ≃ₗᵢ ℋ Λ ⊗ ℋ (Λ' ∖ Λ)` of the spatial split property (Fewster 2016 eqn (13)). -/ -noncomputable def decompᵢ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - ℋ Λ' ≃ₗᵢ[ℂ] ℋ Λ ⊗[ℂ] ℋ (Λ' \ Λ) := - { S.decomp h with norm_map' := S.decomp_norm h } - -@[simp] theorem decompᵢ_toLinearEquiv {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - (S.decompᵢ h).toLinearEquiv = S.decomp h := - rfl - -/-- The **partial trace on the action space** induced by the split factorisation: trace out the -complementary factor `ℋ (Λ' ∖ Λ)` and retain `ℋ Λ`. This is `LinearMap.partialTrace` paired with -the tensor decomposition `decomp h`. -/ -noncomputable def partialTrace {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - Module.End ℂ (ℋ Λ') →ₗ[ℂ] Module.End ℂ (ℋ Λ) := - LinearMap.partialTrace (S.decomp h) - -/-- The **marginal map** `𝔄(Λ') →ₗ 𝔄(Λ)` of the net: the partial trace on the action space -transported to the algebra along `act`. This is the abstract, representation-free analogue of -`Matrix.restrict` (partial trace of a density matrix onto the subregion). -/ -noncomputable def restrict {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - N.algebra Λ' →ₗ[ℂ] N.algebra Λ := - (S.act Λ).symm.toLinearMap ∘ₗ LinearMap.partialTrace (S.decomp h) ∘ₗ (S.act Λ').toLinearMap - -theorem restrict_apply {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra Λ') : - S.restrict h y = (S.act Λ).symm (LinearMap.partialTrace (S.decomp h) (S.act Λ' y)) := - rfl - -/-- **Partial-trace pull-out** (conditional-expectation property): tracing the complement out of -`incl h x * y` factors the embedded `x` out of the marginal, -`restrict h (incl h x * y) = x * restrict h y`. This is the algebraic heart of the statistical -independence supplied by the split property (Fewster 2016 eqn (3)); it is the Heisenberg-picture -trace identity `Tr_B((X ⊗ 1) · ρ) = X · Tr_B ρ` (`LinearMap.partialTrace_ampliate_mul`) -transported to the net. -/ -theorem restrict_incl_mul {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') - (x : N.algebra Λ) (y : N.algebra Λ') : - S.restrict h (N.incl h x * y) = x * S.restrict h y := by - rw [restrict_apply, restrict_apply, map_mul (S.act Λ'), S.act_incl h x, - LinearMap.partialTrace_ampliate_mul, map_mul (S.act Λ).symm, AlgEquiv.symm_apply_apply] - -end Split - -end LocalNet diff --git a/QuantumSystem/Analysis/Entropy/SplitEntropy.lean b/QuantumSystem/Analysis/Entropy/SplitEntropy.lean deleted file mode 100644 index ea6eb53..0000000 --- a/QuantumSystem/Analysis/Entropy/SplitEntropy.lean +++ /dev/null @@ -1,45 +0,0 @@ -module - -public import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Basic -public import Mathlib.Analysis.SpecialFunctions.Log.NegMulLog -public import QuantumSystem.Analysis.Entropy.SplitTrace - -/-! -# Von Neumann entropy on a split net - -The von Neumann entropy of a state of a split net, stated **representation-free** on the local -C⋆-algebra. The local algebra `N.algebra Λ` of a split net is a unital C⋆-algebra, so it carries -the continuous functional calculus `cfc`; combined with the split trace `LocalNet.Split.trace` -this defines - - `S(ρ) = Tr (negMulLog ρ) = -Tr (ρ log ρ)`, - -exactly mirroring the matrix definition `Matrix.vonNeumannEntropy` (`vonNeumannEntropy_eq_cfc_re`) -but with no index basis. Here `Real.negMulLog x = -x * log x` is Mathlib's entropy integrand, with -the `0 log 0 = 0` convention built in. - -Its quantitative properties (non-negativity, strong subadditivity) are obtained in later files by -transporting the matrix theory along an orthonormal basis of the action space. --/ - -@[expose] public section - -namespace LocalNet.Split - -variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] - (S : Split N ℋ) - -/-- **Von Neumann entropy** of a state `ρ` of a split net at region `Λ`: -`S(ρ) = Tr (negMulLog ρ)`, the representation-free analogue of `Matrix.vonNeumannEntropy`. The -trace is the split trace `Split.trace` and `negMulLog ρ` is the continuous functional calculus of -`Real.negMulLog` on the local C⋆-algebra. -/ -noncomputable def entropy {Λ : Finset sites} (ρ : N.algebra Λ) : ℝ := - (S.trace Λ (cfc Real.negMulLog ρ)).re - -theorem entropy_def {Λ : Finset sites} (ρ : N.algebra Λ) : - S.entropy ρ = (S.trace Λ (cfc Real.negMulLog ρ)).re := - rfl - -end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean deleted file mode 100644 index 6bc989e..0000000 --- a/QuantumSystem/Analysis/Entropy/SplitRelativeEntropy.lean +++ /dev/null @@ -1,101 +0,0 @@ -module - -public import QuantumSystem.Analysis.Entropy.SplitTransport -public import QuantumSystem.Analysis.Entropy.RelativeEntropy - -/-! -# Relative entropy on a split net - -The **quantum relative entropy** of two states of a split net, stated representation-free on the -local C⋆-algebra. Since the split property makes each local algebra a type I factor (`act`), a state -is a density operator and the Araki relative entropy coincides with the density-operator relative -entropy `D(ρ ‖ σ) = Tr (ρ (log ρ - log σ))`; we obtain it by transporting to the matrix -representation `toMatrix` and reusing `Matrix.relativeEntropy`. - -The key inequality (the **data-processing inequality** under the marginal `restrict`) is the engine -of strong subadditivity; it is established in `SplitSSA` via the transported quantum channel. --/ - -@[expose] public section - -open scoped MatrixOrder ComplexOrder - -namespace LocalNet.Split - -variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] - (S : Split N ℋ) - -/-- **Quantum relative entropy** `D(ρ ‖ σ)` of two states of the split net at region `Λ`, defined -by transporting to the matrix representation (`toDensityMatrix`) and reusing `Matrix.relativeEntropy` -(for the type I factor this is the Araki relative entropy). -/ -noncomputable def relativeEntropy {Λ : Finset sites} {ρ σ : N.algebra Λ} - (hρ : S.IsDensity ρ) (hσ : S.IsDensity σ) : EReal := - Matrix.relativeEntropy (S.toDensityMatrix hρ) (S.toDensityMatrix hσ) - -/-- Relative entropy is **non-negative** (Klein's inequality), transported from the matrix result. -/ -theorem relativeEntropy_nonneg {Λ : Finset sites} {ρ σ : N.algebra Λ} - (hρ : S.IsDensity ρ) (hσ : S.IsDensity σ) : - 0 ≤ S.relativeEntropy hρ hσ := - Matrix.relativeEntropy_nonneg _ _ - -/-- The **transported marginal as a matrix map** `M ↦ toMatrix (restrict (toMatrix.symm M))`: the -partial-trace marginal `restrict h` read through the matrix representation of the type I factors. -/ -noncomputable def restrictChannelMap {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - Matrix (Fin (Module.finrank ℂ (ℋ Λ'))) (Fin (Module.finrank ℂ (ℋ Λ'))) ℂ →ₗ[ℂ] - Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ))) ℂ where - toFun M := S.toMatrix Λ (S.restrict h ((S.toMatrix Λ').symm M)) - map_add' M M' := by simp only [map_add] - map_smul' c M := by simp only [map_smul, RingHom.id_apply] - -@[simp] theorem restrictChannelMap_apply {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') - (M : Matrix (Fin (Module.finrank ℂ (ℋ Λ'))) (Fin (Module.finrank ℂ (ℋ Λ'))) ℂ) : - S.restrictChannelMap h M = S.toMatrix Λ (S.restrict h ((S.toMatrix Λ').symm M)) := - rfl - -/-- The transported marginal is a **quantum channel** (completely positive + trace preserving): -complete positivity from the matrix Kraus form `toMatrix_restrict_eq_sum_kraus`, trace preservation -from `trace_restrict`. This realises the partial trace as a CPTP map, as required for the -data-processing inequality. -/ -theorem isQuantumChannel_restrictChannelMap {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - Matrix.IsQuantumChannel (S.restrictChannelMap h) where - completelyPositive := by - refine ⟨Module.finrank ℂ (ℋ (Λ' \ Λ)), S.restrictKraus h, fun M => ?_⟩ - rw [restrictChannelMap_apply, S.toMatrix_restrict_eq_sum_kraus h, - StarAlgEquiv.apply_symm_apply] - tracePreserving := by - intro M - rw [restrictChannelMap_apply, ← S.trace_eq_matrixTrace, S.trace_restrict h, - S.trace_eq_matrixTrace, StarAlgEquiv.apply_symm_apply] - -/-- The transported marginal packaged as a `QuantumChannel`. -/ -noncomputable def restrictMatrixChannel {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') : - Matrix.QuantumChannel (Fin (Module.finrank ℂ (ℋ Λ'))) (Fin (Module.finrank ℂ (ℋ Λ))) := - ⟨S.restrictChannelMap h, S.isQuantumChannel_restrictChannelMap h⟩ - -/-- The matrix channel transports `toDensityMatrix` along the marginal: it sends the density matrix -of `ρ` to the density matrix of `restrict h ρ`. -/ -theorem restrictMatrixChannel_apply {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') - {ρ : N.algebra Λ'} (hρ : S.IsDensity ρ) : - S.restrictMatrixChannel h (S.toDensityMatrix hρ) - = S.toDensityMatrix (S.restrict_isDensity h hρ) := by - apply DensityMatrix.ext - change S.restrictChannelMap h (S.toMatrix Λ' ρ) = S.toMatrix Λ (S.restrict h ρ) - rw [restrictChannelMap_apply, StarAlgEquiv.symm_apply_apply] - -/-- **Data-processing inequality for the marginal**: the quantum relative entropy of two states does -not increase under the marginal `restrict h`, -`D(restrict ρ ‖ restrict σ) ≤ D(ρ ‖ σ)`. This is monotonicity of relative entropy under the -partial-trace quantum channel `restrictMatrixChannel`; it is the analytic engine of strong -subadditivity, stated representation-free on the split net. -/ -theorem relativeEntropy_restrict_le {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') - {ρ σ : N.algebra Λ'} (hρ : S.IsDensity ρ) (hσ : S.IsDensity σ) : - S.relativeEntropy (S.restrict_isDensity h hρ) (S.restrict_isDensity h hσ) - ≤ S.relativeEntropy hρ hσ := by - have key := Matrix.relativeEntropy_channel_le (S.restrictMatrixChannel h) - (S.toDensityMatrix hρ) (S.toDensityMatrix hσ) - rw [S.restrictMatrixChannel_apply h hρ, S.restrictMatrixChannel_apply h hσ] at key - exact key - -end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitSSA.lean b/QuantumSystem/Analysis/Entropy/SplitSSA.lean deleted file mode 100644 index 8b3b9ec..0000000 --- a/QuantumSystem/Analysis/Entropy/SplitSSA.lean +++ /dev/null @@ -1,713 +0,0 @@ -module - -public import QuantumSystem.Analysis.Entropy.SplitTransport -public import QuantumSystem.Analysis.Entropy.StrongSubadditivityProduct - -/-! -# Strong subadditivity on a split net - -The **strong subadditivity** of the von Neumann entropy, stated representation-free on the abstract -operator-algebraic split net `LocalNet.Split`, assembled from: - -* the **data-processing inequality** `relativeEntropy_restrict_le` (the analytic engine); -* the **tensor commutant theorem** `LinearMap.exists_map_one_of_commute_map_id`, which makes the - partial trace depend only on the subsystem traced out (factorisation uniqueness); -* **basis-independence of the von Neumann entropy** `vonNeumannEntropy_toDensityMatrixBasis`, - which lets us read marginals in a tensor-factorised orthonormal basis; -* the matrix-level `DensityMatrix.vonNeumannEntropy_SSA_product`. - -The first brick is the **partial-trace correspondence**: in the orthonormal basis pulled back from a -tensor factorisation, the matrix partial trace `Matrix.traceRight` realises the operator partial -trace `LinearMap.partialTrace`. --/ - -@[expose] public section - -open scoped TensorProduct ComplexOrder MatrixOrder - -namespace LinearMap - -variable {ℋ A B : Type*} - [NormedAddCommGroup ℋ] [InnerProductSpace ℂ ℋ] [FiniteDimensional ℂ ℋ] - [NormedAddCommGroup A] [InnerProductSpace ℂ A] [FiniteDimensional ℂ A] - [NormedAddCommGroup B] [InnerProductSpace ℂ B] [FiniteDimensional ℂ B] - -/-- **Partial-trace correspondence.** Read in the orthonormal basis of `ℋ` pulled back from the -tensor product basis `bA ⊗ bB` along a unitary factorisation `e : ℋ ≃ₗᵢ A ⊗ B`, the matrix partial -trace over the `B`-index (`Matrix.traceRight`) realises the operator partial trace -`LinearMap.partialTrace e`. -/ -theorem traceRight_toMatrixOrthonormal (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) - {κ ν : Type*} [Fintype κ] [DecidableEq κ] [Fintype ν] [DecidableEq ν] - (bA : OrthonormalBasis κ ℂ A) (bB : OrthonormalBasis ν ℂ B) (T : Module.End ℂ ℋ) : - Matrix.traceRight (LinearMap.toMatrixOrthonormal ((bA.tensorProduct bB).map e.symm) T) - = LinearMap.toMatrixOrthonormal bA (LinearMap.partialTrace e.toLinearEquiv T) := by - ext i j - rw [Matrix.traceRight_apply, LinearMap.toMatrixOrthonormal_apply_apply, partialTrace_apply, - ← inner_conj_symm (𝕜 := ℂ), TensorProduct.inner_partialTraceRight bB, map_sum] - refine Finset.sum_congr rfl fun k _ => ?_ - rw [LinearMap.toMatrixOrthonormal_apply_apply, OrthonormalBasis.map_apply, - OrthonormalBasis.tensorProduct_apply, OrthonormalBasis.map_apply, - OrthonormalBasis.tensorProduct_apply, AlgEquiv.apply_symm_apply, - LinearEquiv.conjAlgEquiv_apply_apply, - show (e.toLinearEquiv) (T (e.toLinearEquiv.symm (bA j ⊗ₜ[ℂ] bB k))) - = e (T (e.symm (bA j ⊗ₜ[ℂ] bB k))) from rfl, - ← e.inner_map_map (e.symm (bA i ⊗ₜ[ℂ] bB k)) (T (e.symm (bA j ⊗ₜ[ℂ] bB k))), - e.apply_symm_apply] - exact (inner_conj_symm _ _).symm - -/-- **Partial-trace correspondence, left factor.** Tracing out the *first* index (`Matrix.traceLeft`) -of the matrix in the basis pulled back from `bA ⊗ bB` along `e : ℋ ≃ₗᵢ A ⊗ B` realises the operator -partial trace along `e` post-composed with the tensor swap — i.e. tracing out the `A`-factor and -retaining `B`. This reads the `A`-marginal (`ptLeft`) of the tensor-factorised density matrix. -/ -theorem traceLeft_toMatrixOrthonormal (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) - {κ ν : Type*} [Fintype κ] [DecidableEq κ] [Fintype ν] [DecidableEq ν] - (bA : OrthonormalBasis κ ℂ A) (bB : OrthonormalBasis ν ℂ B) (T : Module.End ℂ ℋ) : - Matrix.traceLeft (LinearMap.toMatrixOrthonormal ((bA.tensorProduct bB).map e.symm) T) - = LinearMap.toMatrixOrthonormal bB - (LinearMap.partialTrace (e.trans (TensorProduct.commIsometry ℂ A B)).toLinearEquiv T) := by - have hswap : ((bA.tensorProduct bB).map e.symm).reindex (Equiv.prodComm κ ν) - = (bB.tensorProduct bA).map (e.trans (TensorProduct.commIsometry ℂ A B)).symm := by - apply DFunLike.ext - rintro ⟨j, i⟩ - simp only [OrthonormalBasis.reindex_apply, OrthonormalBasis.map_apply, - OrthonormalBasis.tensorProduct_apply, Equiv.prodComm_symm, Equiv.prodComm_apply, - Prod.swap_prod_mk, LinearIsometryEquiv.symm_trans, LinearIsometryEquiv.trans_apply, - TensorProduct.commIsometry_symm, TensorProduct.commIsometry_apply, - TensorProduct.comm_tmul] - rw [Matrix.traceLeft_eq_traceRight_prodComm, ← LinearMap.toMatrixOrthonormal_reindex, hswap, - LinearMap.traceRight_toMatrixOrthonormal] - -end LinearMap - -/-! ### Conjugation under a tensor congruence -/ - -/-- Conjugating an ampliation `N ⊗ M` by a tensor congruence `congr f g` distributes: -`(congr f g)-conj (N ⊗ M) = (f-conj N) ⊗ (g-conj M)`. -/ -theorem TensorProduct.congr_conjAlgEquiv_map {𝕜 E F G K : Type*} [Field 𝕜] - [AddCommGroup E] [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F] - [AddCommGroup G] [Module 𝕜 G] [AddCommGroup K] [Module 𝕜 K] - (f : E ≃ₗ[𝕜] F) (g : G ≃ₗ[𝕜] K) (N : Module.End 𝕜 E) (M : Module.End 𝕜 G) : - (TensorProduct.congr f g).conjAlgEquiv 𝕜 (TensorProduct.map N M) - = TensorProduct.map (f.conjAlgEquiv 𝕜 N) (g.conjAlgEquiv 𝕜 M) := by - rw [LinearEquiv.conjAlgEquiv_apply, LinearEquiv.conjAlgEquiv_apply, - LinearEquiv.conjAlgEquiv_apply] - apply TensorProduct.ext' - intro f' k' - simp [TensorProduct.map_tmul] - -/-- Conjugation by a composite equivalence is the composite of conjugations. -/ -theorem LinearEquiv.conjAlgEquiv_trans {𝕜 M₁ M₂ M₃ : Type*} [Field 𝕜] - [AddCommGroup M₁] [Module 𝕜 M₁] [AddCommGroup M₂] [Module 𝕜 M₂] - [AddCommGroup M₃] [Module 𝕜 M₃] (e : M₁ ≃ₗ[𝕜] M₂) (f : M₂ ≃ₗ[𝕜] M₃) - (T : Module.End 𝕜 M₁) : - (e.trans f).conjAlgEquiv 𝕜 T = f.conjAlgEquiv 𝕜 (e.conjAlgEquiv 𝕜 T) := by - rw [LinearEquiv.conjAlgEquiv_apply, LinearEquiv.conjAlgEquiv_apply, - LinearEquiv.conjAlgEquiv_apply] - ext x - simp [LinearMap.comp_assoc] - -/-- Conjugating an ampliation by the tensor commutativity isomorphism swaps the two factors. -/ -theorem TensorProduct.comm_conjAlgEquiv_map {𝕜 A B : Type*} [Field 𝕜] - [AddCommGroup A] [Module 𝕜 A] [AddCommGroup B] [Module 𝕜 B] - (f : Module.End 𝕜 A) (g : Module.End 𝕜 B) : - (TensorProduct.comm 𝕜 A B).conjAlgEquiv 𝕜 (TensorProduct.map f g) - = TensorProduct.map g f := by - rw [LinearEquiv.conjAlgEquiv_apply] - apply TensorProduct.ext' - intro b a - simp [TensorProduct.map_tmul] - -/-- Conjugating a nested ampliation `(f ⊗ g) ⊗ h` by the tensor associativity isomorphism -reassociates it to `f ⊗ (g ⊗ h)`. -/ -theorem TensorProduct.assoc_conjAlgEquiv_map {𝕜 A B C : Type*} [Field 𝕜] - [AddCommGroup A] [Module 𝕜 A] [AddCommGroup B] [Module 𝕜 B] [AddCommGroup C] [Module 𝕜 C] - (f : Module.End 𝕜 A) (g : Module.End 𝕜 B) (h : Module.End 𝕜 C) : - (TensorProduct.assoc 𝕜 A B C).conjAlgEquiv 𝕜 - (TensorProduct.map (TensorProduct.map f g) h) - = TensorProduct.map f (TensorProduct.map g h) := by - rw [LinearEquiv.conjAlgEquiv_apply] - apply TensorProduct.ext' - intro a bc - induction bc using TensorProduct.induction_on with - | zero => simp - | tmul b c => simp [TensorProduct.map_tmul] - | add y z hy hz => simp only [map_add, TensorProduct.tmul_add, hy, hz] - -/-! ### Naturality of the partial trace under relabelling the retained factor -/ - -section Naturality - -variable {R H K K' D : Type*} [Field R] - [AddCommGroup H] [Module R H] - [AddCommGroup K] [Module R K] [Module.Finite R K] [Module.Free R K] - [AddCommGroup K'] [Module R K'] [Module.Finite R K'] [Module.Free R K'] - [AddCommGroup D] [Module R D] [Module.Finite R D] [Module.Free R D] - -omit [Module.Finite R K] [Module.Free R K] [Module.Finite R K'] [Module.Free R K'] - [Module.Finite R D] [Module.Free R D] in -/-- `partialTraceRight` is natural under relabelling the retained (first) factor by `V`: it carries -the ampliation `V ⊗ 1` (here `LinearEquiv.conj V` on the first factor of the operator tensor) through -to conjugation by `V` of the result. -/ -theorem TensorProduct.partialTraceRight_map_conj (V : K ≃ₗ[R] K') - (S : Module.End R K ⊗[R] Module.End R D) : - TensorProduct.partialTraceRight - (TensorProduct.map (LinearEquiv.conj V).toLinearMap LinearMap.id S) - = (LinearEquiv.conj V) (TensorProduct.partialTraceRight S) := by - induction S using TensorProduct.induction_on with - | zero => simp - | tmul L Rr => simp only [TensorProduct.map_tmul, LinearMap.id_apply, - TensorProduct.partialTraceRight_tmul, map_smul, LinearEquiv.coe_coe] - | add S₁ S₂ h₁ h₂ => simp only [map_add, h₁, h₂] - -/-- Naturality of `endTensorEndAlgEquiv` under conjugation by `congr V 1`: it intertwines the -operator-level conjugation by `V ⊗ 1` with the tensor-level `conj V ⊗ id`. -/ -theorem TensorProduct.endTensorEndAlgEquiv_symm_conjAlgEquiv_congr (V : K ≃ₗ[R] K') - (S : Module.End R K ⊗[R] Module.End R D) : - (TensorProduct.endTensorEndAlgEquiv).symm - ((TensorProduct.congr V (LinearEquiv.refl R D)).conjAlgEquiv R - (TensorProduct.endTensorEndAlgEquiv S)) - = TensorProduct.map (LinearEquiv.conj V).toLinearMap LinearMap.id S := by - induction S using TensorProduct.induction_on with - | zero => simp - | tmul L Rr => - rw [TensorProduct.endTensorEndAlgEquiv_tmul, LinearEquiv.conjAlgEquiv_apply, - show (TensorProduct.congr V (LinearEquiv.refl R D)).toLinearMap - = TensorProduct.map V.toLinearMap LinearMap.id from by ext; simp, - show ((TensorProduct.congr V (LinearEquiv.refl R D)).symm.toLinearMap) - = TensorProduct.map V.symm.toLinearMap LinearMap.id from by - ext; simp [TensorProduct.congr_symm], - ← TensorProduct.map_comp, ← TensorProduct.map_comp, TensorProduct.map_tmul, LinearMap.id_apply, - AlgEquiv.symm_apply_eq, TensorProduct.endTensorEndAlgEquiv_tmul] - rfl - | add S₁ S₂ h₁ h₂ => simp only [map_add, h₁, h₂] - -/-- **Naturality of the partial trace.** Composing the factorisation `e : H ≃ₗ K ⊗ D` with a -relabelling `V ⊗ 1` of the retained factor conjugates the partial trace by `V`: -`Tr_D ((V ⊗ 1) ∘ e) = V ∘ (Tr_D e) ∘ V⁻¹`. Two factorisations differing by `V ⊗ 1` give unitarily -equivalent marginals — the operator content of factorisation uniqueness. -/ -theorem LinearMap.partialTrace_congr_conj (V : K ≃ₗ[R] K') (e : H ≃ₗ[R] K ⊗[R] D) - (T : Module.End R H) : - LinearMap.partialTrace (e ≪≫ₗ TensorProduct.congr V (LinearEquiv.refl R D)) T - = (LinearEquiv.conj V) (LinearMap.partialTrace e T) := by - rw [LinearMap.partialTrace_apply, LinearMap.partialTrace_apply] - have hcomp : (e ≪≫ₗ TensorProduct.congr V (LinearEquiv.refl R D)).conjAlgEquiv R T - = (TensorProduct.congr V (LinearEquiv.refl R D)).conjAlgEquiv R (e.conjAlgEquiv R T) := by - rw [LinearEquiv.conjAlgEquiv_apply, LinearEquiv.conjAlgEquiv_apply, - LinearEquiv.conjAlgEquiv_apply] - rfl - rw [hcomp, ← (TensorProduct.endTensorEndAlgEquiv).apply_symm_apply (e.conjAlgEquiv R T), - TensorProduct.endTensorEndAlgEquiv_symm_conjAlgEquiv_congr, TensorProduct.partialTraceRight_map_conj, - AlgEquiv.symm_apply_apply] - -/-- **The partial trace is invariant under a unitary relabelling of the traced-out factor.** -Composing `e : H ≃ₗ K ⊗ D` with `congr 1 U` (identity on the retained factor `K`, an isomorphism `U` -on the traced factor `D ≃ D'`) leaves the partial trace unchanged — the trace of the traced factor -is conjugation-invariant. This lets the `castIso`-relabelled factorisation `bcDirect` share its -partial trace with the canonical `BC`-marginal `restrict (decompᵢ (sdiff))`. -/ -theorem LinearMap.partialTrace_congr_right_id (e : H ≃ₗ[R] K ⊗[R] D) (U : D ≃ₗ[R] K') - (T : Module.End R H) : - LinearMap.partialTrace (e ≪≫ₗ TensorProduct.congr (LinearEquiv.refl R K) U) T - = LinearMap.partialTrace e T := by - rw [LinearMap.partialTrace_apply, LinearMap.partialTrace_apply, - LinearEquiv.conjAlgEquiv_trans e (TensorProduct.congr (LinearEquiv.refl R K) U) T, - ← (TensorProduct.endTensorEndAlgEquiv (R := R) (M := K) (N := D)).apply_symm_apply - (e.conjAlgEquiv R T)] - generalize (TensorProduct.endTensorEndAlgEquiv (R := R) (M := K) (N := D)).symm - (e.conjAlgEquiv R T) = W - induction W using TensorProduct.induction_on with - | zero => simp - | tmul Y Z => - rw [AlgEquiv.symm_apply_apply, TensorProduct.partialTraceRight_tmul, - TensorProduct.endTensorEndAlgEquiv_tmul, TensorProduct.congr_conjAlgEquiv_map, - ← TensorProduct.endTensorEndAlgEquiv_tmul, AlgEquiv.symm_apply_apply, - TensorProduct.partialTraceRight_tmul, - show U.conjAlgEquiv R Z = U.conj Z from rfl, LinearMap.trace_conj'] - congr 1 - | add W₁ W₂ h₁ h₂ => simp only [map_add, h₁, h₂] - -end Naturality - -/-! ### Factorisation uniqueness: extracting the relabelling isometry -/ - -section FactorizationUniqueness - -variable {K K' D : Type*} - [NormedAddCommGroup K] [InnerProductSpace ℂ K] [FiniteDimensional ℂ K] - [NormedAddCommGroup K'] [InnerProductSpace ℂ K'] [FiniteDimensional ℂ K'] - [NormedAddCommGroup D] [InnerProductSpace ℂ D] [FiniteDimensional ℂ D] - -omit [FiniteDimensional ℂ K] in -/-- A unitary `Φ : K ⊗ D ≃ₗᵢ K' ⊗ D` whose underlying map is an ampliation `V ⊗ 1` of a linear map -`V_lin` upgrades that `V_lin` to a **unitary** `V : K ≃ₗᵢ K'`: it is automatically an -isometric isomorphism. (`Φ = V ⊗ 1` with `Φ` unitary forces `V` unitary.) -/ -theorem exists_isometryEquiv_of_toLinearMap_eq_map [Nontrivial D] - (Φ : (K ⊗[ℂ] D) ≃ₗᵢ[ℂ] (K' ⊗[ℂ] D)) (V_lin : K →ₗ[ℂ] K') - (hΦ : Φ.toLinearEquiv.toLinearMap = TensorProduct.map V_lin LinearMap.id) : - ∃ V : K ≃ₗᵢ[ℂ] K', V.toLinearEquiv.toLinearMap = V_lin := by - obtain ⟨d₀, hd₀⟩ := exists_ne (0 : D) - have hdd : (inner ℂ d₀ d₀ : ℂ) ≠ 0 := by simp only [ne_eq, inner_self_eq_zero]; exact hd₀ - have hiso : ∀ k₁ k₂ : K, (inner ℂ (V_lin k₁) (V_lin k₂) : ℂ) = inner ℂ k₁ k₂ := by - intro k₁ k₂ - have h1 : (inner ℂ (Φ (k₁ ⊗ₜ[ℂ] d₀)) (Φ (k₂ ⊗ₜ[ℂ] d₀)) : ℂ) - = inner ℂ (k₁ ⊗ₜ[ℂ] d₀) (k₂ ⊗ₜ[ℂ] d₀) := Φ.inner_map_map _ _ - rw [show Φ (k₁ ⊗ₜ[ℂ] d₀) = V_lin k₁ ⊗ₜ[ℂ] d₀ by - rw [show Φ (k₁ ⊗ₜ[ℂ] d₀) = Φ.toLinearEquiv.toLinearMap (k₁ ⊗ₜ[ℂ] d₀) from rfl, hΦ]; simp, - show Φ (k₂ ⊗ₜ[ℂ] d₀) = V_lin k₂ ⊗ₜ[ℂ] d₀ by - rw [show Φ (k₂ ⊗ₜ[ℂ] d₀) = Φ.toLinearEquiv.toLinearMap (k₂ ⊗ₜ[ℂ] d₀) from rfl, hΦ]; simp, - TensorProduct.inner_tmul, TensorProduct.inner_tmul] at h1 - exact mul_right_cancel₀ hdd h1 - have hinj : Function.Injective V_lin := by - rw [← LinearMap.ker_eq_bot, LinearMap.ker_eq_bot'] - intro k hk - have := hiso k k - rw [hk] at this; simp only [inner_zero_left] at this - exact inner_self_eq_zero.mp this.symm - have hrank : Module.finrank ℂ K = Module.finrank ℂ K' := by - have := Φ.toLinearEquiv.finrank_eq - rw [Module.finrank_tensorProduct, Module.finrank_tensorProduct] at this - exact Nat.eq_of_mul_eq_mul_right Module.finrank_pos this - have hsurj : Function.Surjective V_lin := by - rw [← LinearMap.range_eq_top] - apply Submodule.eq_top_of_finrank_eq - rw [LinearMap.finrank_range_of_inj hinj, hrank] - let Ve : K ≃ₗ[ℂ] K' := LinearEquiv.ofBijective V_lin ⟨hinj, hsurj⟩ - refine ⟨{ Ve with norm_map' := fun k => ?_ }, rfl⟩ - rw [← Real.sqrt_sq (norm_nonneg (Ve k)), ← Real.sqrt_sq (norm_nonneg k)] - congr 1 - rw [← @inner_self_eq_norm_sq ℂ, ← @inner_self_eq_norm_sq ℂ] - exact congrArg Complex.re (hiso k k) - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [FiniteDimensional ℂ H] - -omit [FiniteDimensional ℂ H] in -/-- **Factorisation uniqueness.** Two unitary factorisations `e₁ : H ≃ₗᵢ K ⊗ D`, -`e₂ : H ≃ₗᵢ K' ⊗ D` that implement the *same* action of `End D` on `H` (`hcomm`: the transition -`e₁.symm.trans e₂` commutes with every `1 ⊗ f`) have partial traces over `D` that agree up to a -unitary `V : K ≃ₗᵢ K'`. The marginal of a state over a subsystem thus depends only on the subsystem, -not on the chosen factorisation of its complement. -/ -theorem factorization_uniqueness [Nontrivial D] - (e₁ : H ≃ₗᵢ[ℂ] (K ⊗[ℂ] D)) (e₂ : H ≃ₗᵢ[ℂ] (K' ⊗[ℂ] D)) - (hcomm : ∀ f : Module.End ℂ D, - (e₁.symm.trans e₂).toLinearEquiv.toLinearMap ∘ₗ TensorProduct.map LinearMap.id f - = TensorProduct.map LinearMap.id f ∘ₗ (e₁.symm.trans e₂).toLinearEquiv.toLinearMap) - (T : Module.End ℂ H) : - ∃ V : K ≃ₗᵢ[ℂ] K', - LinearMap.partialTrace e₂.toLinearEquiv T - = (LinearEquiv.conj V.toLinearEquiv) (LinearMap.partialTrace e₁.toLinearEquiv T) := by - set Φ : (K ⊗[ℂ] D) ≃ₗᵢ[ℂ] (K' ⊗[ℂ] D) := e₁.symm.trans e₂ with hΦdef - have hrank : Module.finrank ℂ K' = Module.finrank ℂ K := by - have := Φ.toLinearEquiv.finrank_eq - rw [Module.finrank_tensorProduct, Module.finrank_tensorProduct] at this - exact (Nat.eq_of_mul_eq_mul_right Module.finrank_pos this).symm - obtain ⟨W₀⟩ := - FiniteDimensional.nonempty_linearEquiv_of_finrank_eq (R := ℂ) (M := K') (M' := K) hrank - have hcomm2 : ∀ f : Module.End ℂ D, - (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) - ∘ₗ TensorProduct.map LinearMap.id f - = TensorProduct.map LinearMap.id f - ∘ₗ (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) := by - intro f - rw [LinearMap.comp_assoc, hcomm f, ← LinearMap.comp_assoc, ← LinearMap.comp_assoc] - congr 1 - rw [← TensorProduct.map_comp, ← TensorProduct.map_comp]; simp - obtain ⟨g, hg⟩ := LinearMap.exists_map_id_of_commute_map_one - (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) hcomm2 - have hVlin : Φ.toLinearEquiv.toLinearMap - = TensorProduct.map (W₀.symm.toLinearMap ∘ₗ g) LinearMap.id := by - have h2 : Φ.toLinearEquiv.toLinearMap = TensorProduct.map W₀.symm.toLinearMap LinearMap.id ∘ₗ - (TensorProduct.map W₀.toLinearMap LinearMap.id ∘ₗ Φ.toLinearEquiv.toLinearMap) := by - rw [← LinearMap.comp_assoc, ← TensorProduct.map_comp]; simp - rw [h2, hg, ← TensorProduct.map_comp]; simp - obtain ⟨V, hV⟩ := exists_isometryEquiv_of_toLinearMap_eq_map Φ _ hVlin - refine ⟨V, ?_⟩ - have hΦeq : Φ.toLinearEquiv = TensorProduct.congr V.toLinearEquiv (LinearEquiv.refl ℂ D) := by - apply LinearEquiv.toLinearMap_injective - rw [hVlin, ← hV]; ext; simp - have he₂ : e₂.toLinearEquiv = e₁.toLinearEquiv ≪≫ₗ Φ.toLinearEquiv := by - rw [hΦdef]; ext x; simp - rw [he₂, hΦeq, LinearMap.partialTrace_congr_conj] - -/-- Conjugating an operator by a unitary `V : K ≃ₗᵢ K'` and reading it in the `V`-image of an -orthonormal basis gives the *same matrix* as the original in the original basis. Hence the matrix — -and its von Neumann entropy — is unchanged by `conj V`. -/ -theorem toMatrixOrthonormal_conj_map {ι : Type*} [Fintype ι] [DecidableEq ι] - (V : K ≃ₗᵢ[ℂ] K') (b : OrthonormalBasis ι ℂ K) (X : Module.End ℂ K) : - LinearMap.toMatrixOrthonormal (b.map V) (LinearEquiv.conj V.toLinearEquiv X) - = LinearMap.toMatrixOrthonormal b X := by - ext i j - rw [LinearMap.toMatrixOrthonormal_apply_apply, LinearMap.toMatrixOrthonormal_apply_apply, - OrthonormalBasis.map_apply, OrthonormalBasis.map_apply, LinearEquiv.conj_apply_apply] - simp only [LinearIsometryEquiv.coe_toLinearEquiv] - rw [LinearIsometryEquiv.inner_map_map] - simp - -end FactorizationUniqueness - -/-! ### Reindexing the density matrix of a state -/ - -namespace LocalNet.Split - -variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] - (S : Split N ℋ) - -/-- Reindexing the orthonormal basis and then transporting the density matrix back along the same -equivalence is the identity: `(toDensityMatrixBasis (b.reindex e) hρ).mapEquiv e = -toDensityMatrixBasis b hρ`. Used to align the tensor-factorised basis with the `A × B × C` -positional index of `vonNeumannEntropy_SSA_product`. -/ -theorem toDensityMatrixBasis_reindex_mapEquiv {Λ : Finset sites} {ι ι' : Type*} - [Fintype ι] [DecidableEq ι] [Fintype ι'] [DecidableEq ι'] - (b : OrthonormalBasis ι ℂ (ℋ Λ)) (e : ι ≃ ι') {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - (S.toDensityMatrixBasis (b.reindex e) hρ).mapEquiv e = S.toDensityMatrixBasis b hρ := by - apply DensityMatrix.ext - rw [DensityMatrix.mapEquiv_toMatrix, S.toDensityMatrixBasis_toMatrix, - S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, S.toMatrixBasis_apply, - LinearMap.toMatrixOrthonormal_reindex] - ext a b' - simp [Matrix.submatrix_apply, Matrix.reindex_apply] - -/-- The canonical unitary transport `ℋ s ≃ₗᵢ ℋ t` along a propositional equality of regions -`s = t`. (Both action spaces are literally the same once `s = t` is substituted.) -/ -noncomputable def castEquiv {s t : Finset sites} (hst : s = t) : ℋ s ≃ₗᵢ[ℂ] ℋ t := by - rw [hst]; exact LinearIsometryEquiv.refl ℂ (ℋ t) - -/-- **The action is natural under `castEquiv`.** Transporting the operator `act s y` along the -region equality `s = t` (conjugating by `castEquiv`) yields `act t` of the transported operand. -This is the spatial half of the dependent-type coherence between a region and a propositionally -equal one, used to align the `act_incl_compl` action on `ΛABC ∖ (ΛABC ∖ ΛA)` with `act ΛA`. -/ -theorem castEquiv_conjAlgEquiv_act {s t : Finset sites} (hst : s = t) (x : N.algebra t) : - (castEquiv (ℋ := ℋ) hst).conjAlgEquiv ℂ (S.act s (hst.symm ▸ x)) = S.act t x := by - subst hst - simp only [castEquiv, eq_mpr_eq_cast, cast_eq] - rfl - -/-- The unitary identification `ℋ (ΛABC ∖ (ΛABC ∖ ΛA)) ≃ₗᵢ ℋ ΛA`, transporting the -complement-of-complement action space to the original sub-region's. Used to match the traced factor -of `decompᵢ` for the `BC` marginal (`ΛABC ∖ ΛA`) with `ΛA` in `factorization_uniqueness`. -/ -noncomputable def castIso {ΛA ΛABC : Finset sites} (h : ΛA ⊆ ΛABC) : - ℋ (ΛABC \ (ΛABC \ ΛA)) ≃ₗᵢ[ℂ] ℋ ΛA := - castEquiv (ℋ := ℋ) (by rw [Finset.sdiff_sdiff_self_left, Finset.inter_eq_right.mpr h]) - -/-- **The `A`-action through the nested factorisation `W`.** Reorganising `ℋ ΛABC` as -`(ℋ ΛA ⊗ ℋ (ΛAB ∖ ΛA)) ⊗ ℋ (ΛABC ∖ ΛAB)` (the unitary `W`), the embedded sub-region operator -`act ΛABC (incl x)` becomes the leftmost ampliation `(x ⊗ 1) ⊗ 1`. This pins the `A`-action in the -`(A ⊗ B) ⊗ C` picture and is the input to factorisation uniqueness for the `BC` marginal. -/ -theorem wReorg_conjAlgEquiv_act_incl {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) - (h_AB : ΛAB ⊆ ΛABC) (x : N.algebra ΛA) : - ((S.decompᵢ h_AB).trans - (TensorProduct.congrIsometry (S.decompᵢ h_A) - (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).toLinearEquiv.conjAlgEquiv ℂ - (S.act ΛABC (N.incl (h_A.trans h_AB) x)) - = TensorProduct.map (TensorProduct.map (S.act ΛA x) 1) 1 := by - rw [← N.incl_trans h_A h_AB, S.act_incl h_AB, S.act_incl h_A] - rw [show ((S.decompᵢ h_AB).trans - (TensorProduct.congrIsometry (S.decompᵢ h_A) - (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).toLinearEquiv - = (S.decompᵢ h_AB).toLinearEquiv.trans - (TensorProduct.congr (S.decompᵢ h_A).toLinearEquiv - (LinearEquiv.refl ℂ (ℋ (ΛABC \ ΛAB)))) from by - rw [LinearIsometryEquiv.toLinearEquiv_trans, TensorProduct.toLinearEquiv_congrIsometry]; rfl] - rw [LinearEquiv.conjAlgEquiv_trans, LinearMap.ampliate, S.decompᵢ_toLinearEquiv h_AB, - AlgEquiv.apply_symm_apply, TensorProduct.congr_conjAlgEquiv_map, LinearMap.ampliate, - S.decompᵢ_toLinearEquiv h_A, AlgEquiv.apply_symm_apply] - congr 1 - -/-- **Isotony is invariant under a propositional equality of regions.** If `s = t` as finsets, the -embeddings `incl (s ⊆ Λ)` and `incl (t ⊆ Λ)` agree once the operand is transported along `s = t`. -This discharges the dependent-type coherence between the complement-of-complement region -`ΛABC ∖ (ΛABC ∖ ΛA)` and `ΛA` in the `BC`-marginal factorisation uniqueness. -/ -theorem _root_.LocalNet.incl_cast {s t Λ : Finset sites} (hst : s = t) (hs : s ⊆ Λ) (ht : t ⊆ Λ) - (z : N.algebra s) : - N.incl hs z = N.incl ht (hst ▸ z) := by - subst hst; rfl - -/-- The reorganised unitary factorisation `ℋ ΛABC ≃ᵢ (ℋ B ⊗ ℋ C) ⊗ ℋ A` for the `BC` marginal: -factor out `ΛA` then `ΛAB ∖ ΛA`, reassociate, and move the `ΛA` factor to the end. This is the -factorisation `e₂` that reads the marginal of the `A × (B × C)` density matrix over the `A` factor; -the `ΛA` (traced-out) factor sits last so the partial trace over it lines up with `Matrix.traceRight` -of the reindexed density matrix. -/ -noncomputable def bcReorg {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) (h_AB : ΛAB ⊆ ΛABC) : - ℋ ΛABC ≃ₗᵢ[ℂ] (ℋ (ΛAB \ ΛA) ⊗[ℂ] ℋ (ΛABC \ ΛAB)) ⊗[ℂ] ℋ ΛA := - ((S.decompᵢ h_AB).trans - (TensorProduct.congrIsometry (S.decompᵢ h_A) - (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).trans - ((TensorProduct.assocIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)) (ℋ (ΛABC \ ΛAB))).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA) ⊗[ℂ] ℋ (ΛABC \ ΛAB)))) - -/-- **The `A`-action through the reorganised factorisation `bcReorg`** is the canonical ampliation -on the last factor: `bcReorg-conj (act ΛABC (incl x)) = 1 ⊗ act ΛA x`. Together with the -complementary `act_incl_compl` action of the `decompᵢ (sdiff)` factorisation, this is the input to -factorisation uniqueness for the `BC` marginal. -/ -theorem bcReorg_conjAlgEquiv_act_incl {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) - (h_AB : ΛAB ⊆ ΛABC) (x : N.algebra ΛA) : - (S.bcReorg h_A h_AB).toLinearEquiv.conjAlgEquiv ℂ (S.act ΛABC (N.incl (h_A.trans h_AB) x)) - = TensorProduct.map 1 (S.act ΛA x) := by - rw [bcReorg, LinearIsometryEquiv.toLinearEquiv_trans, LinearEquiv.conjAlgEquiv_trans, - S.wReorg_conjAlgEquiv_act_incl h_A h_AB, LinearIsometryEquiv.toLinearEquiv_trans, - LinearEquiv.conjAlgEquiv_trans, TensorProduct.toLinearEquiv_assocIsometry, - TensorProduct.assoc_conjAlgEquiv_map, TensorProduct.map_one, - TensorProduct.toLinearEquiv_commIsometry, TensorProduct.comm_conjAlgEquiv_map] - -/-- The direct unitary factorisation `ℋ ΛABC ≃ᵢ ℋ (ΛABC ∖ ΛA) ⊗ ℋ ΛA` for the `BC` marginal: factor -out `ΛA`'s complement directly (`decompᵢ (sdiff)`) and identify the complement-of-complement factor -with `ℋ ΛA` (`castIso`). This is the factorisation `e₁` whose partial trace is, by construction, the -`BC` marginal `restrict`; the traced-out factor is `ℋ ΛA`, matching `bcReorg`. -/ -noncomputable def bcDirect {ΛA ΛABC : Finset sites} (h : ΛA ⊆ ΛABC) : - ℋ ΛABC ≃ₗᵢ[ℂ] ℋ (ΛABC \ ΛA) ⊗[ℂ] ℋ ΛA := - (S.decompᵢ (Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC)).trans - (TensorProduct.congrIsometry (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛA))) - (castIso (ℋ := ℋ) h)) - -/-- **The `A`-action through the direct factorisation `bcDirect`** is the canonical ampliation on -the last factor: `bcDirect-conj (act ΛABC (incl x)) = 1 ⊗ act ΛA x`. Proved via `act_incl_compl` -(the complement acts canonically on its factor), `incl_cast`/`castEquiv_conjAlgEquiv_act` (the -complement-of-complement region is `ΛA`). With `bcReorg_conjAlgEquiv_act_incl` this shows both -factorisations implement the *same* `ΛA`-action, the hypothesis of factorisation uniqueness. -/ -theorem bcDirect_conjAlgEquiv_act_incl {ΛA ΛABC : Finset sites} (h : ΛA ⊆ ΛABC) (x : N.algebra ΛA) : - (S.bcDirect h).toLinearEquiv.conjAlgEquiv ℂ (S.act ΛABC (N.incl h x)) - = TensorProduct.map 1 (S.act ΛA x) := by - have hΛ : ΛABC \ (ΛABC \ ΛA) = ΛA := by - rw [Finset.sdiff_sdiff_self_left, Finset.inter_eq_right.mpr h] - rw [LocalNet.incl_cast hΛ.symm h Finset.sdiff_subset x, - S.act_incl_compl (Λ := ΛABC \ ΛA) Finset.sdiff_subset (hΛ.symm ▸ x)] - rw [bcDirect, LinearIsometryEquiv.toLinearEquiv_trans, LinearEquiv.conjAlgEquiv_trans, - S.decompᵢ_toLinearEquiv, LinearMap.coampliate, AlgEquiv.apply_symm_apply, - TensorProduct.toLinearEquiv_congrIsometry, TensorProduct.congr_conjAlgEquiv_map, - castIso, S.castEquiv_conjAlgEquiv_act, map_one] - -/-- **The nested tensor-product basis reassociates to the `bcReorg` factorisation.** The orthonormal -basis of `ℋ ΛABC` built by factoring `ΛA ⊆ ΛAB ⊆ ΛABC` and reindexing `((κA × κB) × κC)` to -`(κA × (κB × κC))` equals the basis pulled back along the `A`-first factorisation -`(decompᵢ h_AB) ≫ congr (decompᵢ h_A) 1 ≫ assoc`. This rewrites the density matrix `ρ_ABC` so that -its `A`-marginal (`ptLeft`) corresponds to the operator partial trace along `bcReorg`. -/ -theorem tensorBasis_reindex_prodAssoc {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) - (h_AB : ΛAB ⊆ ΛABC) {κA κB κC : Type*} [Fintype κA] [Fintype κB] [Fintype κC] - (bA : OrthonormalBasis κA ℂ (ℋ ΛA)) (bB : OrthonormalBasis κB ℂ (ℋ (ΛAB \ ΛA))) - (bC : OrthonormalBasis κC ℂ (ℋ (ΛABC \ ΛAB))) : - ((((bA.tensorProduct bB).map (S.decompᵢ h_A).symm).tensorProduct bC).map - (S.decompᵢ h_AB).symm).reindex (Equiv.prodAssoc κA κB κC) - = (bA.tensorProduct (bB.tensorProduct bC)).map - (((S.decompᵢ h_AB).trans (TensorProduct.congrIsometry (S.decompᵢ h_A) - (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).trans - (TensorProduct.assocIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)) (ℋ (ΛABC \ ΛAB)))).symm := by - apply DFunLike.ext - rintro ⟨a, b, c⟩ - simp only [OrthonormalBasis.reindex_apply, OrthonormalBasis.map_apply, - OrthonormalBasis.tensorProduct_apply, Equiv.prodAssoc_symm_apply, - LinearIsometryEquiv.symm_trans, LinearIsometryEquiv.trans_apply, - TensorProduct.assocIsometry_symm_apply, TensorProduct.congrIsometry_symm, - TensorProduct.congrIsometry_apply, TensorProduct.assoc_symm_tmul, TensorProduct.congr_tmul] - rfl - -/-- **The `ΛA`-marginal entropy via the factorised basis equals the representation-free marginal -entropy.** For a state `σ` on `ℋ ΛAB`, tracing out the `ΛA`-index (`ptLeft`) of its density matrix -in the orthonormal basis pulled back from `ℋ ΛA ⊗ ℋ (ΛAB ∖ ΛA)` gives the von Neumann entropy of the -abstract marginal `restrict (sdiff) σ`. Proved by factorisation uniqueness comparing the -complement factorisation `bcDirect h_A` (whose partial trace is `restrict`) with the canonical -`decompᵢ h_A ≫ comm`. This is the building block for the middle-region (`B`) marginal of SSA. -/ -theorem vonNeumannEntropy_ptLeft_decompBasis [∀ Λ, Nontrivial (ℋ Λ)] - {ΛA ΛAB : Finset sites} (h_A : ΛA ⊆ ΛAB) {κA κB : Type*} [Fintype κA] [DecidableEq κA] - [Fintype κB] [DecidableEq κB] (bA : OrthonormalBasis κA ℂ (ℋ ΛA)) - (bB : OrthonormalBasis κB ℂ (ℋ (ΛAB \ ΛA))) {σ : N.algebra ΛAB} (hσ : S.IsDensity σ) : - Matrix.vonNeumannEntropy - (S.toDensityMatrixBasis ((bA.tensorProduct bB).map (S.decompᵢ h_A).symm) hσ).ptLeft - = S.entropy (S.restrict (Finset.sdiff_subset : ΛAB \ ΛA ⊆ ΛAB) σ) := by - have hcommB : ∀ f : Module.End ℂ (ℋ ΛA), - ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap - ∘ₗ TensorProduct.map LinearMap.id f - = TensorProduct.map LinearMap.id f - ∘ₗ ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap := by - intro f - obtain ⟨x, rfl⟩ : ∃ x, S.act ΛA x = f := ⟨(S.act ΛA).symm f, by simp⟩ - have h1 := S.bcDirect_conjAlgEquiv_act_incl h_A x - have h2 : ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)))).toLinearEquiv.conjAlgEquiv ℂ - (S.act ΛAB (N.incl h_A x)) = TensorProduct.map 1 (S.act ΛA x) := by - rw [S.act_incl h_A, LinearIsometryEquiv.toLinearEquiv_trans, LinearEquiv.conjAlgEquiv_trans, - LinearMap.ampliate, S.decompᵢ_toLinearEquiv, AlgEquiv.apply_symm_apply, - TensorProduct.toLinearEquiv_commIsometry, TensorProduct.comm_conjAlgEquiv_map] - simp only [← Module.End.one_eq_id] - have hΨM : ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.conjAlgEquiv ℂ - (TensorProduct.map 1 (S.act ΛA x)) = TensorProduct.map 1 (S.act ΛA x) := by - conv_lhs => rw [← h1] - rw [show ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv - = (S.bcDirect h_A).toLinearEquiv.symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)))).toLinearEquiv from rfl, - LinearEquiv.conjAlgEquiv_trans, ← LinearEquiv.symm_conjAlgEquiv, AlgEquiv.symm_apply_apply, h2] - rw [LinearEquiv.conjAlgEquiv_apply] at hΨM - calc ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap - ∘ₗ TensorProduct.map 1 (S.act ΛA x) - = (((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap - ∘ₗ TensorProduct.map 1 (S.act ΛA x) - ∘ₗ ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) - (ℋ (ΛAB \ ΛA))))).toLinearEquiv.symm.toLinearMap) - ∘ₗ ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap := by - rw [LinearMap.comp_assoc, LinearMap.comp_assoc, ← LinearMap.comp_assoc _ _ - ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap, - LinearEquiv.comp_coe, LinearEquiv.self_trans_symm, LinearEquiv.refl_toLinearMap, - LinearMap.comp_id] - _ = TensorProduct.map 1 (S.act ΛA x) - ∘ₗ ((S.bcDirect h_A).symm.trans - ((S.decompᵢ h_A).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA))))).toLinearEquiv.toLinearMap := by - rw [hΨM] - obtain ⟨W, hW⟩ := factorization_uniqueness (S.bcDirect h_A) - ((S.decompᵢ h_A).trans (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)))) hcommB (S.act ΛAB σ) - have hptdB : LinearMap.partialTrace (S.bcDirect h_A).toLinearEquiv (S.act ΛAB σ) - = S.act (ΛAB \ ΛA) (S.restrict Finset.sdiff_subset σ) := by - rw [LocalNet.Split.bcDirect, LinearIsometryEquiv.toLinearEquiv_trans, S.decompᵢ_toLinearEquiv, - TensorProduct.toLinearEquiv_congrIsometry, - show (LinearIsometryEquiv.refl ℂ (ℋ (ΛAB \ ΛA))).toLinearEquiv - = LinearEquiv.refl ℂ (ℋ (ΛAB \ ΛA)) from rfl, - LinearMap.partialTrace_congr_right_id, S.restrict_apply, AlgEquiv.apply_symm_apply] - have hbmap : (bB.map W.symm).map W = bB := by - apply DFunLike.ext; intro i; simp [OrthonormalBasis.map_apply] - rw [show (S.toDensityMatrixBasis ((bA.tensorProduct bB).map (S.decompᵢ h_A).symm) hσ).ptLeft - = S.toDensityMatrixBasis (bB.map W.symm) (S.restrict_isDensity Finset.sdiff_subset hσ) from ?_, - S.vonNeumannEntropy_toDensityMatrixBasis] - apply DensityMatrix.ext - rw [DensityMatrix.ptLeft_toMatrix, S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, - S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, LinearMap.traceLeft_toMatrixOrthonormal, - hW] - conv_lhs => rw [← hbmap] - rw [toMatrixOrthonormal_conj_map, hptdB] - -/-- **Strong subadditivity of the von Neumann entropy on an abstract split net.** For a faithful -operator-algebraic split net `LocalNet.Split` over finite-dimensional action spaces, and a state -`ρ` on a region `ΛABC` with a nested decomposition `ΛA ⊆ ΛAB ⊆ ΛABC`, the entropies of the marginals -obey -`S(ABC) + S(B) ≤ S(AB) + S(BC)`, -where `B = ΛAB ∖ ΛA`, `BC = ΛABC ∖ ΛA`, and each marginal is the representation-free `restrict`. -This is the AQFT form of strong subadditivity: it is assembled entirely on the abstract net (no -matrix model), by reading each marginal in a tensor-factorised orthonormal basis, using factorisation -uniqueness (the partial trace depends only on the subsystem, not the chosen factorisation of its -complement — the tensor commutant theorem plus the spatial split data `act_incl`/`act_incl_compl`), -and transporting the analytic core `DensityMatrix.vonNeumannEntropy_SSA_product` to the net. -/ -theorem vonNeumannEntropy_SSA [∀ Λ, Nontrivial (ℋ Λ)] - {ΛA ΛAB ΛABC : Finset sites} (h_A : ΛA ⊆ ΛAB) (h_AB : ΛAB ⊆ ΛABC) - {ρ : N.algebra ΛABC} (hρ : S.IsDensity ρ) : - S.entropy ρ + S.entropy (S.restrict ((Finset.sdiff_subset : ΛAB \ ΛA ⊆ ΛAB).trans h_AB) ρ) - ≤ S.entropy (S.restrict h_AB ρ) - + S.entropy (S.restrict (Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC) ρ) := by - haveI : Nonempty (Fin (Module.finrank ℂ (ℋ ΛA))) := ⟨⟨0, Module.finrank_pos⟩⟩ - haveI : Nonempty (Fin (Module.finrank ℂ (ℋ (ΛAB \ ΛA)))) := ⟨⟨0, Module.finrank_pos⟩⟩ - haveI : Nonempty (Fin (Module.finrank ℂ (ℋ (ΛABC \ ΛAB)))) := ⟨⟨0, Module.finrank_pos⟩⟩ - set bA := stdOrthonormalBasis ℂ (ℋ ΛA) with hbA - set bB := stdOrthonormalBasis ℂ (ℋ (ΛAB \ ΛA)) with hbB - set bC := stdOrthonormalBasis ℂ (ℋ (ΛABC \ ΛAB)) with hbC - set ρ_ABC := S.toDensityMatrixBasis - (((((bA.tensorProduct bB).map (S.decompᵢ h_A).symm).tensorProduct bC).map - (S.decompᵢ h_AB).symm).reindex (Equiv.prodAssoc _ _ _)) hρ with hρ_ABC - have key := DensityMatrix.vonNeumannEntropy_SSA_product ρ_ABC - ((ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight) ρ_ABC.ptLeft ρ_ABC.ptLeft.ptRight rfl rfl rfl - have hABC : Matrix.vonNeumannEntropy ρ_ABC = S.entropy ρ := by - rw [hρ_ABC, S.vonNeumannEntropy_toDensityMatrixBasis] - have hmar : (ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight - = S.toDensityMatrixBasis ((bA.tensorProduct bB).map (S.decompᵢ h_A).symm) - (S.restrict_isDensity h_AB hρ) := by - rw [hρ_ABC, S.toDensityMatrixBasis_reindex_mapEquiv] - apply DensityMatrix.ext - rw [DensityMatrix.ptRight_toMatrix, S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, - S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, LinearMap.traceRight_toMatrixOrthonormal] - congr 1 - rw [S.restrict_apply, AlgEquiv.apply_symm_apply, S.decompᵢ_toLinearEquiv] - have hAB : Matrix.vonNeumannEntropy (ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight - = S.entropy (S.restrict h_AB ρ) := by rw [hmar, S.vonNeumannEntropy_toDensityMatrixBasis] - have hcomm : ∀ f : Module.End ℂ (ℋ ΛA), - ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap - ∘ₗ TensorProduct.map LinearMap.id f - = TensorProduct.map LinearMap.id f - ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans - (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap := by - intro f - obtain ⟨x, rfl⟩ : ∃ x, S.act ΛA x = f := ⟨(S.act ΛA).symm f, by simp⟩ - have h1 := S.bcDirect_conjAlgEquiv_act_incl (h_A.trans h_AB) x - have h2 := S.bcReorg_conjAlgEquiv_act_incl h_A h_AB x - simp only [← Module.End.one_eq_id] - have hΨM : ((S.bcDirect (h_A.trans h_AB)).symm.trans - (S.bcReorg h_A h_AB)).toLinearEquiv.conjAlgEquiv ℂ - (TensorProduct.map 1 (S.act ΛA x)) = TensorProduct.map 1 (S.act ΛA x) := by - conv_lhs => rw [← h1] - rw [show ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv - = (S.bcDirect (h_A.trans h_AB)).toLinearEquiv.symm.trans (S.bcReorg h_A h_AB).toLinearEquiv - from rfl, LinearEquiv.conjAlgEquiv_trans, ← LinearEquiv.symm_conjAlgEquiv, - AlgEquiv.symm_apply_apply, h2] - rw [LinearEquiv.conjAlgEquiv_apply] at hΨM - calc ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap - ∘ₗ TensorProduct.map 1 (S.act ΛA x) - = (((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap - ∘ₗ TensorProduct.map 1 (S.act ΛA x) - ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans - (S.bcReorg h_A h_AB)).toLinearEquiv.symm.toLinearMap) - ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans - (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap := by - rw [LinearMap.comp_assoc, LinearMap.comp_assoc, ← LinearMap.comp_assoc _ _ - ((S.bcDirect (h_A.trans h_AB)).symm.trans (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap, - LinearEquiv.comp_coe, LinearEquiv.self_trans_symm, LinearEquiv.refl_toLinearMap, - LinearMap.comp_id] - _ = TensorProduct.map 1 (S.act ΛA x) - ∘ₗ ((S.bcDirect (h_A.trans h_AB)).symm.trans - (S.bcReorg h_A h_AB)).toLinearEquiv.toLinearMap := by - rw [hΨM] - have hBC : Matrix.vonNeumannEntropy ρ_ABC.ptLeft - = S.entropy (S.restrict (Finset.sdiff_subset : ΛABC \ ΛA ⊆ ΛABC) ρ) := by - rw [hρ_ABC] - obtain ⟨V, hV⟩ := factorization_uniqueness (S.bcDirect (h_A.trans h_AB)) (S.bcReorg h_A h_AB) - hcomm (S.act ΛABC ρ) - have hptd : LinearMap.partialTrace (S.bcDirect (h_A.trans h_AB)).toLinearEquiv (S.act ΛABC ρ) - = S.act (ΛABC \ ΛA) (S.restrict Finset.sdiff_subset ρ) := by - rw [LocalNet.Split.bcDirect, LinearIsometryEquiv.toLinearEquiv_trans, S.decompᵢ_toLinearEquiv, - TensorProduct.toLinearEquiv_congrIsometry, - show (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛA))).toLinearEquiv - = LinearEquiv.refl ℂ (ℋ (ΛABC \ ΛA)) from rfl, - LinearMap.partialTrace_congr_right_id, S.restrict_apply, AlgEquiv.apply_symm_apply] - have hbmap : ((bB.tensorProduct bC).map V.symm).map V = bB.tensorProduct bC := by - apply DFunLike.ext; intro i; simp [OrthonormalBasis.map_apply] - rw [show (S.toDensityMatrixBasis _ hρ).ptLeft = S.toDensityMatrixBasis - ((bB.tensorProduct bC).map V.symm) (S.restrict_isDensity Finset.sdiff_subset hρ) from ?_, - S.vonNeumannEntropy_toDensityMatrixBasis] - apply DensityMatrix.ext - rw [DensityMatrix.ptLeft_toMatrix, S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, - S.toDensityMatrixBasis_toMatrix, S.toMatrixBasis_apply, - S.tensorBasis_reindex_prodAssoc h_A h_AB bA bB bC, LinearMap.traceLeft_toMatrixOrthonormal, - show (((S.decompᵢ h_AB).trans (TensorProduct.congrIsometry (S.decompᵢ h_A) - (LinearIsometryEquiv.refl ℂ (ℋ (ΛABC \ ΛAB))))).trans - (TensorProduct.assocIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA)) (ℋ (ΛABC \ ΛAB)))).trans - (TensorProduct.commIsometry ℂ (ℋ ΛA) (ℋ (ΛAB \ ΛA) ⊗[ℂ] ℋ (ΛABC \ ΛAB))) - = S.bcReorg h_A h_AB from by rw [LocalNet.Split.bcReorg, LinearIsometryEquiv.trans_assoc], - hV] - conv_lhs => rw [← hbmap] - rw [toMatrixOrthonormal_conj_map, hptd] - have hB : Matrix.vonNeumannEntropy ρ_ABC.ptLeft.ptRight - = S.entropy (S.restrict ((Finset.sdiff_subset : ΛAB \ ΛA ⊆ ΛAB).trans h_AB) ρ) := by - rw [show ρ_ABC.ptLeft.ptRight = (ρ_ABC.mapEquiv (Equiv.prodAssoc _ _ _)).ptRight.ptLeft from ?_, - hmar, S.vonNeumannEntropy_ptLeft_decompBasis h_A bA bB (S.restrict_isDensity h_AB hρ), - S.restrict_restrict] - apply DensityMatrix.ext - rw [DensityMatrix.ptRight_toMatrix, DensityMatrix.ptLeft_toMatrix, DensityMatrix.ptLeft_toMatrix, - DensityMatrix.ptRight_toMatrix, DensityMatrix.mapEquiv_toMatrix] - exact (Matrix.traceLeft_traceRight_submatrix_prodAssoc _).symm - rw [hABC, hB, hAB, hBC] at key - exact key - -end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitTrace.lean b/QuantumSystem/Analysis/Entropy/SplitTrace.lean deleted file mode 100644 index b886047..0000000 --- a/QuantumSystem/Analysis/Entropy/SplitTrace.lean +++ /dev/null @@ -1,124 +0,0 @@ -module - -public import Mathlib.Analysis.InnerProductSpace.Positive -public import QuantumSystem.Algebra.LocalNet.TensorDecomposition - -/-! -# Trace on a split net and its preservation under the marginal - -The first brick of the **representation-free quantum-information layer** built on the split -property (`LocalNet.Split`). The split structure identifies each local algebra with the type I -factor `End ℂ (ℋ Λ)` of operators on a finite-dimensional action space, which carries the -canonical trace `LinearMap.trace`. This file: - -* records the general fact that the partial trace along a tensor decomposition preserves the - trace (`LinearMap.trace_partialTrace`, via the operator factorisation `partialTraceRight`); -* defines the trace `LocalNet.Split.trace` on the local algebra of a split net; -* proves it is preserved by the marginal `LocalNet.Split.restrict` (`trace_restrict`). - -These are the building blocks for density operators, von Neumann entropy and strong -subadditivity stated directly on the abstract split net, with no matrix index substrate. --/ - -@[expose] public section - -open scoped TensorProduct - -namespace TensorProduct - -variable {R : Type*} [CommRing R] {M N : Type*} - [AddCommGroup M] [Module R M] [Module.Finite R M] [Module.Free R M] - [AddCommGroup N] [Module R N] [Module.Finite R N] [Module.Free R N] - -/-- The partial trace over the second factor relates to the full trace through the operator -tensor decomposition: `trace_M (partialTraceRight S) = trace_{M ⊗ N} (endTensorEndAlgEquiv S)`. -On a pure operator tensor both sides are `trace Y * trace Z`. -/ -theorem trace_partialTraceRight (S : Module.End R M ⊗[R] Module.End R N) : - LinearMap.trace R M (partialTraceRight S) = - LinearMap.trace R (M ⊗[R] N) (endTensorEndAlgEquiv S) := by - induction S using TensorProduct.induction_on with - | zero => simp - | tmul Y Z => - rw [partialTraceRight_tmul, endTensorEndAlgEquiv_tmul, LinearMap.trace_tensorProduct', - map_smul, smul_eq_mul] - ring - | add S₁ S₂ h₁ h₂ => simp only [map_add, h₁, h₂] - -end TensorProduct - -namespace LinearMap - -open scoped TensorProduct - -variable {𝕜 ℋ A B : Type*} [Field 𝕜] - [AddCommGroup ℋ] [Module 𝕜 ℋ] - [AddCommGroup A] [Module 𝕜 A] [Module.Finite 𝕜 A] [Module.Free 𝕜 A] - [AddCommGroup B] [Module 𝕜 B] [Module.Finite 𝕜 B] [Module.Free 𝕜 B] - -/-- **The partial trace preserves the trace**: tracing out the second factor of a decomposition -`e : ℋ ≃ₗ A ⊗ B` and then taking the trace over `A` recovers the trace over `ℋ`. -/ -theorem trace_partialTrace (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (ρ : Module.End 𝕜 ℋ) : - LinearMap.trace 𝕜 A (LinearMap.partialTrace e ρ) = LinearMap.trace 𝕜 ℋ ρ := by - rw [LinearMap.partialTrace_apply, TensorProduct.trace_partialTraceRight, - AlgEquiv.apply_symm_apply] - exact LinearMap.trace_conj' ρ e - -end LinearMap - -namespace LocalNet.Split - -variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] - (S : Split N ℋ) - -/-- The **trace** on a local algebra of a split net: the canonical operator trace on the action -space `ℋ Λ`, transported along the type I identification `act Λ`. -/ -noncomputable def trace (Λ : Finset sites) : N.algebra Λ →ₗ[ℂ] ℂ := - LinearMap.trace ℂ (ℋ Λ) ∘ₗ (S.act Λ).toLinearMap - -theorem trace_apply (Λ : Finset sites) (X : N.algebra Λ) : - S.trace Λ X = LinearMap.trace ℂ (ℋ Λ) (S.act Λ X) := - rfl - -/-- **The marginal preserves the trace**: `trace (restrict h M) = trace M`. The split partial -trace is trace-preserving, the property that makes it the Schrödinger-picture dual of the -isotony embedding. -/ -theorem trace_restrict {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (M : N.algebra Λ') : - S.trace Λ (S.restrict h M) = S.trace Λ' M := by - rw [trace_apply, trace_apply, restrict_apply, AlgEquiv.apply_symm_apply, - LinearMap.trace_partialTrace] - -/-- The trace is **cyclic**: `trace (A * B) = trace (B * A)` (it is the operator trace through the -type I identification `act`, transported from `LinearMap.trace_mul_comm`). -/ -theorem trace_mul_comm {Λ : Finset sites} (A B : N.algebra Λ) : - S.trace Λ (A * B) = S.trace Λ (B * A) := by - rw [trace_apply, trace_apply, map_mul (S.act Λ), map_mul (S.act Λ), LinearMap.trace_mul_comm] - -/-- **Heisenberg / trace duality** between the isotony embedding `incl` (Heisenberg picture) and the -marginal `restrict` (Schrödinger picture): `trace (ρ · incl h X) = trace (restrict h ρ · X)`. The -marginal `restrict h` is the predual of the inclusion `incl h`. Derived purely from -`restrict_incl_mul` and `trace_restrict` (no tensor data), so it holds for the abstract net. -/ -theorem trace_mul_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (ρ : N.algebra Λ') (X : N.algebra Λ) : - S.trace Λ' (ρ * N.incl h X) = S.trace Λ (S.restrict h ρ * X) := by - have key := congrArg (S.trace Λ) (S.restrict_incl_mul h X ρ) - rw [S.trace_restrict h (N.incl h X * ρ), S.trace_mul_comm (N.incl h X) ρ, - S.trace_mul_comm X (S.restrict h ρ)] at key - exact key - -/-- A **density operator** of the split net at region `Λ`: an element of the local algebra whose -operator image `act Λ ρ` is positive (the Loewner order on `End ℂ (ℋ Λ)`) and whose trace is one. -Since `act` is a `*`-isomorphism (`act_star`), positivity of `act Λ ρ` is the genuine C⋆-positivity -of `ρ`; this is the representation-free analogue of a density matrix, stated with no index basis. -/ -def IsDensity {Λ : Finset sites} (ρ : N.algebra Λ) : Prop := - 0 ≤ S.act Λ ρ ∧ S.trace Λ ρ = 1 - -theorem IsDensity.trace_eq_one {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - S.trace Λ ρ = 1 := - hρ.2 - -theorem IsDensity.nonneg {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - 0 ≤ S.act Λ ρ := - hρ.1 - -end LocalNet.Split diff --git a/QuantumSystem/Analysis/Entropy/SplitTransport.lean b/QuantumSystem/Analysis/Entropy/SplitTransport.lean deleted file mode 100644 index e0c5a68..0000000 --- a/QuantumSystem/Analysis/Entropy/SplitTransport.lean +++ /dev/null @@ -1,374 +0,0 @@ -module - -public import Mathlib.Analysis.InnerProductSpace.Trace -public import QuantumSystem.Analysis.Entropy.SplitEntropy -public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy - -/-! -# Matrix transport for a split net - -The **transport bridge** that carries the representation-free split-net quantum information back to -the matrix theory: for a region `Λ`, an orthonormal basis of the action space `ℋ Λ` realises the -local algebra as a matrix algebra, - - `Split.toMatrix Λ : N.algebra Λ ≃⋆ₐ[ℂ] Matrix (Fin (finrank ℂ (ℋ Λ))) … ℂ`, - -a genuine `*`-isomorphism (`act` is a `*`-iso by `act_star`, and `LinearMap.toMatrixOrthonormal` is -a `*`-iso for an orthonormal basis). Through it, positivity, trace, density and von Neumann entropy -on the split net coincide with their matrix counterparts, so the deep matrix results -(non-negativity, strong subadditivity, …) transport to the abstract net. --/ - -@[expose] public section - -open scoped Matrix ComplexOrder TensorProduct - -namespace TensorProduct - -variable {ι A B : Type*} [Fintype ι] - [NormedAddCommGroup A] [InnerProductSpace ℂ A] [FiniteDimensional ℂ A] - [NormedAddCommGroup B] [InnerProductSpace ℂ B] [FiniteDimensional ℂ B] - -/-- The diagonal quadratic form of the partial trace over the second factor, expanded over an -orthonormal basis `w` of `B`: `⟪partialTraceRight S a, a⟫ = ∑ₖ ⟪(S as operator) (a ⊗ wₖ), a ⊗ wₖ⟫`. -This is the bridge that makes `partialTraceRight` manifestly positivity-preserving. -/ -lemma inner_partialTraceRight (w : OrthonormalBasis ι ℂ B) - (S : Module.End ℂ A ⊗[ℂ] Module.End ℂ B) (a a' : A) : - inner ℂ (partialTraceRight S a') a - = ∑ k, inner ℂ (endTensorEndAlgEquiv S (a' ⊗ₜ[ℂ] w k)) (a ⊗ₜ[ℂ] w k) := by - induction S using TensorProduct.induction_on with - | zero => simp - | tmul Y Z => - rw [partialTraceRight_tmul, endTensorEndAlgEquiv_tmul, LinearMap.smul_apply, inner_smul_left] - simp only [TensorProduct.map_tmul, TensorProduct.inner_tmul, ← Finset.mul_sum] - rw [mul_comm] - congr 1 - rw [LinearMap.trace_eq_sum_inner Z w, starRingEnd_apply, star_sum] - refine Finset.sum_congr rfl fun k _ => ?_ - rw [← starRingEnd_apply, inner_conj_symm] - | add S₁ S₂ h₁ h₂ => - simp only [map_add, LinearMap.add_apply, inner_add_left, h₁, h₂, Finset.sum_add_distrib] - -end TensorProduct - -namespace LinearMap - -open scoped ComplexOrder - -variable {ℋ A B : Type*} - [NormedAddCommGroup ℋ] [InnerProductSpace ℂ ℋ] [FiniteDimensional ℂ ℋ] - [NormedAddCommGroup A] [InnerProductSpace ℂ A] [FiniteDimensional ℂ A] - [NormedAddCommGroup B] [InnerProductSpace ℂ B] [FiniteDimensional ℂ B] - -omit [FiniteDimensional ℂ ℋ] in -/-- **The partial trace preserves positivity.** Along a *unitary* tensor factorisation -`e : ℋ ≃ₗᵢ A ⊗ B`, the partial trace of a positive operator is positive — the partial trace is a -quantum channel. The quadratic form expands (`TensorProduct.inner_partialTraceRight`) into a sum of -the quadratic form of `T` at the unit-vectors `e.symm (a ⊗ wₖ)`, each non-negative. -/ -theorem isPositive_partialTrace (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) {T : Module.End ℂ ℋ} - (hT : T.IsPositive) : (LinearMap.partialTrace e.toLinearEquiv T).IsPositive := by - rw [LinearMap.isPositive_iff_complex] - intro a - set w := stdOrthonormalBasis ℂ B with hw - have key : inner ℂ (LinearMap.partialTrace e.toLinearEquiv T a) a = - ((∑ k, RCLike.re (inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k))) : ℝ) : ℂ) := by - rw [LinearMap.partialTrace_apply, TensorProduct.inner_partialTraceRight w, - AlgEquiv.apply_symm_apply, Complex.ofReal_sum] - refine Finset.sum_congr rfl fun k _ => ?_ - rw [LinearEquiv.conjAlgEquiv_apply_apply, - show inner ℂ (e.toLinearEquiv (T (e.toLinearEquiv.symm (a ⊗ₜ[ℂ] w k)))) (a ⊗ₜ[ℂ] w k) - = inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k)) from by - change inner ℂ (e (T (e.symm (a ⊗ₜ[ℂ] w k)))) (a ⊗ₜ[ℂ] w k) - = inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k)) - rw [← e.inner_map_map (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k)), - e.apply_symm_apply], - (((LinearMap.isPositive_iff_complex T).mp hT _).1)] - rw [key] - have hre : RCLike.re ((∑ k, RCLike.re (inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) - (e.symm (a ⊗ₜ[ℂ] w k))) : ℝ) : ℂ) - = ∑ k, RCLike.re (inner ℂ (T (e.symm (a ⊗ₜ[ℂ] w k))) (e.symm (a ⊗ₜ[ℂ] w k))) := - RCLike.ofReal_re _ - rw [hre] - exact ⟨rfl, Finset.sum_nonneg fun k _ => ((LinearMap.isPositive_iff_complex T).mp hT _).2⟩ - -/-- The **Kraus operators** `Vⱼ : A →ₗ ℋ`, `a ↦ e.symm (a ⊗ wⱼ)`, of the partial trace along a -unitary factorisation `e : ℋ ≃ₗᵢ A ⊗ B`, where `w` is the standard orthonormal basis of `B`. -/ -noncomputable def ptKraus (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) (j : Fin (Module.finrank ℂ B)) : - A →ₗ[ℂ] ℋ := - e.symm.toLinearEquiv.toLinearMap ∘ₗ (TensorProduct.mk ℂ A B).flip (stdOrthonormalBasis ℂ B j) - -omit [FiniteDimensional ℂ ℋ] [FiniteDimensional ℂ A] in -@[simp] theorem ptKraus_apply (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) (j : Fin (Module.finrank ℂ B)) (a : A) : - ptKraus e j a = e.symm (a ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j) := - rfl - -/-- **Kraus form of the partial trace**: along a unitary factorisation `e`, the partial trace is a -sum of compressions `Tr_B T = ∑ⱼ Vⱼ⋆ T Vⱼ`. This is the Kraus/Stinespring decomposition exhibiting -the partial trace as a completely positive map. -/ -theorem partialTrace_eq_sum_kraus (e : ℋ ≃ₗᵢ[ℂ] (A ⊗[ℂ] B)) (T : Module.End ℂ ℋ) : - LinearMap.partialTrace e.toLinearEquiv T - = ∑ j, LinearMap.adjoint (ptKraus e j) ∘ₗ T ∘ₗ ptKraus e j := by - ext a' - refine ext_inner_right ℂ fun a => ?_ - rw [LinearMap.partialTrace_apply, TensorProduct.inner_partialTraceRight (stdOrthonormalBasis ℂ B), - AlgEquiv.apply_symm_apply, LinearMap.sum_apply, sum_inner] - refine Finset.sum_congr rfl fun j _ => ?_ - rw [LinearMap.comp_apply, LinearMap.comp_apply, LinearMap.adjoint_inner_left, ptKraus_apply, - ptKraus_apply, LinearEquiv.conjAlgEquiv_apply_apply] - rw [show e.toLinearEquiv (T (e.toLinearEquiv.symm (a' ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j))) - = e (T (e.symm (a' ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j))) from rfl, - ← e.inner_map_map (T (e.symm (a' ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j))) - (e.symm (a ⊗ₜ[ℂ] stdOrthonormalBasis ℂ B j)), e.apply_symm_apply] - -omit [FiniteDimensional ℂ A] [FiniteDimensional ℂ B] in -/-- The matrix trace of the matrix of `T` in an orthonormal basis `b` is the operator trace of `T` -(independent of the choice of orthonormal basis). -/ -theorem trace_toMatrixOrthonormal {ι : Type*} [Fintype ι] [DecidableEq ι] - (b : OrthonormalBasis ι ℂ ℋ) (T : Module.End ℂ ℋ) : - (LinearMap.toMatrixOrthonormal b T).trace = LinearMap.trace ℂ ℋ T := by - rw [LinearMap.trace_eq_sum_inner T b, Matrix.trace] - refine Finset.sum_congr rfl fun i _ => ?_ - rw [Matrix.diag_apply, LinearMap.toMatrixOrthonormal_apply_apply] - -end LinearMap - -namespace LocalNet.Split - -variable {sites : Type*} [DecidableEq sites] {N : LocalNet sites} {ℋ : Finset sites → Type*} - [∀ Λ, NormedAddCommGroup (ℋ Λ)] [∀ Λ, InnerProductSpace ℂ (ℋ Λ)] - [∀ Λ, FiniteDimensional ℂ (ℋ Λ)] - (S : Split N ℋ) - -/-- The type I identification `act Λ` packaged as a `*`-isomorphism, using `act_star`. -/ -noncomputable def actₛ (Λ : Finset sites) : N.algebra Λ ≃⋆ₐ[ℂ] Module.End ℂ (ℋ Λ) := - { S.act Λ with map_smul' := map_smul (S.act Λ), map_star' := S.act_star } - -@[simp] theorem actₛ_apply (Λ : Finset sites) (x : N.algebra Λ) : - S.actₛ Λ x = S.act Λ x := - rfl - -/-- The **matrix representation** of the local algebra at `Λ`, a `*`-isomorphism onto the matrix -algebra on the index `Fin (finrank ℂ (ℋ Λ))` obtained from the standard orthonormal basis of the -action space. The composite of the type I identification `actₛ` with the orthonormal matrix -representation `LinearMap.toMatrixOrthonormal`. -/ -noncomputable def toMatrix (Λ : Finset sites) : - N.algebra Λ ≃⋆ₐ[ℂ] Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ))) ℂ := - (S.actₛ Λ).trans (LinearMap.toMatrixOrthonormal (stdOrthonormalBasis ℂ (ℋ Λ))) - -theorem toMatrix_apply (Λ : Finset sites) (x : N.algebra Λ) : - S.toMatrix Λ x = - LinearMap.toMatrixOrthonormal (stdOrthonormalBasis ℂ (ℋ Λ)) (S.act Λ x) := - rfl - -/-- **Trace transport**: the split trace coincides with the matrix trace of the transported -operator. -/ -theorem trace_eq_matrixTrace (Λ : Finset sites) (ρ : N.algebra Λ) : - S.trace Λ ρ = (S.toMatrix Λ ρ).trace := by - rw [trace_apply, LinearMap.trace_eq_sum_inner (S.act Λ ρ) (stdOrthonormalBasis ℂ (ℋ Λ)), - Matrix.trace] - refine Finset.sum_congr rfl fun i _ => ?_ - rw [Matrix.diag_apply, toMatrix_apply, LinearMap.toMatrixOrthonormal_apply_apply] - -/-- **Positivity transport**: the transported matrix is positive semidefinite iff the operator -`act Λ ρ` is positive (Loewner). This is `LinearMap.posSemidef_toMatrix_iff` for the orthonormal -basis, through `act`. -/ -theorem posSemidef_toMatrix_iff (Λ : Finset sites) (ρ : N.algebra Λ) : - (S.toMatrix Λ ρ).PosSemidef ↔ 0 ≤ S.act Λ ρ := by - rw [toMatrix_apply, LinearMap.nonneg_iff_isPositive] - exact LinearMap.posSemidef_toMatrix_iff (stdOrthonormalBasis ℂ (ℋ Λ)) - -/-- **Density transport**: a state of the split net (`IsDensity`) maps to a genuine density matrix -under the matrix representation. This is the bridge object through which the matrix quantum -information (von Neumann entropy, strong subadditivity, …) is pulled back to the split net. -/ -noncomputable def toDensityMatrix {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - DensityMatrix (Fin (Module.finrank ℂ (ℋ Λ))) where - toMatrix := S.toMatrix Λ ρ - posSemidef := (S.posSemidef_toMatrix_iff Λ ρ).mpr hρ.nonneg - trace_eq_one := by rw [← S.trace_eq_matrixTrace]; exact hρ.trace_eq_one - -@[simp] theorem toDensityMatrix_toMatrix {Λ : Finset sites} {ρ : N.algebra Λ} - (hρ : S.IsDensity ρ) : (S.toDensityMatrix hρ).toMatrix = S.toMatrix Λ ρ := - rfl - -include S in -/-- The local algebra of a split net is finite-dimensional (it is `*`-isomorphic to the operator -algebra on the finite-dimensional action space). -/ -theorem finiteDimensional_algebra (Λ : Finset sites) : FiniteDimensional ℂ (N.algebra Λ) := - (S.act Λ).symm.toLinearEquiv.finiteDimensional - -/-- The matrix representation `Split.toMatrix Λ` is continuous (a linear map of -finite-dimensional spaces). -/ -theorem continuous_toMatrix (Λ : Finset sites) : Continuous (S.toMatrix Λ) := by - haveI := S.finiteDimensional_algebra Λ - let L : N.algebra Λ →ₗ[ℂ] - Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ))) ℂ := - { toFun := S.toMatrix Λ, map_add' := map_add _, map_smul' := map_smul _ } - exact L.continuous_of_finiteDimensional - -/-- A state of the split net is self-adjoint (positive operators are self-adjoint, and `act` is a -`*`-isomorphism). -/ -theorem isSelfAdjoint_of_isDensity {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - IsSelfAdjoint ρ := by - have h1 : IsSelfAdjoint (S.act Λ ρ) := - ((LinearMap.nonneg_iff_isPositive _).mp hρ.nonneg).isSelfAdjoint - apply (S.act Λ).injective - rw [S.act_star] - exact h1 - -/-- **Entropy transport**: the split-net von Neumann entropy of a state coincides with the matrix -von Neumann entropy of its transported density matrix. The continuous functional calculus commutes -with the `*`-isomorphism `toMatrix` (`StarAlgHomClass.map_cfc`). -/ -theorem entropy_eq_vonNeumannEntropy {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - S.entropy ρ = Matrix.vonNeumannEntropy (S.toDensityMatrix hρ) := by - haveI : IsScalarTower ℝ ℂ (N.algebra Λ) := IsScalarTower.complexToReal - have hsa : IsSelfAdjoint ρ := S.isSelfAdjoint_of_isDensity hρ - have hsa' : IsSelfAdjoint (S.toMatrix Λ ρ) := - show star (S.toMatrix Λ ρ) = S.toMatrix Λ ρ by rw [← map_star, hsa] - rw [entropy_def, trace_eq_matrixTrace, Matrix.vonNeumannEntropy_eq_cfc_re, - toDensityMatrix_toMatrix, - StarAlgHomClass.map_cfc (S.toMatrix Λ) Real.negMulLog ρ - Real.continuous_negMulLog.continuousOn (S.continuous_toMatrix Λ) hsa hsa'] - -/-- **Von Neumann entropy of a split-net state is non-negative.** Transported from the matrix -result `Matrix.vonNeumannEntropy_nonneg`. -/ -theorem entropy_nonneg {Λ : Finset sites} {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - 0 ≤ S.entropy ρ := by - rw [S.entropy_eq_vonNeumannEntropy hρ] - exact Matrix.vonNeumannEntropy_nonneg _ - -/-- The **matrix representation in an arbitrary orthonormal basis** `b` of the action space, a -`*`-isomorphism `N.algebra Λ ≃⋆ₐ Matrix ι`. The von Neumann entropy of the resulting density matrix -is independent of `b` (`vonNeumannEntropy_toDensityMatrixBasis`); this is the freedom of orthonormal -basis used to transport tensor-factorised marginals. -/ -noncomputable def toMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] - (b : OrthonormalBasis ι ℂ (ℋ Λ)) : N.algebra Λ ≃⋆ₐ[ℂ] Matrix ι ι ℂ := - (S.actₛ Λ).trans (LinearMap.toMatrixOrthonormal b) - -theorem toMatrixBasis_apply {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] - (b : OrthonormalBasis ι ℂ (ℋ Λ)) (x : N.algebra Λ) : - S.toMatrixBasis b x = LinearMap.toMatrixOrthonormal b (S.act Λ x) := - rfl - -theorem trace_eq_matrixTrace_basis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] - (b : OrthonormalBasis ι ℂ (ℋ Λ)) (ρ : N.algebra Λ) : - S.trace Λ ρ = (S.toMatrixBasis b ρ).trace := by - rw [toMatrixBasis_apply, LinearMap.trace_toMatrixOrthonormal, trace_apply] - -theorem continuous_toMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] - (b : OrthonormalBasis ι ℂ (ℋ Λ)) : Continuous (S.toMatrixBasis b) := by - haveI := S.finiteDimensional_algebra Λ - let L : N.algebra Λ →ₗ[ℂ] Matrix ι ι ℂ := - { toFun := S.toMatrixBasis b, map_add' := map_add _, map_smul' := map_smul _ } - exact L.continuous_of_finiteDimensional - -/-- The density matrix of a state in an arbitrary orthonormal basis `b` of the action space. -/ -noncomputable def toDensityMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] [DecidableEq ι] - (b : OrthonormalBasis ι ℂ (ℋ Λ)) {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - DensityMatrix ι where - toMatrix := S.toMatrixBasis b ρ - posSemidef := by - rw [toMatrixBasis_apply] - exact (LinearMap.posSemidef_toMatrix_iff b).mpr - ((LinearMap.nonneg_iff_isPositive _).mp hρ.nonneg) - trace_eq_one := by rw [← S.trace_eq_matrixTrace_basis b]; exact hρ.trace_eq_one - -@[simp] theorem toDensityMatrixBasis_toMatrix {Λ : Finset sites} {ι : Type*} [Fintype ι] - [DecidableEq ι] (b : OrthonormalBasis ι ℂ (ℋ Λ)) {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - (S.toDensityMatrixBasis b hρ).toMatrix = S.toMatrixBasis b ρ := - rfl - -/-- **Basis-independence of the von Neumann entropy**: the matrix von Neumann entropy of a state's -density matrix is the same in any orthonormal basis of the action space, and equals the -representation-free split-net entropy `S.entropy`. This is the freedom needed to compute marginal -entropies in a *tensor-factorised* orthonormal basis. -/ -theorem vonNeumannEntropy_toDensityMatrixBasis {Λ : Finset sites} {ι : Type*} [Fintype ι] - [DecidableEq ι] (b : OrthonormalBasis ι ℂ (ℋ Λ)) {ρ : N.algebra Λ} (hρ : S.IsDensity ρ) : - Matrix.vonNeumannEntropy (S.toDensityMatrixBasis b hρ) = S.entropy ρ := by - haveI : IsScalarTower ℝ ℂ (N.algebra Λ) := IsScalarTower.complexToReal - have hsa : IsSelfAdjoint ρ := S.isSelfAdjoint_of_isDensity hρ - have hsa' : IsSelfAdjoint (S.toMatrixBasis b ρ) := - show star (S.toMatrixBasis b ρ) = S.toMatrixBasis b ρ by rw [← map_star, hsa] - rw [entropy_def, S.trace_eq_matrixTrace_basis b, Matrix.vonNeumannEntropy_eq_cfc_re, - toDensityMatrixBasis_toMatrix, - StarAlgHomClass.map_cfc (S.toMatrixBasis b) Real.negMulLog ρ - Real.continuous_negMulLog.continuousOn (S.continuous_toMatrixBasis b) hsa hsa'] - -/-- **The marginal of a state is a state.** Restricting a density operator to a sub-region yields a -density operator: the marginal preserves positivity (the partial trace along the *unitary* -factorisation `decompᵢ` is positivity-preserving, `LinearMap.isPositive_partialTrace`) and the -trace (`trace_restrict`). This is the representation-free statement that `restrict` is a quantum -channel on states. -/ -theorem restrict_isDensity {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') {ρ : N.algebra Λ'} - (hρ : S.IsDensity ρ) : S.IsDensity (S.restrict h ρ) := by - refine ⟨?_, ?_⟩ - · rw [LinearMap.nonneg_iff_isPositive, restrict_apply, AlgEquiv.apply_symm_apply] - have hpt := LinearMap.isPositive_partialTrace (S.decompᵢ h) - ((LinearMap.nonneg_iff_isPositive _).mp hρ.nonneg) - rwa [S.decompᵢ_toLinearEquiv h] at hpt - · rw [S.trace_restrict h ρ] - exact hρ.trace_eq_one - -/-- **Non-degeneracy of the trace pairing** on a local algebra: if `trace (A · X) = trace (B · X)` -for every `X`, then `A = B`. The trace form on the type I factor is non-degenerate -(`Matrix.ext_iff_trace_mul_right` through the matrix representation `toMatrix`). -/ -theorem trace_nondeg {Λ : Finset sites} {A B : N.algebra Λ} - (hAB : ∀ X, S.trace Λ (A * X) = S.trace Λ (B * X)) : A = B := by - apply (S.toMatrix Λ).injective - rw [Matrix.ext_iff_trace_mul_right] - intro Y - have hX := hAB ((S.toMatrix Λ).symm Y) - simp only [trace_eq_matrixTrace, map_mul, StarAlgEquiv.apply_symm_apply] at hX - exact hX - -/-- **Iterated marginalisation equals direct marginalisation**: -`restrict h₂ (restrict h₁ ρ) = restrict (h₂.trans h₁) ρ`. This is the coherence that strong -subadditivity needs — and it is **free**: it follows from the Heisenberg/trace duality -`trace_mul_incl` together with the net's functoriality `incl_trans`, with no associativity axiom on -the tensor factorisations. (The marginal is the predual of `incl`, and inclusions compose.) -/ -theorem restrict_restrict {Λ'' Λ Λ' : Finset sites} (h₁ : Λ ⊆ Λ') (h₂ : Λ'' ⊆ Λ) - (ρ : N.algebra Λ') : - S.restrict h₂ (S.restrict h₁ ρ) = S.restrict (h₂.trans h₁) ρ := by - apply S.trace_nondeg - intro X - rw [← S.trace_mul_incl h₂ (S.restrict h₁ ρ) X, ← S.trace_mul_incl (h₂.trans h₁) ρ X, - ← S.trace_mul_incl h₁ ρ (N.incl h₂ X), N.incl_trans h₂ h₁ X] - -/-- The **matrix Kraus operators** of the transported marginal: `Kⱼ = ⟨the matrix of the adjoint of -the partial-trace Kraus operator `Vⱼ` of `decompᵢ h`⟩`, in the standard orthonormal bases. -/ -noncomputable def restrictKraus {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') - (j : Fin (Module.finrank ℂ (ℋ (Λ' \ Λ)))) : - Matrix (Fin (Module.finrank ℂ (ℋ Λ))) (Fin (Module.finrank ℂ (ℋ Λ'))) ℂ := - LinearMap.toMatrix (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis - (LinearMap.adjoint (LinearMap.ptKraus (S.decompᵢ h) j)) - -/-- **Matrix Kraus form of the marginal**: under the matrix representation, `restrict h` acts as -`M ↦ ∑ⱼ Kⱼ M Kⱼᴴ`. Transports the operator Kraus form `partialTrace_eq_sum_kraus`; exhibits the -transported marginal as a completely positive map. -/ -theorem toMatrix_restrict_eq_sum_kraus {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (ρ : N.algebra Λ') : - S.toMatrix Λ (S.restrict h ρ) - = ∑ j, S.restrictKraus h j * S.toMatrix Λ' ρ * (S.restrictKraus h j)ᴴ := by - have hact : S.act Λ (S.restrict h ρ) - = LinearMap.partialTrace (S.decompᵢ h).toLinearEquiv (S.act Λ' ρ) := by - rw [restrict_apply, AlgEquiv.apply_symm_apply, S.decompᵢ_toLinearEquiv h] - -- `toMatrixOrthonormal` is the matrix in the standard ON basis (clean `LinearMap.toMatrix` form). - have htmo : ∀ {Λ₀ : Finset sites} (g : Module.End ℂ (ℋ Λ₀)), - LinearMap.toMatrixOrthonormal (stdOrthonormalBasis ℂ (ℋ Λ₀)) g - = LinearMap.toMatrix (stdOrthonormalBasis ℂ (ℋ Λ₀)).toBasis - (stdOrthonormalBasis ℂ (ℋ Λ₀)).toBasis g := fun g => rfl - -- `(restrictKraus h j)ᴴ` is the matrix of the Kraus operator `Vⱼ` itself. - have hKt : ∀ j, (S.restrictKraus h j)ᴴ - = LinearMap.toMatrix (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis - (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (LinearMap.ptKraus (S.decompᵢ h) j) := by - intro j - rw [restrictKraus, LinearMap.toMatrix_adjoint, Matrix.conjTranspose_conjTranspose] - rw [toMatrix_apply, hact, LinearMap.partialTrace_eq_sum_kraus, map_sum] - refine Finset.sum_congr rfl fun j _ => ?_ - rw [hKt j, restrictKraus, toMatrix_apply] - simp only [htmo] - rw [LinearMap.toMatrix_comp (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis - (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis, - LinearMap.toMatrix_comp (stdOrthonormalBasis ℂ (ℋ Λ)).toBasis - (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis (stdOrthonormalBasis ℂ (ℋ Λ')).toBasis, - Matrix.mul_assoc] - -end LocalNet.Split From 3e23dd681d7cd2e715ccaa5e19144c4b6b0dbebd Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 17:51:37 +0000 Subject: [PATCH 029/113] refactor: remove QuantumSystem.Analysis.Channel.PartialTrace --- QuantumSystem.lean | 1 - .../Analysis/Channel/PartialTrace.lean | 212 ------------------ .../Entropy/StrongSubadditivityProduct.lean | 2 +- QuantumSystem/Channel.lean | 191 ++++++++++++++++ 4 files changed, 192 insertions(+), 214 deletions(-) delete mode 100644 QuantumSystem/Analysis/Channel/PartialTrace.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 49dd05b..17a9378 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -23,7 +23,6 @@ public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal -public import QuantumSystem.Analysis.Channel.PartialTrace public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.MutualInfoProduct public import QuantumSystem.Analysis.Entropy.RelativeEntropy diff --git a/QuantumSystem/Analysis/Channel/PartialTrace.lean b/QuantumSystem/Analysis/Channel/PartialTrace.lean deleted file mode 100644 index 7979f1d..0000000 --- a/QuantumSystem/Analysis/Channel/PartialTrace.lean +++ /dev/null @@ -1,212 +0,0 @@ -module - -public import QuantumSystem.Channel -public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace - -/-! -# Partial trace as a quantum channel (product index types) - -The **partial trace** on plain product index types `X × Y`, packaged as a completely positive -trace-preserving map (`QuantumChannel`): it traces out the right factor `Y` of a matrix on `X × Y`, -leaving a matrix on `X`. - -We also package conjugation by an index equivalence (`reindexₗ`) as a channel, and compose the two -into the trace-out-`C` channel `QuantumChannel.traceOutC : QuantumChannel (A × B × C) (A × B)`, -whose action is exactly the `lean-eval` marginal map -`M ↦ traceRight (M.reindex (prodAssoc).symm (prodAssoc).symm)`. - -## Main definitions - -* `Matrix.partialTraceRightₗ` — right partial trace as a `ℂ`-linear map. -* `Matrix.QuantumChannel.partialTraceRight` — bundled quantum channel tracing out `Y`. -* `Matrix.QuantumChannel.reindex` — conjugation by an index equivalence, as a channel. -* `Matrix.QuantumChannel.traceOutC` — trace out the `C` factor of `A × B × C`. --/ - -@[expose] public section - -namespace Matrix - -open scoped ComplexOrder - -/-! ### Positive semidefiniteness and trace facts for the partial trace -/ - -/-- The right partial trace preserves positive semidefiniteness (it is a sum of principal -submatrices). -/ -theorem traceRight_posSemidef {l n : Type*} [Fintype n] - {M : Matrix (l × n) (l × n) ℂ} (hM : M.PosSemidef) : (Matrix.traceRight M).PosSemidef := by - have hsum : Matrix.traceRight M - = ∑ k : n, M.submatrix (fun i : l => (i, k)) (fun j : l => (j, k)) := by - ext i j; simp [Matrix.traceRight_apply, Matrix.sum_apply, Matrix.submatrix_apply] - rw [hsum] - exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) - -/-- The left partial trace preserves positive semidefiniteness. -/ -theorem traceLeft_posSemidef {l n : Type*} [Fintype n] - {M : Matrix (n × l) (n × l) ℂ} (hM : M.PosSemidef) : (Matrix.traceLeft M).PosSemidef := by - have hsum : Matrix.traceLeft M - = ∑ k : n, M.submatrix (fun i : l => (k, i)) (fun j : l => (k, j)) := by - ext i j; simp [Matrix.traceLeft_apply, Matrix.sum_apply, Matrix.submatrix_apply] - rw [hsum] - exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) - -/-- Reindexing by an index equivalence preserves the trace. -/ -@[simp] theorem trace_reindex_self {n m : Type*} [Fintype n] [Fintype m] (e : n ≃ m) - (M : Matrix n n ℂ) : (M.reindex e e).trace = M.trace := by - simp only [Matrix.trace, Matrix.diag_apply, Matrix.reindex_apply, Matrix.submatrix_apply] - exact Equiv.sum_comp e.symm (fun i => M i i) - -/-- The right partial trace of the identity scales by the cardinality of the traced factor. -/ -theorem traceRight_one {X Y : Type*} [DecidableEq X] [Fintype Y] [DecidableEq Y] : - Matrix.traceRight (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card Y : ℂ) • (1 : Matrix X X ℂ) := by - ext i j - simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] - by_cases hij : i = j - · subst hij; simp [Finset.card_univ] - · simp [hij] - -/-- The left partial trace of the identity scales by the cardinality of the traced factor. -/ -theorem traceLeft_one {X Y : Type*} [Fintype X] [DecidableEq X] [DecidableEq Y] : - Matrix.traceLeft (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card X : ℂ) • (1 : Matrix Y Y ℂ) := by - ext i j - simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] - by_cases hij : i = j - · subst hij; simp [Finset.card_univ] - · simp [hij] - -/-! ### Right partial trace as a linear map -/ - -/-- `Matrix.traceRight` as a `ℂ`-linear map `Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix X X ℂ`. -/ -noncomputable def partialTraceRightₗ {X Y : Type*} [Fintype Y] : - Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix X X ℂ where - toFun M := Matrix.traceRight M - map_add' M N := by - ext i j; simp only [traceRight_apply, Matrix.add_apply, Finset.sum_add_distrib] - map_smul' c M := by - ext i j - simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, RingHom.id_apply, Finset.mul_sum] - -@[simp] lemma partialTraceRightₗ_apply {X Y : Type*} [Fintype Y] (M : Matrix (X × Y) (X × Y) ℂ) : - partialTraceRightₗ M = Matrix.traceRight M := rfl - -/-- `Matrix.traceLeft` as a `ℂ`-linear map `Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix Y Y ℂ`. -/ -noncomputable def partialTraceLeftₗ {X Y : Type*} [Fintype X] : - Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix Y Y ℂ where - toFun M := Matrix.traceLeft M - map_add' M N := by - ext i j; simp only [traceLeft_apply, Matrix.add_apply, Finset.sum_add_distrib] - map_smul' c M := by - ext i j - simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, RingHom.id_apply, Finset.mul_sum] - -@[simp] lemma partialTraceLeftₗ_apply {X Y : Type*} [Fintype X] (M : Matrix (X × Y) (X × Y) ℂ) : - partialTraceLeftₗ M = Matrix.traceLeft M := rfl - -/-! ### Kraus operators and complete positivity -/ - -/-- Kraus operator for the right partial trace, indexed by `y : Y`: `K_y x p = [p = (x, y)]`. -/ -def traceRightKraus {X Y : Type*} [DecidableEq X] [DecidableEq Y] (y : Y) : - Matrix X (X × Y) ℂ := - Matrix.of fun x p => if p = (x, y) then (1 : ℂ) else 0 - -theorem isCompletelyPositive_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : - IsCompletelyPositive (partialTraceRightₗ (X := X) (Y := Y)) := by - classical - refine ⟨Fintype.card Y, fun i => traceRightKraus ((Fintype.equivFin Y).symm i), fun M => ?_⟩ - rw [partialTraceRightₗ_apply] - ext i j - rw [traceRight_apply, Matrix.sum_apply, ← (Fintype.equivFin Y).symm.sum_comp - (fun y => M (i, y) (j, y))] - refine Finset.sum_congr rfl fun p _ => ?_ - -- Goal: M (i, y) (j, y) = (K_y * M * K_yᴴ) i j with `y = (equivFin Y).symm p` - -- (mul is `Matrix.mul` from `IsCompletelyPositive`). - symm - rw [Matrix.mul_apply, Finset.sum_eq_single (j, (Fintype.equivFin Y).symm p)] - · rw [Matrix.mul_apply, Finset.sum_eq_single (i, (Fintype.equivFin Y).symm p)] - · simp [traceRightKraus, Matrix.conjTranspose_apply] - · intro q _ hq - simp only [traceRightKraus, Matrix.of_apply] - rw [if_neg hq]; ring - · simp - · intro q _ hq - simp only [traceRightKraus, Matrix.conjTranspose_apply, Matrix.of_apply, - apply_ite (star · : ℂ → ℂ), star_one, star_zero] - rw [if_neg hq]; simp - · simp - -theorem isTracePreserving_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : - IsTracePreserving (partialTraceRightₗ (X := X) (Y := Y)) := - fun M => by rw [partialTraceRightₗ_apply]; exact trace_traceRight M - -/-- Right partial trace (trace out `Y`) as a bundled `QuantumChannel`. -/ -noncomputable def QuantumChannel.partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : - Matrix.QuantumChannel (X × Y) X := - ⟨partialTraceRightₗ, isCompletelyPositive_partialTraceRight, isTracePreserving_partialTraceRight⟩ - -/-! ### Conjugation by an index equivalence as a channel -/ - -/-- Conjugation by a reindex `e : Z ≃ W`: `M ↦ M.submatrix e.symm e.symm`, as a linear map. -/ -noncomputable def reindexₗ {Z W : Type*} (e : Z ≃ W) : - Matrix Z Z ℂ →ₗ[ℂ] Matrix W W ℂ where - toFun M := M.submatrix e.symm e.symm - map_add' M N := by ext w w'; simp [Matrix.submatrix_apply] - map_smul' c M := by ext w w'; simp [Matrix.submatrix_apply] - -@[simp] lemma reindexₗ_apply {Z W : Type*} (e : Z ≃ W) (M : Matrix Z Z ℂ) : - reindexₗ e M = M.submatrix e.symm e.symm := rfl - -/-- Kraus operator (permutation matrix) for `reindexₗ e`: `P w z = [z = e.symm w]`. -/ -def reindexKraus {Z W : Type*} [DecidableEq Z] (e : Z ≃ W) : Matrix W Z ℂ := - Matrix.of fun w z => if z = e.symm w then (1 : ℂ) else 0 - -theorem isCompletelyPositive_reindexₗ {Z W : Type*} [Fintype Z] (e : Z ≃ W) : - IsCompletelyPositive (reindexₗ e) := by - classical - refine ⟨1, fun _ => reindexKraus e, fun M => ?_⟩ - simp only [Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton] - ext w w' - rw [reindexₗ_apply, Matrix.submatrix_apply] - symm - rw [Matrix.mul_apply, Finset.sum_eq_single (e.symm w')] - · rw [Matrix.mul_apply, Finset.sum_eq_single (e.symm w)] - · simp [reindexKraus] - · intro q _ hq - simp only [reindexKraus, Matrix.of_apply] - rw [if_neg hq]; ring - · simp - · intro z _ hz - simp only [reindexKraus, Matrix.conjTranspose_apply, Matrix.of_apply, - apply_ite (star · : ℂ → ℂ), star_one, star_zero] - rw [if_neg hz]; simp - · simp - -theorem isTracePreserving_reindexₗ {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : - IsTracePreserving (reindexₗ e) := by - intro M - rw [reindexₗ_apply] - exact trace_reindex_self e M - -/-- Conjugation by an index equivalence as a bundled `QuantumChannel`. -/ -noncomputable def QuantumChannel.reindex {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : - Matrix.QuantumChannel Z W := - ⟨reindexₗ e, isCompletelyPositive_reindexₗ e, isTracePreserving_reindexₗ e⟩ - -/-! ### Trace-out-`C` channel for `A × B × C` -/ - -/-- Trace out the `C` factor of `A × B × C`, landing on `A × B`. Its action is the `lean-eval` -marginal map `M ↦ traceRight (M.reindex (prodAssoc).symm (prodAssoc).symm)`. -/ -noncomputable def QuantumChannel.traceOutC {A B C : Type*} [Fintype A] [Fintype B] [Fintype C] : - Matrix.QuantumChannel (A × B × C) (A × B) := - ⟨(partialTraceRightₗ (X := A × B) (Y := C)).comp (reindexₗ (Equiv.prodAssoc A B C).symm), - QuantumChannel.comp (QuantumChannel.reindex (Equiv.prodAssoc A B C).symm) - QuantumChannel.partialTraceRight⟩ - -@[simp] lemma QuantumChannel.traceOutC_val_apply {A B C : Type*} - [Fintype A] [Fintype B] [Fintype C] (M : Matrix (A × B × C) (A × B × C) ℂ) : - (QuantumChannel.traceOutC (A := A) (B := B) (C := C)).val M - = Matrix.traceRight - (M.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) := by - change partialTraceRightₗ (reindexₗ (Equiv.prodAssoc A B C).symm M) = _ - rw [partialTraceRightₗ_apply, reindexₗ_apply, Matrix.reindex_apply] - -end Matrix diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean index d18f714..4eb0dc0 100644 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean @@ -1,6 +1,6 @@ module -public import QuantumSystem.Analysis.Channel.PartialTrace +public import QuantumSystem.Channel public import QuantumSystem.Analysis.Entropy.MutualInfoProduct /-! diff --git a/QuantumSystem/Channel.lean b/QuantumSystem/Channel.lean index a9a9a07..0cb66a6 100644 --- a/QuantumSystem/Channel.lean +++ b/QuantumSystem/Channel.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.State +public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace /-! # Quantum Channels (Completely Positive Trace-Preserving Maps) @@ -10,11 +11,19 @@ their basic properties. A quantum channel is a linear map Φ: M_n(ℂ) → M_m( 1. Completely positive (CP): Has a Kraus representation Φ(ρ) = Σᵢ Kᵢ ρ Kᵢ† 2. Trace-preserving (TP): Tr(Φ(A)) = Tr(A) for all A, equivalently Σᵢ Kᵢ† Kᵢ = I +It also packages the **partial trace** on product index types as a quantum channel: tracing out a +factor of a matrix on `X × Y` (or `A × B × C`) is completely positive and trace preserving, and the +trace-out-`C` channel `QuantumChannel.traceOutC` realises the `lean-eval` marginal map. + ## Main definitions * `IsTracePreserving`: A linear map preserves trace. * `IsCompletelyPositive`: A linear map has a Kraus representation. * `IsQuantumChannel`: A linear map is both CP and TP. +* `Matrix.partialTraceRightₗ` — right partial trace as a `ℂ`-linear map. +* `Matrix.QuantumChannel.partialTraceRight` — bundled quantum channel tracing out `Y`. +* `Matrix.QuantumChannel.reindex` — conjugation by an index equivalence, as a channel. +* `Matrix.QuantumChannel.traceOutC` — trace out the `C` factor of `A × B × C`. ## Mathematical Background @@ -196,4 +205,186 @@ lemma stinespringIsometry_conjTranspose_mul {r : ℕ} [DecidableEq n] = (1 : Matrix n n ℂ) a b := by rw [hK] _ = if a = b then 1 else 0 := Matrix.one_apply +/-! ### Partial trace as a quantum channel (product index types) -/ + +/-! #### Positive semidefiniteness and trace facts for the partial trace -/ + +/-- The right partial trace preserves positive semidefiniteness (it is a sum of principal +submatrices). -/ +theorem traceRight_posSemidef {l n : Type*} [Fintype n] + {M : Matrix (l × n) (l × n) ℂ} (hM : M.PosSemidef) : (Matrix.traceRight M).PosSemidef := by + have hsum : Matrix.traceRight M + = ∑ k : n, M.submatrix (fun i : l => (i, k)) (fun j : l => (j, k)) := by + ext i j; simp [Matrix.traceRight_apply, Matrix.sum_apply, Matrix.submatrix_apply] + rw [hsum] + exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) + +/-- The left partial trace preserves positive semidefiniteness. -/ +theorem traceLeft_posSemidef {l n : Type*} [Fintype n] + {M : Matrix (n × l) (n × l) ℂ} (hM : M.PosSemidef) : (Matrix.traceLeft M).PosSemidef := by + have hsum : Matrix.traceLeft M + = ∑ k : n, M.submatrix (fun i : l => (k, i)) (fun j : l => (k, j)) := by + ext i j; simp [Matrix.traceLeft_apply, Matrix.sum_apply, Matrix.submatrix_apply] + rw [hsum] + exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) + +/-- Reindexing by an index equivalence preserves the trace. -/ +@[simp] theorem trace_reindex_self {n m : Type*} [Fintype n] [Fintype m] (e : n ≃ m) + (M : Matrix n n ℂ) : (M.reindex e e).trace = M.trace := by + simp only [Matrix.trace, Matrix.diag_apply, Matrix.reindex_apply, Matrix.submatrix_apply] + exact Equiv.sum_comp e.symm (fun i => M i i) + +/-- The right partial trace of the identity scales by the cardinality of the traced factor. -/ +theorem traceRight_one {X Y : Type*} [DecidableEq X] [Fintype Y] [DecidableEq Y] : + Matrix.traceRight (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card Y : ℂ) • (1 : Matrix X X ℂ) := by + ext i j + simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] + by_cases hij : i = j + · subst hij; simp [Finset.card_univ] + · simp [hij] + +/-- The left partial trace of the identity scales by the cardinality of the traced factor. -/ +theorem traceLeft_one {X Y : Type*} [Fintype X] [DecidableEq X] [DecidableEq Y] : + Matrix.traceLeft (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card X : ℂ) • (1 : Matrix Y Y ℂ) := by + ext i j + simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] + by_cases hij : i = j + · subst hij; simp [Finset.card_univ] + · simp [hij] + +/-! #### Right partial trace as a linear map -/ + +/-- `Matrix.traceRight` as a `ℂ`-linear map `Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix X X ℂ`. -/ +noncomputable def partialTraceRightₗ {X Y : Type*} [Fintype Y] : + Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix X X ℂ where + toFun M := Matrix.traceRight M + map_add' M N := by + ext i j; simp only [traceRight_apply, Matrix.add_apply, Finset.sum_add_distrib] + map_smul' c M := by + ext i j + simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, RingHom.id_apply, Finset.mul_sum] + +@[simp] lemma partialTraceRightₗ_apply {X Y : Type*} [Fintype Y] (M : Matrix (X × Y) (X × Y) ℂ) : + partialTraceRightₗ M = Matrix.traceRight M := rfl + +/-- `Matrix.traceLeft` as a `ℂ`-linear map `Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix Y Y ℂ`. -/ +noncomputable def partialTraceLeftₗ {X Y : Type*} [Fintype X] : + Matrix (X × Y) (X × Y) ℂ →ₗ[ℂ] Matrix Y Y ℂ where + toFun M := Matrix.traceLeft M + map_add' M N := by + ext i j; simp only [traceLeft_apply, Matrix.add_apply, Finset.sum_add_distrib] + map_smul' c M := by + ext i j + simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, RingHom.id_apply, Finset.mul_sum] + +@[simp] lemma partialTraceLeftₗ_apply {X Y : Type*} [Fintype X] (M : Matrix (X × Y) (X × Y) ℂ) : + partialTraceLeftₗ M = Matrix.traceLeft M := rfl + +/-! #### Kraus operators and complete positivity -/ + +/-- Kraus operator for the right partial trace, indexed by `y : Y`: `K_y x p = [p = (x, y)]`. -/ +def traceRightKraus {X Y : Type*} [DecidableEq X] [DecidableEq Y] (y : Y) : + Matrix X (X × Y) ℂ := + Matrix.of fun x p => if p = (x, y) then (1 : ℂ) else 0 + +theorem isCompletelyPositive_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : + IsCompletelyPositive (partialTraceRightₗ (X := X) (Y := Y)) := by + classical + refine ⟨Fintype.card Y, fun i => traceRightKraus ((Fintype.equivFin Y).symm i), fun M => ?_⟩ + rw [partialTraceRightₗ_apply] + ext i j + rw [traceRight_apply, Matrix.sum_apply, ← (Fintype.equivFin Y).symm.sum_comp + (fun y => M (i, y) (j, y))] + refine Finset.sum_congr rfl fun p _ => ?_ + -- Goal: M (i, y) (j, y) = (K_y * M * K_yᴴ) i j with `y = (equivFin Y).symm p` + -- (mul is `Matrix.mul` from `IsCompletelyPositive`). + symm + rw [Matrix.mul_apply, Finset.sum_eq_single (j, (Fintype.equivFin Y).symm p)] + · rw [Matrix.mul_apply, Finset.sum_eq_single (i, (Fintype.equivFin Y).symm p)] + · simp [traceRightKraus, Matrix.conjTranspose_apply] + · intro q _ hq + simp only [traceRightKraus, Matrix.of_apply] + rw [if_neg hq]; ring + · simp + · intro q _ hq + simp only [traceRightKraus, Matrix.conjTranspose_apply, Matrix.of_apply, + apply_ite (star · : ℂ → ℂ), star_one, star_zero] + rw [if_neg hq]; simp + · simp + +theorem isTracePreserving_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : + IsTracePreserving (partialTraceRightₗ (X := X) (Y := Y)) := + fun M => by rw [partialTraceRightₗ_apply]; exact trace_traceRight M + +/-- Right partial trace (trace out `Y`) as a bundled `QuantumChannel`. -/ +noncomputable def QuantumChannel.partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : + Matrix.QuantumChannel (X × Y) X := + ⟨partialTraceRightₗ, isCompletelyPositive_partialTraceRight, isTracePreserving_partialTraceRight⟩ + +/-! #### Conjugation by an index equivalence as a channel -/ + +/-- Conjugation by a reindex `e : Z ≃ W`: `M ↦ M.submatrix e.symm e.symm`, as a linear map. -/ +noncomputable def reindexₗ {Z W : Type*} (e : Z ≃ W) : + Matrix Z Z ℂ →ₗ[ℂ] Matrix W W ℂ where + toFun M := M.submatrix e.symm e.symm + map_add' M N := by ext w w'; simp [Matrix.submatrix_apply] + map_smul' c M := by ext w w'; simp [Matrix.submatrix_apply] + +@[simp] lemma reindexₗ_apply {Z W : Type*} (e : Z ≃ W) (M : Matrix Z Z ℂ) : + reindexₗ e M = M.submatrix e.symm e.symm := rfl + +/-- Kraus operator (permutation matrix) for `reindexₗ e`: `P w z = [z = e.symm w]`. -/ +def reindexKraus {Z W : Type*} [DecidableEq Z] (e : Z ≃ W) : Matrix W Z ℂ := + Matrix.of fun w z => if z = e.symm w then (1 : ℂ) else 0 + +theorem isCompletelyPositive_reindexₗ {Z W : Type*} [Fintype Z] (e : Z ≃ W) : + IsCompletelyPositive (reindexₗ e) := by + classical + refine ⟨1, fun _ => reindexKraus e, fun M => ?_⟩ + simp only [Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton] + ext w w' + rw [reindexₗ_apply, Matrix.submatrix_apply] + symm + rw [Matrix.mul_apply, Finset.sum_eq_single (e.symm w')] + · rw [Matrix.mul_apply, Finset.sum_eq_single (e.symm w)] + · simp [reindexKraus] + · intro q _ hq + simp only [reindexKraus, Matrix.of_apply] + rw [if_neg hq]; ring + · simp + · intro z _ hz + simp only [reindexKraus, Matrix.conjTranspose_apply, Matrix.of_apply, + apply_ite (star · : ℂ → ℂ), star_one, star_zero] + rw [if_neg hz]; simp + · simp + +theorem isTracePreserving_reindexₗ {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : + IsTracePreserving (reindexₗ e) := by + intro M + rw [reindexₗ_apply] + exact trace_reindex_self e M + +/-- Conjugation by an index equivalence as a bundled `QuantumChannel`. -/ +noncomputable def QuantumChannel.reindex {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : + Matrix.QuantumChannel Z W := + ⟨reindexₗ e, isCompletelyPositive_reindexₗ e, isTracePreserving_reindexₗ e⟩ + +/-! #### Trace-out-`C` channel for `A × B × C` -/ + +/-- Trace out the `C` factor of `A × B × C`, landing on `A × B`. Its action is the `lean-eval` +marginal map `M ↦ traceRight (M.reindex (prodAssoc).symm (prodAssoc).symm)`. -/ +noncomputable def QuantumChannel.traceOutC {A B C : Type*} [Fintype A] [Fintype B] [Fintype C] : + Matrix.QuantumChannel (A × B × C) (A × B) := + ⟨(partialTraceRightₗ (X := A × B) (Y := C)).comp (reindexₗ (Equiv.prodAssoc A B C).symm), + QuantumChannel.comp (QuantumChannel.reindex (Equiv.prodAssoc A B C).symm) + QuantumChannel.partialTraceRight⟩ + +@[simp] lemma QuantumChannel.traceOutC_val_apply {A B C : Type*} + [Fintype A] [Fintype B] [Fintype C] (M : Matrix (A × B × C) (A × B × C) ℂ) : + (QuantumChannel.traceOutC (A := A) (B := B) (C := C)).val M + = Matrix.traceRight + (M.reindex (Equiv.prodAssoc A B C).symm (Equiv.prodAssoc A B C).symm) := by + change partialTraceRightₗ (reindexₗ (Equiv.prodAssoc A B C).symm M) = _ + rw [partialTraceRightₗ_apply, reindexₗ_apply, Matrix.reindex_apply] + end Matrix From 9ecd9675780388a41f4f31b11764a2080bea7fd4 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 18:07:28 +0000 Subject: [PATCH 030/113] refactor(entropy): drop redundant 'product' qualifier from SSA/mutual-information names Co-Authored-By: Claude Opus 4.8 --- QuantumSystem.lean | 4 +-- ...nfoProduct.lean => MutualInformation.lean} | 12 ++++---- ...yProduct.lean => StrongSubadditivity.lean} | 28 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) rename QuantumSystem/Analysis/Entropy/{MutualInfoProduct.lean => MutualInformation.lean} (92%) rename QuantumSystem/Analysis/Entropy/{StrongSubadditivityProduct.lean => StrongSubadditivity.lean} (93%) diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 17a9378..77c7aed 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -24,9 +24,9 @@ public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Analysis.CFC.Diagonal public import QuantumSystem.Analysis.Entropy.KroneckerProduct -public import QuantumSystem.Analysis.Entropy.MutualInfoProduct +public import QuantumSystem.Analysis.Entropy.MutualInformation public import QuantumSystem.Analysis.Entropy.RelativeEntropy -public import QuantumSystem.Analysis.Entropy.StrongSubadditivityProduct +public import QuantumSystem.Analysis.Entropy.StrongSubadditivity public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy public import QuantumSystem.Analysis.Matrix.Effros public import QuantumSystem.Analysis.Matrix.HermitianFunctionalCalculus diff --git a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean b/QuantumSystem/Analysis/Entropy/MutualInformation.lean similarity index 92% rename from QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean rename to QuantumSystem/Analysis/Entropy/MutualInformation.lean index e7f0037..d2e765e 100644 --- a/QuantumSystem/Analysis/Entropy/MutualInfoProduct.lean +++ b/QuantumSystem/Analysis/Entropy/MutualInformation.lean @@ -5,15 +5,15 @@ public import QuantumSystem.Analysis.Entropy.RelativeEntropy public import QuantumSystem.Analysis.Entropy.VonNeumannEntropy /-! -# Mutual-information identity (product-type form) +# Mutual-information identity The relative-entropy form of quantum mutual information for a bipartite density matrix on a plain product index type `n × m`: `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -It is representation-free; the analytic core reused both by the product-form proof -(`Analysis/Entropy/StrongSubadditivityProduct.lean`) and, via transport, by the abstract split-net +It is representation-free; the analytic core reused both by the direct proof +(`Analysis/Entropy/StrongSubadditivity.lean`) and, via transport, by the abstract split-net proof (`Analysis/Entropy/SplitSSA.lean`). -/ @@ -25,13 +25,13 @@ open scoped Kronecker MatrixOrder ComplexOrder QuantumInfo variable {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] -/-! ### Product-type relative-entropy identity -/ +/-! ### Relative-entropy identity -/ -/-- **Mutual-information identity (product-type form)**: for a bipartite density +/-- **Mutual-information identity**: for a bipartite density matrix `ρ_AB : DensityMatrix (n × m)` whose canonical partial traces coincide with PosDef factor states `ρ_A` and `ρ_B`, the relative entropy w.r.t. the product `ρ_A ⊗ ρ_B` equals `-S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -/ -theorem relativeEntropy_kronecker_marginals_product +theorem relativeEntropy_kronecker_marginals (ρ_AB : DensityMatrix (n × m)) (ρ_A : DensityMatrix n) (hρ_A : ρ_A.toMatrix.PosDef) (ρ_B : DensityMatrix m) (hρ_B : ρ_B.toMatrix.PosDef) diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean similarity index 93% rename from QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean rename to QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean index 4eb0dc0..4c0a9b4 100644 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivityProduct.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean @@ -1,30 +1,30 @@ module public import QuantumSystem.Channel -public import QuantumSystem.Analysis.Entropy.MutualInfoProduct +public import QuantumSystem.Analysis.Entropy.MutualInformation /-! -# Strong subadditivity of the von Neumann entropy (product form) +# Strong subadditivity of the von Neumann entropy This file proves strong subadditivity (SSA) directly on plain product index types `A × B × C`, with marginals taken by the positional partial traces `Matrix.traceLeft` / `Matrix.traceRight`. It is representation-free — no net structure — the proof is the bare finite-dimensional quantum-information argument -1. the mutual-information identity `Matrix.relativeEntropy_kronecker_marginals_product` +1. the mutual-information identity `Matrix.relativeEntropy_kronecker_marginals` (applied to the `(A : B×C)` and `(A : B)` bipartitions), and 2. the data-processing inequality `Matrix.relativeEntropy_channel_le` for the trace-out-`C` channel `Matrix.QuantumChannel.traceOutC`. The AQFT companion — the same inequality stated representation-free over an abstract operator- algebraic split net with nested regions — is `LocalNet.Split.vonNeumannEntropy_SSA` -(`SplitSSA.lean`), which transports this product-form result to the net. +(`SplitSSA.lean`), which transports this result to the net. ## Main results -* `DensityMatrix.vonNeumannEntropy_SSA_product_posDef` — SSA on `A × B × C` for a positive +* `DensityMatrix.vonNeumannEntropy_SSA_posDef` — SSA on `A × B × C` for a positive definite density matrix. -* `DensityMatrix.vonNeumannEntropy_SSA_product` — SSA on `A × B × C` for an arbitrary density +* `DensityMatrix.vonNeumannEntropy_SSA` — SSA on `A × B × C` for an arbitrary density matrix (via regularisation). -/ @@ -112,15 +112,15 @@ noncomputable def ptLeft {X Y : Type*} [Fintype X] [DecidableEq X] [Fintype Y] [ @[simp] lemma ptLeft_toMatrix {X Y : Type*} [Fintype X] [DecidableEq X] [Fintype Y] [DecidableEq Y] (ρ : DensityMatrix (X × Y)) : (ρ.ptLeft).toMatrix = Matrix.traceLeft ρ.toMatrix := rfl -/-! ### Strong subadditivity (product form) -/ +/-! ### Strong subadditivity -/ variable {A B C : Type*} [Fintype A] [DecidableEq A] [Fintype B] [DecidableEq B] [Fintype C] [DecidableEq C] -/-- **Strong subadditivity (product form, positive definite case).** For a positive definite +/-- **Strong subadditivity (positive definite case).** For a positive definite density matrix `ρ` on `A × B × C`, with all four marginals positive definite, `S(ρ) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC)`. -/ -private lemma vonNeumannEntropy_SSA_product_posDef +private lemma vonNeumannEntropy_SSA_posDef (ρ_ABC : DensityMatrix (A × B × C)) (ρ_A : DensityMatrix A) (ρ_AB : DensityMatrix (A × B)) (ρ_BC : DensityMatrix (B × C)) (ρ_B : DensityMatrix B) @@ -141,7 +141,7 @@ private lemma vonNeumannEntropy_SSA_product_posDef have h_tr1 : tr₁(ρ_ABC.toMatrix) = ρ_BC.toMatrix := by rw [hρ_BC, ptLeft_toMatrix]; exact partialTrace_prodComm_eq_traceLeft ρ_ABC.toMatrix have h_id1 : D(ρ_ABC ∥ ρ_A ⊗ ρ_BC) = -S(ρ_ABC) + S(ρ_A) + S(ρ_BC) := - Matrix.relativeEntropy_kronecker_marginals_product ρ_ABC ρ_A hA ρ_BC hBC h_tr2 h_tr1 + Matrix.relativeEntropy_kronecker_marginals ρ_ABC ρ_A hA ρ_BC hBC h_tr2 h_tr1 -- Mutual-information identity for the `(A : B)` split of `ρ_AB`. have h_tr2' : tr₂(ρ_AB.toMatrix) = ρ_A.toMatrix := by rw [hρ_AB, hρ_A, ptRight_toMatrix, ptRight_toMatrix, DensityMatrix.mapEquiv_toMatrix, @@ -152,7 +152,7 @@ private lemma vonNeumannEntropy_SSA_product_posDef DensityMatrix.mapEquiv_toMatrix, partialTrace_prodComm_eq_traceLeft] exact traceLeft_traceRight_submatrix_prodAssoc ρ_ABC.toMatrix have h_id2 : D(ρ_AB ∥ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B) := - Matrix.relativeEntropy_kronecker_marginals_product ρ_AB ρ_A hA ρ_B hB h_tr2' h_tr1' + Matrix.relativeEntropy_kronecker_marginals ρ_AB ρ_A hA ρ_B hB h_tr2' h_tr1' -- Data-processing inequality for the trace-out-`C` channel. set Φ := Matrix.QuantumChannel.traceOutC (A := A) (B := B) (C := C) with hΦ have h_Φρ_ABC : Φ ρ_ABC = ρ_AB := by @@ -228,10 +228,10 @@ lemma ptLeft_regularize {X Y : Type*} [Fintype X] [DecidableEq X] [Nonempty X] ptLeft_toMatrix, ← Matrix.partialTraceLeftₗ_apply, map_add, map_smul, map_smul, Matrix.partialTraceLeftₗ_apply, Matrix.partialTraceLeftₗ_apply, traceLeft_maximallyMixed] -/-- **Strong subadditivity (product form).** For any density matrix `ρ` on `A × B × C`, +/-- **Strong subadditivity.** For any density matrix `ρ` on `A × B × C`, `S(ρ) + S(ρ_B) ≤ S(ρ_AB) + S(ρ_BC)`. Obtained from the positive-definite case by regularisation and a limit. -/ -theorem vonNeumannEntropy_SSA_product [Nonempty A] [Nonempty B] [Nonempty C] +theorem vonNeumannEntropy_SSA [Nonempty A] [Nonempty B] [Nonempty C] (ρ_ABC : DensityMatrix (A × B × C)) (ρ_AB : DensityMatrix (A × B)) (ρ_BC : DensityMatrix (B × C)) (ρ_B : DensityMatrix B) (h_AB : ρ_AB = (ρ_ABC.mapEquiv (Equiv.prodAssoc A B C)).ptRight) @@ -258,7 +258,7 @@ theorem vonNeumannEntropy_SSA_product [Nonempty A] [Nonempty B] [Nonempty C] have hB_pos : ((DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptLeft.ptRight).toMatrix.PosDef := by rw [ptLeft_regularize, ptRight_regularize]; exact DensityMatrix.regularize_posDef _ hε_pos hε_le - have h_ssa := vonNeumannEntropy_SSA_product_posDef + have h_ssa := vonNeumannEntropy_SSA_posDef (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le) _ _ _ _ rfl rfl rfl rfl hA_pos hBC_pos hB_pos rw [show (DensityMatrix.regularize ρ_ABC hε_pos.le hε_le).ptLeft.ptRight From 512e352aa1c89387fbde7f98debf827ce24f5256 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 18:11:55 +0000 Subject: [PATCH 031/113] chore: remove junk file --- goals.yaml | 120 ----------------------------------------------------- 1 file changed, 120 deletions(-) delete mode 100644 goals.yaml diff --git a/goals.yaml b/goals.yaml deleted file mode 100644 index 36b19f2..0000000 --- a/goals.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# Formalization targets for QuantumSystem. -# -# `declarations` is the **truth source**: each goal is satisfied iff every -# fully-qualified Lean name in `declarations` exists in the project's Lean -# tree. Run with: -# -# python3 .claude/skills/gap-filler/scripts/detect_gaps.py \ -# references/ --goals goals.yaml --lean-root QuantumSystem \ -# --output references/gaps.json -# -# `concepts` is **informational**: it lists the prerequisite knowledge a -# goal depends on. `gap-filler` uses these hints to plan ingestions but -# they do not affect goal satisfaction. Each concept may be a bare string -# (any references//INDEX.md mentioning it counts) or a structured -# entry that pins it to specific slugs and/or section anchors. - -goals: - - id: gelfand-naimark-theorem - description: >- - Every (possibly non-unital) C*-algebra embeds isometrically as a - *-subalgebra of B(H), realized as a direct sum of GNS reps. - declarations: - - gelfand_naimark_theorem - - GNS.DirectSum.directSumAlgHom_injective - - GNS.DirectSum.directSumAlgHom_isometry - concepts: - - name: GNS representation - sources: - - { slug: "92737", anchor: { definition: GNSRepresentation } } - - - id: gns-construction - description: >- - Cyclic representation (π_ω, H_ω, Ω_ω) with - ω(a) = ⟨Ω_ω, π_ω(a) Ω_ω⟩ for any state ω on a C*-algebra. - declarations: - - GNS.Representation - - GNS.Representation.unique_up_to_unitary_equivalence - - GNS.Construction.isFaithful_iff_separating - concepts: - - name: GNS representation - sources: - - { slug: "92737", anchor: { definition: GNSRepresentation } } - - - id: von-neumann-bicommutant - description: >- - Hard half of the bicommutant theorem: every WOT-closed (or - SOT-closed) unital *-subalgebra A of B(H) equals its double - commutant A″. - declarations: - - WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed - - SOTClosedSubalgebra.doubleCommutant_eq_of_isSOTClosed - - SOTClosedSubalgebra.isWOTClosed_of_isSOTClosed_starSubalgebra - - - id: von-neumann-entropy - description: >- - S(ρ) = −Tr(ρ log ρ) on finite-dimensional density matrices, plus - non-negativity, the dimension bound S(ρ) ≤ log(dim), and concavity - in ρ. - declarations: - - Matrix.vonNeumannEntropy - - Matrix.vonNeumannEntropy_nonneg - - Matrix.vonNeumannEntropy_le_log_dim - - Matrix.vonNeumannEntropy_concave - - - id: umegaki-relative-entropy - description: >- - Umegaki relative entropy D(ρ‖σ) = Tr ρ (log ρ − log σ) on EReal - so non-overlapping support is admitted as +∞. - declarations: - - Matrix.relativeEntropy - - Matrix.relativeEntropy_nonneg - - Matrix.relativeEntropy_eq_zero_iff - - - id: strong-subadditivity-region-explicit - description: >- - S(ρ_AB) + S(ρ_BC) ≥ S(ρ_ABC) + S(ρ_B) for tripartite finite - tensor products. Currently region-explicit on a fixed `LocalNet` - with concrete Finset regions. - declarations: - - DensityMatrix.vonNeumannEntropy_SSA - concepts: - - name: localNet - sources: - - { slug: "92737", anchor: { definition: localNet } } - - Lieb concavity - - - id: lieb-concavity - description: >- - Joint concavity of (A, B) ↦ Tr(A^p K† B^(1−p) K) on positive - semidefinite matrices for 0 ≤ p ≤ 1 (Effros' matrix-convex - argument). - declarations: - - Matrix.lieb_joint_concavity_semidef - - Matrix.lieb_joint_concavity_rect_semidef - - # Open TODO surfaced in the README itself. - - id: strong-subadditivity-abstract-local-net - description: >- - TODO. Abstract SSA over a generic local net of algebras (currently - only the region-explicit form is formalized). - declarations: [] - concepts: - - name: localNet - sources: - - { slug: "92737", anchor: { definition: localNet } } - - name: quasiLocalAlgebra - sources: - - { slug: "92737", anchor: { definition: quasiLocalAlgebra } } - - name: local algebra A(O) - sources: - - { slug: arxiv-2507.00900, anchor: { section: "1.2" } } - - name: Tomita-Takesaki modular operator - sources: - - { slug: arxiv-2507.00900, anchor: { section: "2.1" } } - - name: KMS condition - sources: - - { slug: arxiv-2507.00900, anchor: { section: "2.1" } } - - name: Araki-Uhlmann relative entropy - sources: - - { slug: arxiv-2507.00900, anchor: { section: "2.4" } } From c12df3fd88a03e82b7a340a351cb11ea747067a1 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 18:19:34 +0000 Subject: [PATCH 032/113] feat: remove skills --- .claude/skills/gap-filler/SKILL.md | 313 ---- .../skills/gap-filler/references/workflow.md | 336 ----- .../skills/gap-filler/scripts/detect_gaps.py | 1319 ----------------- .claude/skills/gap-filler/scripts/issues.py | 401 ----- .../gap-filler/scripts/rank_bibliography.py | 465 ------ .../skills/paper-notation-refactor/SKILL.md | 324 ---- .../references/notation-map.md | 396 ----- .claude/skills/pdf-to-knowledge/SKILL.md | 347 ----- .../skills/pdf-to-knowledge/hooks/README.md | 88 -- .../pdf-to-knowledge/hooks/on_index_change.py | 132 -- .../references/output-format.md | 207 --- .../pdf-to-knowledge/scripts/convert.py | 397 ----- .../scripts/update_concepts.py | 344 ----- .../scripts/verify_mathlib_refs.py | 576 ------- .claude/skills/web-to-knowledge/SKILL.md | 207 --- .../references/output-format.md | 119 -- .../skills/web-to-knowledge/scripts/fetch.py | 481 ------ 17 files changed, 6452 deletions(-) delete mode 100644 .claude/skills/gap-filler/SKILL.md delete mode 100644 .claude/skills/gap-filler/references/workflow.md delete mode 100644 .claude/skills/gap-filler/scripts/detect_gaps.py delete mode 100644 .claude/skills/gap-filler/scripts/issues.py delete mode 100644 .claude/skills/gap-filler/scripts/rank_bibliography.py delete mode 100644 .claude/skills/paper-notation-refactor/SKILL.md delete mode 100644 .claude/skills/paper-notation-refactor/references/notation-map.md delete mode 100644 .claude/skills/pdf-to-knowledge/SKILL.md delete mode 100644 .claude/skills/pdf-to-knowledge/hooks/README.md delete mode 100644 .claude/skills/pdf-to-knowledge/hooks/on_index_change.py delete mode 100644 .claude/skills/pdf-to-knowledge/references/output-format.md delete mode 100755 .claude/skills/pdf-to-knowledge/scripts/convert.py delete mode 100755 .claude/skills/pdf-to-knowledge/scripts/update_concepts.py delete mode 100644 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py delete mode 100644 .claude/skills/web-to-knowledge/SKILL.md delete mode 100644 .claude/skills/web-to-knowledge/references/output-format.md delete mode 100755 .claude/skills/web-to-knowledge/scripts/fetch.py diff --git a/.claude/skills/gap-filler/SKILL.md b/.claude/skills/gap-filler/SKILL.md deleted file mode 100644 index 8ac64a3..0000000 --- a/.claude/skills/gap-filler/SKILL.md +++ /dev/null @@ -1,313 +0,0 @@ ---- -name: gap-filler -description: Recursively expand `references/` to cover the prerequisites of a formalization goal. Use this skill whenever the user asks to "fill the gaps", "find prerequisite knowledge", "expand references", "follow citations", "plan a formalization", or says they need to know what is still missing to formalize a topic in Lean 4. Given an existing ingested paper (slug) or a goal description, this skill identifies concepts that are still `→ needs formalization`, ranks the paper's bibliography by in-text centrality, and proposes which sources to ingest next via pdf-to-knowledge (PDFs, arxiv) or web-to-knowledge (Wikipedia, nLab). Do NOT invoke for a single-source ingestion request — those go directly to pdf-to-knowledge or web-to-knowledge. Trigger even when the user does not explicitly say "gap" — e.g. "what else do I need to ingest for Araki relative entropy?" should trigger. ---- - -# gap-filler - -Turn a formalization goal into a bounded recursive ingestion plan and, -with user approval, execute it. Orchestrates the existing -`pdf-to-knowledge` and `web-to-knowledge` skills. - -## When to invoke - -- The user references an already-ingested slug and asks what else is - needed: "for the Araki paper I just ingested, what's still missing - before I can formalize relative entropy?". -- The user states a formalization goal and wants a plan: "plan the - ingestion to cover the prerequisites of Araki's relative entropy". -- The user wants to "follow the citations" of an ingested paper to pull - in the most-cited references. - -Do **not** invoke for: - -- A single PDF / URL ingestion (use the source-specific skill). -- A purely literature-review question with no Lean formalisation - angle — this skill's mathlib annotation loop makes it Lean-specific. - -## Output contract - -The skill does not write a new standalone directory. Instead it: - -1. Writes a `references/gaps.json` — machine-readable snapshot of the - current gap situation (resolved / gaps / ambiguous / other_knowledge - counts per concept). -2. Writes a `references//bibliography-ranked.json` — ordered list of - bibliography entries by in-text citation centrality, with `ingested` - flags and any arxiv / doi IDs surfaced. -3. Optionally triggers `pdf-to-knowledge` or `web-to-knowledge` to ingest - top-ranked gaps, then re-runs the concept index and re-scores. - -Both JSON files are regenerated on each invocation; they are safe to -commit if you want audit history, or to `.gitignore` for ephemeral runs. - -## Workflow - -1. **Identify the target.** Pull from the user's message one of: - - A slug that exists under `references/` (e.g. `arxiv-2202.03357`). - - A short goal description (e.g. "formalize Araki's relative - entropy in Lean 4") — in this case ask which existing slug is the - canonical source, and if none, suggest running `pdf-to-knowledge` - first. - -2. **Detect gaps.** - ```bash - python3 .claude/skills/gap-filler/scripts/detect_gaps.py \ - references/ --target-slug --output references/gaps.json - ``` - - When the project has a `goals.yaml` (a fixed list of formalization - targets — see "Side channels" below), pass - `--goals goals.yaml --lean-root ` so the report adds - per-goal status verified against the actual Lean declarations, plus - `goal_coverage_score = verified_declarations / total_declarations`. - The plain `coverage_score` keeps its meaning ("ingestion-wide - knowledge coverage"); use whichever the user asked for. Both can - appear in the same report. - The report lists every Key concepts bullet's status across all - ingested slugs: - - `formalized` — at least one source annotated - `→ formalized: QuantumSystem.X.y` (a local proof in this repo) and - `verify_mathlib_refs.py` did not flag it. Strongest tier; outranks - `resolved` because a local proof is harder evidence than a mathlib - match. - - `resolved` — at least one source annotated `→ mathlib: ...` and - `verify_mathlib_refs.py` did not flag it as `[UNVERIFIED]`. - - `suspect` — a source annotated `→ mathlib: ...` but - `verify_mathlib_refs.py` (run as part of pdf-to-knowledge / - web-to-knowledge step 4g / 6) could not confirm the declaration - exists — the annotation has an `[UNVERIFIED]` marker. Treat as a - stronger signal than `gap`: **the previous search was a false - positive** and the concept needs either a corrected annotation or - genuine formalisation. - - `partial` — target slug still annotates `→ needs formalization`, - but another ingested slug discusses the concept (e.g. a - Wikipedia / nLab page). Locally readable even though mathlib - lacks it. Often the most cost-effective tier to prioritise next. - - `gap` — target slug annotates `→ needs formalization` and no - other slug documents the concept. This is where future recursive - ingestion should focus. - - `ambiguous` — no annotation (rarely happens if previous - ingestions followed the SKILL.md contract). - - `other_knowledge` — concepts coming from non-target slugs (may - still be useful prerequisites). Its `status` field uses the - strongest available source-tier vocabulary (`formalized`, - `resolved`, `suspect`, `gap`, or `ambiguous`), including `suspect` - when the only known annotation is an `[UNVERIFIED]` false positive. - - When `--goals` is enabled, the goal block introduces two more status - vocabularies: - - goal-concept `status` may also be `unknown` — the concept was - pinned to specific `sources[*].slug` entries, but none of those - slugs currently document it. - - goal `goal_status` is one of `satisfied`, `partially_satisfied`, - `missing`, or `unverified`. - - Concept-name matching is normalised aggressively: `Connes cocycle`, - `Connes.cocycle`, `ConnesCocycle`, and `connes-cocycle` all merge. - camelCase / PascalCase identifiers are split on case transitions, - then lowercased and punctuation-stripped. - - The report also exposes `coverage_score`, a single 0..1 number - equal to - `(formalized × 1.0 + resolved × 1.0 + partial × 0.5) / target_total`. - Use this as the headline progress metric when reporting to the user — - it captures "local proof + mathlib coverage + local-reference - coverage" in one figure, so an ingestion that adds 3 Wikipedia pages - moves the number even when `formalized` and `resolved` stay flat. - -3. **Rank the target's bibliography by centrality.** - ```bash - python3 .claude/skills/gap-filler/scripts/rank_bibliography.py \ - references// --output references//bibliography-ranked.json - ``` - The ranking counts how many times each bibliography key is cited in - `content.md`, weighting the first 30 % of the body double (i.e. - abstract / intro / early theorems count more than late appendices). - Already-ingested entries (`ingested: true`) go to the back. - - For each **uninvested entry without arxiv / DOI** — the common case - for operator algebra, older physics and pre-2000 math — the script - also emits `suggested_search_queries`. The ordering switches on - publication year (`year >= 1995` favours university-domain PDFs; - `year < 1995` favours `lecture-notes` + NUMDAM / Project Euclid). - See [./references/workflow.md](./references/workflow.md) for the - calibration story and a concrete sample of the emitted queries. - -4. **Synthesise a plan.** Read both JSON files and compose a **short - ingestion plan**: - - a. For each gap concept, decide a primary source in this order: - - 1. **arxiv / DOI in the bibliography** — top of the ranked list - with a discoverable URL → `pdf-to-knowledge`. - 2. **University lecture-notes PDF** — when the entry has no arxiv - ID but the topic is covered in standard graduate curricula - (subfactor theory, modular theory, KMS states, entropy - inequalities). Feed the `suggested_search_queries` to - `WebSearch`, pick the most reputable PDF hit (faculty page > - course page > personal blog), hand it to `pdf-to-knowledge`. - For math-heavy gaps lecture notes usually beat Wikipedia - (single author, coherent notation); see - [./references/workflow.md](./references/workflow.md) for the - comparison. - 3. **Wikipedia / nLab** — good for broadly-known math - (`Von_Neumann_entropy`, `Tomita–Takesaki_theory`) and as a - zero-effort fallback when the lecture-notes search returns - nothing → `web-to-knowledge`. - 4. **Needs human action** — no URL discoverable via the above; - ask the user. - - b. **Bound the plan**. By default pick at most 3 ingestions per - invocation to avoid runaway recursion. Increase only when the user - explicitly opts in. - c. Present the plan to the user before executing — list the 3 - proposed ingestions with their rationale (gap they close, citation - score if applicable, source type, URL found via which search - strategy). - -5. **Execute (with user OK).** For each approved entry in the plan: - - If the source is an arxiv ID: invoke `pdf-to-knowledge` with - `https://arxiv.org/pdf/`. - - If the source is a DOI with a direct open PDF URL, or an open-access - publisher PDF URL discovered from that DOI: invoke `pdf-to-knowledge` - with the PDF URL. If only a DOI landing page is available, ask before - using a weaker HTML fallback. - - If the source is a discovered university / course / faculty PDF URL: - invoke `pdf-to-knowledge` with that PDF URL. - - If the source is a Wikipedia / nLab URL: invoke - `web-to-knowledge` with that URL. - - After **each** ingestion, re-run - `python3 .claude/skills/pdf-to-knowledge/scripts/update_concepts.py references/` - so `CONCEPTS.md` and downstream diagnostics stay consistent. - -6. **Re-measure and report.** Re-run step 2 to produce a new - `gaps.json`, then report the delta to the user: how many gaps closed, - how many remain, which ones might require a different source type. - Do not loop automatically — hand control back to the user and wait - for them to approve another round. - -## Side channels - -Three optional outputs that complement `gaps.json`. Every one has a -worked example in [./references/workflow.md](./references/workflow.md); -the summary below gives just the contract. - -- **`references/gaps-history.jsonl`** — append-only JSONL, one record per - `detect_gaps.py` run with `timestamp / coverage_score / - goal_coverage_score / counts / issues_open`. Use it to attribute - progress to specific ingestions. `--no-history` suppresses; - `--history-log ` redirects. - -- **`references/issues/*.yaml`** — file-system tracker for items the - pipeline could not auto-resolve (`[UNVERIFIED]` mathlib refs, skipped - notation candidates, open questions). `verify_mathlib_refs.py - mark-unverified` opens these automatically (idempotent on - `kind + slug + concept + candidate`); manual ones go through - `scripts/issues.py {add,list,close}`. `detect_gaps.py` reports - `issues.open` in its summary. - -- **`goals.yaml`** (project root, checked into git) — pins the - formalization targets so the headline metric tracks "what we promised - to prove", not "what we happened to ingest". Pass - `--goals goals.yaml --lean-root ` to `detect_gaps.py`. - - **Truth source = `declarations`.** Each goal lists fully-qualified - Lean declaration names (`Matrix.vonNeumannEntropy_nonneg`, - `gelfand_naimark_theorem`, …). The script walks `/**/*.lean`, - builds the set of every `theorem`/`def`/`structure`/`class`/ - `instance`/`inductive`/`abbrev`/`axiom` (tracking `namespace`/`end` - stacks), and compares. Verified ⇒ goal counted toward - `goal_coverage_score`. Without `--lean-root`, declarations are - reported as `unverified` (no guess). - - Malformed goal entries are a hard error, not a soft fallback: missing - `id` / `description`, non-list `declarations` / `concepts`, or a - structured `sources:` entry without a `slug` makes `detect_gaps.py` - exit 2 with an `[error] invalid goals file: ...` message. - - **`concepts` is informational** — prerequisite knowledge hints used - by `gap-filler`'s plan output, not by the satisfaction judgement. A - concept may be a bare string (any INDEX.md mentioning it counts) or - a structured entry pinning the prerequisite to specific slugs and - optional anchors: - - ```yaml - goals: - - id: gns-construction - description: "Cyclic representation π_ω …" - declarations: - - GNS.Representation - - GNS.Construction.isFaithful_iff_separating - concepts: - - GNS representation # bare string - - name: Tomita-Takesaki modular operator # structured - sources: - - { slug: arxiv-2507.00900, anchor: { theorem: "2.3" } } - - { slug: "92737", anchor: { definition: "modular operator" } } - - - id: ssa-abstract-local-net - description: "TODO." - declarations: [] # → counts as 1 missing - concepts: - - name: localNet - sources: - - { slug: "92737" } - ``` - - `anchor` is a single-key map keyed by the locator kind - (`chapter` / `section` / `subsection` / `theorem` / `definition` / - `lemma` / `proposition` / `corollary` / `equation` / `page` / - `example`). It is human-readable navigation; the matcher only uses - `slug` for filtering. - - **Coverage formula.** `goal_coverage_score = - verified_declarations / total_declarations`, where a goal with - `declarations: []` contributes 1 to the denominator (an unfulfilled - TODO slot, so the score does not silently inflate). - -## Why this design - -- **Bounded, user-visible plan.** Gap-filling has blast radius (each - ingestion is multi-minute CPU work plus disk space). Showing the 3 - proposed sources before executing lets the user redirect instead of - burning compute on the wrong path. -- **Citation centrality, not just "first in list".** The original user - request specifically called out the heuristic: *"引用数の上位や参考 - アイデアと引用位置の近さ"* — we implement both via the weighted - count in `rank_bibliography.py`. -- **Reuse existing skills.** The recursion engine is Claude-orchestrated - markdown, not a new binary. Adding a source type = teaching Claude to - dispatch to a different sibling skill, not rewriting a DAG. -- **Concept index is the ground truth.** `CONCEPTS.md` already unifies - PDF and web sources. Every script here reads from that layer rather - than re-parsing raw papers. - -## Runtime prerequisites - -- **Sibling skills available.** `pdf-to-knowledge` and - `web-to-knowledge` must be installed under `.claude/skills/` with - their own dependencies in place. This skill does not re-implement - their work. -- **`uv`** on PATH (same reason as the sibling skills). -- No other Python deps — the scripts here use stdlib only. - -## Failure modes to watch for - -- **Bibliography is empty or absent.** The target slug's INDEX.md was - ingested before bibliography extraction was added, or the paper had - no `## References`. In that case `rank_bibliography.py` returns an - empty list; pivot to web sources for the identified gaps. -- **Every top-ranked entry lacks a discoverable URL.** Older math papers - cite each other in print journals. If none of the top entries have - arxiv / doi, the skill should suggest a Wikipedia article on the - concept instead of forcing the user to chase a hard-to-find PDF. -- **Recursive cycles.** If paper A cites paper B and B cites A, the - default budget of 3 ingestions / round prevents a loop. -- **Goal outside the current references set.** If the user provides a - goal string with no matching slug, instruct them to run - `pdf-to-knowledge` on a primary source first, then come back here. - -See [./references/workflow.md](./references/workflow.md) for a worked -example on the Araki relative-entropy paper, including the expected -`gaps.json` output and a sample 3-step ingestion plan. diff --git a/.claude/skills/gap-filler/references/workflow.md b/.claude/skills/gap-filler/references/workflow.md deleted file mode 100644 index e1ea785..0000000 --- a/.claude/skills/gap-filler/references/workflow.md +++ /dev/null @@ -1,336 +0,0 @@ -# gap-filler workflow — worked example - -Concrete trace of running the skill on the Araki / Longo-Witten paper -(`arxiv-2202.03357`) from `references/` in this project. Use this as a -reference when you need to calibrate expectations against the synthetic -behaviour described in `SKILL.md`. - -## Starting state - -``` -references/ -├── CONCEPTS.md # aggregated concept index -├── arxiv-2202.03357/ -│ ├── INDEX.md # Longo–Witten "A note on continuous entropy" -│ ├── content.md # MinerU output with 184 LaTeX spans -│ └── assets/ # empty (no figures) -``` - -INDEX.md has 14–22 Key concepts bullets (varies across iterations) and a -bibliography of ~24 entries with author-year keys (Ara76, Kos86a, Tak03, -Wit21, …). - -## 0. Optional: pin formalization targets (`goals.yaml`) - -Without a goals file, `coverage_score` reports knowledge ingestion -coverage (does mathlib have a home for the concepts mentioned in -ingested papers?). To track *project-level* progress — "have we -proven the theorems we promised?" — anchor on a `goals.yaml` listing -**the actual Lean declarations** that constitute each promise: - -```yaml -goals: - - id: gns-construction - description: "Cyclic representation π_ω with ω(a)=⟨Ω_ω, π_ω(a) Ω_ω⟩." - declarations: - - GNS.Representation - - GNS.Construction.isFaithful_iff_separating - - GNS.Representation.unique_up_to_unitary_equivalence - concepts: - - GNS representation # bare string - - - id: ssa-abstract-local-net - description: "TODO. Abstract SSA over a generic local net." - declarations: [] # empty → counts as 1 missing - concepts: - - name: localNet - sources: - - { slug: "92737", anchor: { definition: "localNet" } } - - name: Tomita-Takesaki modular operator - sources: - - { slug: arxiv-2507.00900, anchor: { theorem: "2.3" } } - - { slug: arxiv-2507.00900, anchor: { section: "2.1" } } -``` - -**Two parallel concerns**, kept separate so each is judged by the -right tool: - -| Field | Truth source | Influences `goal_coverage_score`? | -| --- | --- | --- | -| `declarations` | scanner over `/**/*.lean` | **yes** | -| `concepts` | `references//INDEX.md` Key concepts bullets | no — pure hint for `gap-filler` planning | - -`anchor` is a single-key map; the supported kinds are `chapter`, -`section`, `subsection`, `theorem`, `definition`, `lemma`, -`proposition`, `corollary`, `equation`, `page`, `example`. The -matcher uses only `slug` for filtering — the kind/value pair is -human-readable navigation so a developer (or `gap-filler`'s plan -output) knows exactly which page to consult. - -Pass `--goals goals.yaml --lean-root QuantumSystem` (or whatever your -Lean tree is) to step 1 to get the per-goal block. Without -`--lean-root`, declarations are tagged `unverified` rather than -guessed — `goal_coverage_score` then reads as the absence of evidence. - -## 1. Detect gaps - -```bash -python3 .claude/skills/gap-filler/scripts/detect_gaps.py \ - references/ --target-slug arxiv-2202.03357 --output references/gaps.json -``` - -Expected shape of `gaps.json` (truncated): - -```json -{ - "target_slug": "arxiv-2202.03357", - "counts": { - "formalized": 1, - "resolved": 2, - "partial": 0, - "suspect": 1, - "gaps": 10, - "ambiguous": 0, - "other_knowledge": 0 - }, - "issues": {"open": 1, "directory": "references/issues"}, - "coverage_score": 0.214, - "formalized": [ - {"concept": "Umegaki relative entropy", "sources": [...], - "formalized_annotation": "→ formalized: QuantumSystem.RelativeEntropy.umegaki"} - ], - "resolved": [ - {"concept": "C*-algebra", - "mathlib_annotation": "→ mathlib: Mathlib.Analysis.CStarAlgebra.Classes", - "sources": [{"slug": "arxiv-2202.03357", "annotation": "..."}]} - ], - "suspect": [ - {"concept": "Modular automorphism group", - "mathlib_annotation": "→ mathlib: Mathlib.Foo.Bar [UNVERIFIED] (...)", - "sources": [...]} - ], - "gaps": [ - {"concept": "Araki relative entropy", "sources": [...]}, - {"concept": "Kosaki variational formula", "sources": [...]}, - {"concept": "Jones index", "sources": [...]} - ] -} -``` - -With `--goals goals.yaml --lean-root QuantumSystem` the report also -carries: - -```json -{ - "lean_root": "/abs/path/QuantumSystem", - "lean_declarations_count": 714, - "goals_summary": { - "total": 8, - "satisfied": 7, - "partially_satisfied": 0, - "missing": 1, - "unverified": 0, - "declarations_total": 20, - "declarations_verified": 19, - "goal_coverage_score": 0.95, - "formula": "verified_declarations / total_declarations" - }, - "goals": [ - {"id": "gns-construction", - "goal_status": "satisfied", - "declarations": [ - {"name": "GNS.Representation", "status": "verified"}, - {"name": "GNS.Construction.isFaithful_iff_separating", "status": "verified"} - ], - "missing_declarations": [], - "concepts": [{"name": "GNS representation", - "status": "gap", - "matched_sources": [{"slug": "92737", "annotation": "..."}]}]}, - {"id": "ssa-abstract-local-net", - "goal_status": "missing", - "declarations": [], - "missing_declarations": [], - "missing_concepts": ["Tomita-Takesaki modular operator"]} - ] -} -``` - -The TODO goal contributes 1 to `declarations_total` (so empty -`declarations: []` does not silently inflate the score) but 0 to -`declarations_verified`. - -## 2. Rank the bibliography - -```bash -python3 .claude/skills/gap-filler/scripts/rank_bibliography.py \ - references/arxiv-2202.03357/ \ - --output references/arxiv-2202.03357/bibliography-ranked.json -``` - -Expected top of `uninvested_top` (abridged; each entry now also carries -a `suggested_search_queries` list). **Query ordering depends on the -entry's publication year**: - -- ``year >= 1995`` (modern): `university-pdf:` rotation is listed - first (faculty pages often host the paper or author's lecture notes), - then `lecture-notes`, then `nlab`/`wikipedia`. -- ``year < 1995`` (legacy): `lecture-notes` leads, followed by the - open-access archives `numdam` and `projecteuclid` and a bare - `filetype:pdf` pass. University-PDF rotation is **demoted to the - tail** — iteration-2 showed university domains almost never host - 1980s-era operator-algebra journal papers, so burning WebSearch - budget on them first is wasteful. - -The cutoff is empirical (1995 ≈ onset of institutional preprint -hosting) and editable in -`gap-filler/scripts/rank_bibliography.py::PRE_INSTITUTIONAL_HOSTING_YEAR`. -When `year` is absent from the bibliography entry, the modern ordering -is used as a safe default. - -```json -[ - { - "key": "Jon83", "title": "Index for subfactors", - "authors": ["Vaughan Jones"], "year": 1983, - "arxiv": null, "doi": null, "ingested": false, - "citations_raw": 13, "citation_score": 19.0, - "matched_token": "Jon83", - "suggested_search_queries": [ - {"strategy": "lecture-notes", - "query": "Index subfactors Jones \"lecture notes\" filetype:pdf"}, - {"strategy": "numdam", - "query": "Index subfactors Jones site:numdam.org"}, - {"strategy": "project-euclid", - "query": "Index subfactors Jones site:projecteuclid.org"}, - {"strategy": "open-access-pdf", - "query": "Index subfactors Jones filetype:pdf"}, - {"strategy": "nlab", "query": "Index subfactors site:ncatlab.org"}, - {"strategy": "wikipedia", "query": "Index subfactors wikipedia"}, - {"strategy": "university-pdf:caltech.edu", - "query": "Index subfactors Jones pdf site:caltech.edu"} - ] - } -] -``` - -## 3. Synthesise a plan - -Cross-reference gaps with the ranked bibliography. **When a top entry has -no arxiv/DOI (the common case for operator algebra), try its -`suggested_search_queries` with WebSearch before falling back to -Wikipedia**. For legacy entries this means lecture notes / open-access -archives first; for modern entries it means faculty-hosted PDFs first. -Both routes usually give a cleaner treatment than encyclopedia pages: - -| Gap | Best source (preferred) | Mechanism | -|---|---|---| -| `Jones index` (Jon83) | lecture-notes PDF or open-access archive (try `lecture-notes` → `numdam` → `project-euclid` via the emitted queries) | `pdf-to-knowledge` once a PDF URL is found | -| `Kosaki variational formula` (Kos86a) | lecture-notes / open-access PDF first, nLab as fallback | `pdf-to-knowledge` or `web-to-knowledge` depending on what turns up | -| `Modular operator` / `Tomita-Takesaki` (Tak03) | Wikipedia is fine here — it is a well-maintained article | `web-to-knowledge` | - -Fall back to Wikipedia / nLab only when the PDF / archive search finds -nothing relevant. The trade-off: WebSearch costs a few tool calls per -concept, but the resulting PDFs tend to carry definitions, proofs, and -worked examples in one place — far more useful than stitching together -a Wikipedia stub plus scattered nLab entries. - -A typical plan covers the 3 gaps with the highest intersection of -"blocks many other concepts" and "has a discoverable URL" — the three -rows above. - -## 4. Execute (with user approval) - -For the first two entries, call `web-to-knowledge`: - -```bash -uv run .claude/skills/web-to-knowledge/scripts/fetch.py \ - "https://en.wikipedia.org/wiki/Tomita%E2%80%93Takesaki_theory" -uv run .claude/skills/web-to-knowledge/scripts/fetch.py \ - "https://ncatlab.org/nlab/show/relative+entropy" -``` - -Then **always** refresh the concept index: - -```bash -python3 .claude/skills/pdf-to-knowledge/scripts/update_concepts.py references/ -``` - -## 5. Re-measure - -Run step 1 again. Expected delta: - -- `resolved` grows by any concepts that now carry a `→ mathlib:` - annotation on the freshly ingested INDEX.md (Wikipedia Tomita-Takesaki - typically resolves `VonNeumannAlgebra.commutant`; nLab relative - entropy resolves `InformationTheory.klDiv`, `MeasureTheory.rnDeriv`). -- `gaps` shrinks by the resolved count. -- `other_knowledge` grows — bullets from the new slugs that the target - paper does not mention directly but which supplement the topic. - -## Side channel — issue tracker (`references/issues/`) - -When `verify_mathlib_refs.py mark-unverified` flags a bullet, it -auto-creates a YAML under `references/issues/` so the false positive is -not forgotten across sessions. Re-running the same loop is a no-op (the -dedup key is `kind + slug + concept + candidate`): - -```bash -# Manually open an issue (e.g. paper-notation-refactor skipped a candidate) -python3 .claude/skills/gap-filler/scripts/issues.py add references \ - --kind notation-skipped \ - --slug arxiv-2202.03357 \ - --concept "modular automorphism group" \ - --reason "Mathlib scope conflict on σ" - -python3 .claude/skills/gap-filler/scripts/issues.py list references -python3 .claude/skills/gap-filler/scripts/issues.py close references \ - --kind unverified-mathlib-ref --slug arxiv-2202.03357 \ - --closed-by "human review" -``` - -`detect_gaps.py` surfaces `report.issues.open`; treat that count as the -"system already knows about" backlog complementary to `gaps`. A typical -pattern across one ingestion cycle: - -``` -baseline: formalized=1 resolved=1 gap=12 issues=0 cov=0.214 -after lean_verify rejects modular operator: - formalized=1 suspect=1 gap=12 issues=1 cov=0.143 -after notation-refactor adds → formalized: for it: - formalized=2 resolved=0 gap=12 issues=0 cov=0.214 -``` - -Note that the third row's `coverage_score` returns to baseline even -though the underlying state changed — the project just discovered that -mathlib's annotation was wrong and replaced it with a local proof. The -trajectory shows up clearly in the history log. - -## Side channel — progress history (`references/gaps-history.jsonl`) - -Each `detect_gaps.py` run appends one record. Quick way to see what -moved the needle: - -```bash -jq -c '{ts: .timestamp, cov: .coverage_score, goal: .goals.goal_coverage_score, issues: .issues_open, fmlz: .counts.formalized, susp: .counts.suspect}' \ - references/gaps-history.jsonl -``` - -Sample output across a 5-step cycle: - -``` -{"ts":"2026-05-04T10:00:00Z","cov":0.5,"goal":0.667,"issues":0,"fmlz":1,"susp":0} -{"ts":"2026-05-04T10:05:00Z","cov":0.25,"goal":0.333,"issues":1,"fmlz":1,"susp":1} -{"ts":"2026-05-04T10:10:00Z","cov":0.5,"goal":0.667,"issues":0,"fmlz":2,"susp":0} -``` - -Pass `--no-history` to suppress, or `--history-log path/elsewhere.jsonl` -to redirect when the default `references/` tree is gitignored. - -## When to stop - -- `gaps` shrinks to a stable set whose entries are genuinely unformalised - in mathlib (no amount of recursive ingestion helps). -- The only remaining sources lack discoverable URLs (pre-arxiv 1970s - math journals) — promote those to the user as "needs human action". -- The ingestion budget (default 3 per invocation) has been used; ask the - user before approving another round. diff --git a/.claude/skills/gap-filler/scripts/detect_gaps.py b/.claude/skills/gap-filler/scripts/detect_gaps.py deleted file mode 100644 index 26b7904..0000000 --- a/.claude/skills/gap-filler/scripts/detect_gaps.py +++ /dev/null @@ -1,1319 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -"""Scan a ``references/`` tree and report which Key concepts are still gaps. - -A concept is classified by looking at the annotation on its Key concepts -bullet across every ``/INDEX.md`` under the root: - -- ``→ formalized: QuantumSystem.X.y`` → **formalized** (already proven in - this repository — outranks ``resolved`` for prioritisation). -- ``→ mathlib: Mathlib.X.y`` → **resolved** (mathlib already has it). -- ``→ needs formalization`` → **gap** (no mathlib coverage). -- No annotation → **ambiguous** (treat as potential gap). - -Concepts with the same normalised name coming from multiple sources are -merged; the aggregate classification picks the strongest tier present — -``formalized`` beats ``resolved`` beats ``partial`` beats ``gap`` beats -``ambiguous``. ``suspect`` (a mathlib annotation that ``verify_mathlib_refs.py`` -flagged as ``[UNVERIFIED]``) is reported separately so a previously -trusted answer that turned out wrong is more visible than a fresh gap. - -Optionally, ``--goals path/to/goals.yaml`` constrains the coverage score -to a fixed list of target concepts (the project's actual formalization -goals). Without ``--goals`` the universe is "every concept ingested under -references/" — useful for raw progress, but the denominator drifts as -new papers are added. With ``--goals`` the score answers the operative -question: "of the concepts I committed to formalize, what fraction is -done?". Goal concepts not yet present in any INDEX.md are classified as -``unknown`` and counted as gaps for the coverage formula. - -Usage: - python3 detect_gaps.py [--target-slug SLUG] - [--output gaps.json] - -When ``--target-slug`` is given, the output keys `resolved`/`gaps` are -restricted to concepts that originate from that slug's INDEX.md; other -slugs' concepts appear under `other_knowledge` (useful context but not -what the caller is trying to formalise). When omitted, every slug is -treated symmetrically. - -Exits 0 on success. Prints the JSON report to stdout unless ``--output`` -is specified. -""" - -from __future__ import annotations - -import argparse -import datetime as _dt -import json -import re -import sys -from collections import defaultdict -from pathlib import Path - - -KEY_CONCEPTS_HEADER = re.compile(r"^##\s+Key concepts\s*$", re.IGNORECASE) -NEXT_H2 = re.compile(r"^##\s+") -BULLET = re.compile(r"^\s*-\s+(.*)$") -LEADING_CODE = re.compile(r"^`([^`]+)`(.*)$") -MATHLIB_ANNOT = re.compile(r"→\s*mathlib\s*:", re.IGNORECASE) -FORMALIZED_ANNOT = re.compile(r"→\s*formalized\s*:", re.IGNORECASE) -NEEDS_FORMAL_ANNOT = re.compile(r"→\s*needs\s*formalization", re.IGNORECASE) -UNVERIFIED_MARKER = re.compile(r"\[UNVERIFIED\]", re.IGNORECASE) -LEAN_DECL_NAME = re.compile(r"^[A-Za-z_][\w']*(?:\.[A-Za-z_][\w']*)*$") - - -class GoalsValidationError(ValueError): - """Raised when goals.yaml violates the supported contract.""" - - -def _strip_front_annotation_markers(body: str) -> tuple[str, str]: - """Split a Key concepts bullet body into (description, annotation).""" - m = re.search(r"\s*→\s", body) - if not m: - return body.strip(), "" - return body[: m.start()].strip(), body[m.start() :].strip() - - -# LaTeX command → Unicode character. Keeps the merge key stable whether the -# author wrote ``\alpha``, ``α``, or ``alpha``. Longest commands first so -# ``\infty`` beats ``\in`` and ``\Vert`` beats ``\V`` on the ordered walk. -LATEX_TO_UNICODE: dict[str, str] = { - # Greek lowercase (most common). - r"\alpha": "α", r"\beta": "β", r"\gamma": "γ", r"\delta": "δ", - r"\epsilon": "ε", r"\varepsilon": "ε", r"\zeta": "ζ", r"\eta": "η", - r"\theta": "θ", r"\vartheta": "θ", r"\iota": "ι", r"\kappa": "κ", - r"\lambda": "λ", r"\mu": "μ", r"\nu": "ν", r"\xi": "ξ", - r"\pi": "π", r"\varpi": "π", r"\rho": "ρ", r"\varrho": "ρ", - r"\sigma": "σ", r"\varsigma": "σ", r"\tau": "τ", r"\upsilon": "υ", - r"\phi": "φ", r"\varphi": "φ", r"\chi": "χ", r"\psi": "ψ", - r"\omega": "ω", - # Greek uppercase. - r"\Gamma": "Γ", r"\Delta": "Δ", r"\Theta": "Θ", r"\Lambda": "Λ", - r"\Xi": "Ξ", r"\Pi": "Π", r"\Sigma": "Σ", r"\Upsilon": "Υ", - r"\Phi": "Φ", r"\Psi": "Ψ", r"\Omega": "Ω", - # Math symbols the operator-algebra / QFT canon uses constantly. - r"\infty": "∞", - r"\partial": "∂", - r"\nabla": "∇", - r"\mathbb{N}": "ℕ", r"\mathbb{Z}": "ℤ", r"\mathbb{Q}": "ℚ", - r"\mathbb{R}": "ℝ", r"\mathbb{C}": "ℂ", r"\mathbb{H}": "ℍ", - r"\mathbb{F}": "𝔽", r"\mathbb{P}": "ℙ", r"\mathbb{E}": "𝔼", - r"\mathbb{1}": "𝟙", - r"\emptyset": "∅", r"\varnothing": "∅", - r"\hbar": "ℏ", r"\ell": "ℓ", - r"\dagger": "†", r"\star": "⋆", - # Relations / operators often embedded in concept names. - r"\le": "≤", r"\leq": "≤", r"\ge": "≥", r"\geq": "≥", - r"\ne": "≠", r"\neq": "≠", r"\equiv": "≡", - r"\subset": "⊂", r"\subseteq": "⊆", - r"\supset": "⊃", r"\supseteq": "⊇", - r"\in": "∈", r"\notin": "∉", - r"\to": "→", r"\mapsto": "↦", r"\implies": "⇒", - r"\Rightarrow": "⇒", r"\Leftarrow": "⇐", r"\Leftrightarrow": "⇔", - r"\cup": "∪", r"\cap": "∩", r"\setminus": "∖", - r"\times": "×", r"\otimes": "⊗", r"\oplus": "⊕", r"\odot": "⊙", - r"\cdot": "·", - # Norms / brackets commonly mangled across editors. - r"\Vert": "‖", r"\|": "‖", r"\|\|": "‖", - r"\langle": "⟨", r"\rangle": "⟩", - # Spacing commands we just drop. - r"\,": " ", r"\;": " ", r"\:": " ", r"\!": "", r"\~": " ", -} - -# Unicode math symbols → ASCII-ish tokens so ``α`` / ``\alpha`` / ``alpha`` -# all collapse to the same bucket. Applied after LATEX_TO_UNICODE, so it -# normalises both original Unicode text and LaTeX-derived Unicode. -UNICODE_TO_ASCII: dict[str, str] = { - # Greek lowercase. - "α": " alpha ", "β": " beta ", "γ": " gamma ", "δ": " delta ", - "ε": " epsilon ", "ζ": " zeta ", "η": " eta ", "θ": " theta ", - "ι": " iota ", "κ": " kappa ", "λ": " lambda ", "μ": " mu ", - "ν": " nu ", "ξ": " xi ", "π": " pi ", "ρ": " rho ", - "σ": " sigma ", "τ": " tau ", "υ": " upsilon ", "φ": " phi ", - "ϕ": " phi ", "χ": " chi ", "ψ": " psi ", "ω": " omega ", - # Greek uppercase. - "Γ": " gamma ", "Δ": " delta ", "Θ": " theta ", "Λ": " lambda ", - "Ξ": " xi ", "Π": " pi ", "Σ": " sigma ", "Υ": " upsilon ", - "Φ": " phi ", "Ψ": " psi ", "Ω": " omega ", - # Math symbols. - "∞": " infty ", "∂": " partial ", "∇": " nabla ", - "ℕ": " nat ", "ℤ": " int ", "ℚ": " rat ", "ℝ": " real ", - "ℂ": " complex ", "ℍ": " quat ", "𝔽": " field ", "ℙ": " proj ", - "𝔼": " expect ", "𝟙": " one ", - "∅": " empty ", "ℏ": " hbar ", "ℓ": " ell ", - "†": " dagger ", "⋆": " star ", - "≤": " le ", "≥": " ge ", "≠": " ne ", "≡": " equiv ", - "⊂": " subset ", "⊆": " subseteq ", - "⊃": " supset ", "⊇": " supseteq ", - "∈": " in ", "∉": " notin ", - "→": " to ", "↦": " mapsto ", "⇒": " implies ", - "⇐": " leftarrow ", "⇔": " iff ", - "∪": " cup ", "∩": " cap ", "∖": " setminus ", - "×": " times ", "⊗": " otimes ", "⊕": " oplus ", "⊙": " odot ", - "·": " cdot ", - "‖": " norm ", "⟨": " langle ", "⟩": " rangle ", - # Punctuation variants that frequently appear in math identifiers. - "–": "-", "—": "-", # en-dash / em-dash → hyphen -} - -# Sort LaTeX commands by descending length so longer matches win (``\Vert`` -# before ``\V``, ``\mathbb{N}`` before ``\mathbb``). -_LATEX_ORDERED = sorted(LATEX_TO_UNICODE.items(), key=lambda kv: -len(kv[0])) - - -def _expand_latex(text: str) -> str: - r"""Apply ``LATEX_TO_UNICODE`` in a single pass. - - Uses string replacement (not regex) because TeX command boundaries are - semantic: ``\alpha2`` should still replace ``\alpha`` → ``α``, producing - ``α2``. A regex with ``\b`` would miss that because ``\`` is not a word - char to Python's regex engine, but pure substring replacement works. - """ - for command, replacement in _LATEX_ORDERED: - if command in text: - text = text.replace(command, replacement) - return text - - -def _unicode_to_ascii(text: str) -> str: - for symbol, replacement in UNICODE_TO_ASCII.items(): - if symbol in text: - text = text.replace(symbol, replacement) - return text - - -def _normalise_concept(display: str) -> str: - """Aggressive normalisation so concept names with different spellings merge. - - The merge key has to be stable across: - - - camelCase / PascalCase: ``Connes cocycle`` == ``ConnesCocycle`` - - punctuation: ``Connes cocycle`` == ``Connes.cocycle`` == ``connes-cocycle`` - - acronyms: ``TypeIIIFactor`` == ``Type III factor`` - - **LaTeX vs Unicode vs ASCII** (R1, iter-12): - ``Type II_\\infty`` == ``Type II_∞`` == ``Type II_infty`` - ``S(\\phi\\Vert\\psi)`` == ``S(φ‖ψ)`` == ``S(phi norm psi)`` - - Pipeline: - 0. Expand LaTeX commands to Unicode (``\\alpha`` → ``α``). - 1. Collapse Unicode math symbols to ASCII tokens (``α`` → `` alpha ``, - ``‖`` → `` norm ``, ``∞`` → `` infty ``). - 2. Split camelCase / PascalCase boundaries with a space. - 3. Lowercase. - 4. Replace any run of non-alphanumeric characters with a single space. - 5. Collapse whitespace. - """ - tokenised = _expand_latex(display) - tokenised = _unicode_to_ascii(tokenised) - # Split lower→upper (fooBar) and acronym→word (HTTPServer, TypeIIIFactor). - tokenised = re.sub(r"(?<=[a-z0-9])(?=[A-Z])", " ", tokenised) - tokenised = re.sub(r"(?<=[A-Z])(?=[A-Z][a-z])", " ", tokenised) - tokenised = tokenised.lower() - tokenised = re.sub(r"[^a-z0-9]+", " ", tokenised) - return " ".join(tokenised.split()) - - -def parse_key_concepts(md: str) -> list[dict]: - """Yield ``{name, display, description, annotation, status}`` for each bullet. - - ``name`` is aggressively normalised so bullets differing only by - punctuation (``Connes.cocycle`` vs ``Connes cocycle``) or case - (``typeIIIFactor`` vs ``Type III factor``) merge in - ``classify_across_slugs``. - """ - lines = md.splitlines() - inside = False - entries: list[dict] = [] - for line in lines: - if KEY_CONCEPTS_HEADER.match(line): - inside = True - continue - if inside and NEXT_H2.match(line): - break - if not inside: - continue - bullet = BULLET.match(line) - if not bullet: - continue - body = bullet.group(1).strip() - if not body or body.startswith("` and an incomplete frontmatter. Your job: - - a. **Extract authors into the frontmatter.** Read the first ~30 lines of - `content.md` (or the first `sections/*.md`) to find the author list — - usually between the title and the abstract. Add an `authors` field to - the YAML frontmatter as a list of display names: - ```yaml - authors: ["Huzihiro Araki", "Masanao Ozawa"] - ``` - If authors cannot be identified, omit the field (do not invent names). - The authors list enables author-name-based search later on - (see the *Searching related work* section below). - - b. **Write Summary.** 3–5 sentences that answer "what is this doc and - why would a coding agent care?". Base it on the actual content, not - the title alone. - - c. **Write Key concepts.** Bullet list of identifiers an agent would - grep for. **Each bullet must start with a backtick-quoted identifier - name**, followed by a short description. This is a hard format - requirement — `scripts/update_concepts.py` keys its cross-document - index off this leading identifier, and bullets without one collapse - into a `Unnamed concepts` bucket. - - Required shape (three tiers, choose the strongest that applies): - ```markdown - - `` — → formalized: QuantumSystem.X.y - - `` — → mathlib: Mathlib.X.y - - `` — → needs formalization - ``` - - Use `→ formalized: ` only when the concept is already - proven in this repository (`QuantumSystem.*` or another local - module). It outranks `→ mathlib:` because a local proof is - stronger evidence than a mathlib match — `gap-filler` - consequently treats these as the highest tier (`formalized` > - `resolved` > `partial` > `gap`). The tier is verified by the - same `verify_mathlib_refs.py` loop as `mathlib`, so a stale - identifier picks up `[UNVERIFIED]` automatically. - - Contents of the bullets: - - For **code-adjacent papers**: function/type names, CLI flags, - config keys, environment variables, error messages, protocol fields. - - For **math papers**: named definitions, canonical theorems, operator - or functor names (e.g. `modular automorphism group`, `relative - modular operator`, `KMS condition`). - - Skip this section entirely (delete the TODO block) if the doc has - genuinely no greppable terminology — do not fabricate identifiers. - - d. **Cross-reference against mathlib** (only if the Lean MCP toolchain is - available in this session — i.e. `lean_local_search`, - `lean_leansearch` are callable). For each Key concept bullet: - - - Run `lean_local_search ` first. If it returns a - declaration that matches, annotate the bullet with - `→ mathlib: Mathlib.Namespace.name`. - - If nothing comes back, **also try an author-name search**: - `lean_local_search ` for each author extracted in 4a, - plus any canonical author cited repeatedly in the text (e.g. - "Takesaki", "Araki", "Connes"). This surfaces modules that cite - the author in docstrings or comments, which often reveal - adjacent formalisations even when the term itself is not in - mathlib. See *Searching related work* below for rationale. - - If both searches miss, annotate the bullet with - `→ needs formalization` so the gap is explicit. - - If the session has no Lean MCP tools, skip this step — do not - invent annotations. - - **Never trust search results blindly.** After annotating, pass - each proposed `→ mathlib: ` through the verification loop - in step 4g — silent mismatches undermine every downstream agent. - - e. **Extract the bibliography into the frontmatter.** Read the end of - `content.md` (or the final `sections/*.md`) for the `## References` - section. Parse each numbered / keyed entry into a YAML list and add - it to the frontmatter as `bibliography`: - ```yaml - bibliography: - - key: Ara76 # short citation key; invented if absent - title: "Relative entropy of states of von Neumann algebras" - authors: ["Huzihiro Araki"] - venue: "Publ. RIMS Kyoto Univ. 11" - year: 1976 - arxiv: null # arXiv ID if present in the entry - doi: null # DOI if present - ingested: false # true only if already inside references/ - ``` - Rules: - - Preserve the entry order from the paper so `key` matches the - in-text citation numbering when possible. - - If the paper uses author-year keys ("Kos85", "TV20"), keep them; - otherwise generate `refNN` using the 1-based index. - - `authors` is always a list, even for a single author. Omit fields - (set to `null`) rather than invent data. - - Skip the section entirely if the paper has no References — do not - fabricate entries. - - `ingested: true` is reserved for the `update_concepts.py` helper - to set later; leave it `false` while writing. - - f. **Refresh the concept index (strict mode).** After INDEX.md is - fully populated, run - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/update_concepts.py \ - --strict - ``` - - The `--strict` flag fails with exit 1 if any Key concepts bullet - does not start with a `` `backtick-quoted` `` identifier — this - is what the cross-document index keys off (step 4c contract). If - it fails, fix the offending bullets and re-run; never commit a - tree in which the validator complains. - - **This project auto-runs `update_concepts.py` via a - `PostToolUse` hook** (`.claude/settings.json`) whenever an - INDEX.md under a `references/` tree is edited. The `--strict` - invocation above is still required — the hook runs the - non-strict form, so format-drift checks need to happen - explicitly. If you want to confirm nothing drifted silently, - append `--check-fresh` on its own invocation; it exits 1 when - any INDEX.md is newer than CONCEPTS.md. - - g. **Verify every mathlib annotation** (only when Lean MCP tools are - available; skip otherwise). Run - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py \ - extract --output /tmp/mathlib-worklist.json - ``` - - For each item in the worklist, call `mcp__lean-lsp__lean_verify` - on the candidates in the order listed. The **first candidate that - `lean_verify` accepts as a valid declaration counts as verified**. - If every candidate for an item fails, the annotation is a silent - false positive — record the failure as - `{"slug": "...", "line": NN, "reason": "..."}` and append it to a - `failed.json` list. - - After the loop, patch the offending bullets with - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py \ - mark-unverified --from /tmp/failed.json - ``` - - The script appends ` [UNVERIFIED] (reason)` to each annotation - so `gap-filler`'s `detect_gaps.py` treats the concept as - `suspect` rather than resolved. It **also stamps every INDEX.md** - with a `mathlib_verified: ` frontmatter field so the - verification cycle is provable. Re-run step 4f after patching so - `CONCEPTS.md` picks up the markers. - - **Always run `mark-unverified`, even if `failed.json` is an empty - list.** The empty-list case is the "happy path" where every - annotation passed; the script still needs to stamp the tree so - `check-done` (step 4h) recognises the cycle as complete. - - h. **Prove the cycle ran.** Run - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py \ - check-done - ``` - - It exits 0 only when every INDEX.md carries a fresh - `mathlib_verified` timestamp and no INDEX.md has been edited - after being stamped. Treat a non-zero exit as a hard failure — - the ingestion is not finished until this check passes. If you - edit an INDEX.md after stamping, re-run step 4g with an updated - `failed.json` (even empty) to re-stamp. - - Keep `INDEX.md` concise (under ~80 lines, including the bibliography). - The point is navigation, not summarisation; the body lives in - `content.md` / `sections/`. - -5. **Report back to the user.** Tell them the `INDEX.md` path, any notable - caveats (OCR was skipped, large doc was split, no images found), a - one-line count of how many concepts had a mathlib match vs needed - formalization, and how many bibliography entries were extracted. - Mention `CONCEPTS.md` if it was refreshed. Do not paste the full - summary into chat — they can read the file. - -## Searching related work - -When annotating concepts against mathlib (step 4d) or — in future — against -external sources, two search axes should be used together: - -1. **Term-based search.** The mathematical term or identifier itself - (`"relative entropy"`, `"modular automorphism"`, `"scaled dot-product - attention"`). This finds definitions and direct restatements. - -2. **Author-name search.** The surname(s) of the paper's authors plus the - canonical author of the concept being formalised (often different — - e.g. Araki wrote about *relative entropy* building on *Takesaki's* - modular theory; both names should be tried). Rationale: mathlib - developers routinely cite sources in docstrings and section comments, - so `lean_local_search "Takesaki"` surfaces declarations that invoke - Takesaki-style theory even when the user's exact term is absent. This - is how neighbouring formalisations get discovered. - -Examples: - -- Concept "modular automorphism group" → `lean_local_search "modular - automorphism"` (term) + `lean_local_search "Takesaki"` (author). -- Concept "Araki's relative entropy" → `lean_local_search "relative - entropy"` + `lean_local_search "Araki"` + `lean_local_search "Connes"` - (Connes-Radon-Nikodym cocycle underlies the construction). - -The same two-axis pattern applies to future web / textbook search skills: -looking up the author's publication list often yields introductions that -fill prerequisite gaps which the primary paper assumes. - -## Why this design - -- **MinerU over Docling for math papers.** Earlier iterations used Docling - as a library; it handled layout / figures well but emitted - `` for every equation by default, and the - opt-in formula VLM was GPU-tuned and failed to make meaningful progress - in 10 minutes on an 18-page paper on CPU. MinerU's `pipeline` backend - decodes the same paper end-to-end in ~7 minutes on CPU, with LaTeX for - every formula (display and inline) and no placeholders. MinerU also - preserves equation numbers via `\tag{...}` and provides a straight JSON - page index. The gain for math formalisation work is qualitative, not - just quantitative. -- **CLI subprocess, not library import.** MinerU's Python API exists but - is less stable than the CLI and pulls in a heavier dependency graph - (vLLM, xformers) when imported directly. Shelling out to `mineru` via - `subprocess.run` sidesteps the Python version churn and lets us install - the tool once per machine with `uv tool install "mineru[all]"`. -- **GPL-free dependencies.** MinerU 3.1+ is Apache 2.0 with commercial - thresholds (100M MAU / $20M monthly revenue) that do not apply here. - `pymupdf`/`poppler`/`marker-pdf` remain off-limits for license reasons. -- **Claude writes Summary / Key concepts, not the script.** Summarisation - and identifier extraction are judgement calls; a scripted heuristic - would be wrong often enough to be harmful. The script handles the - mechanical work (download, convert, chunk, save images, scaffold); the - agent handles the semantic work. - -## Runtime prerequisites - -- **`uv`** must be on `PATH`. The script itself declares no Python deps - (stdlib only) but uses `uv run` for invocation hygiene. -- **`mineru` CLI must be on `PATH`**. One-off install: - `uv tool install "mineru[all]"` (≈ 4 GB of Python packages + model weights - on first run). Subsequent runs reuse the cache and start in a second. -- **Disk space.** MinerU's models plus the `mineru[all]` environment live - in the uv tool directory; budget ~4 GB. Per-paper runtime memory peaks - at 3–4 GB on the Araki-size paper. -- **GPU (optional).** If `nvidia-smi` reports a working GPU the converter - switches MinerU to its `hybrid-auto-engine` backend, which is - dramatically faster on the formula-recognition stage. Otherwise it - silently uses the CPU-only `pipeline` backend. No flag needed. - -## Failure modes to watch for - -- **Network errors on download.** The script exits non-zero; forward the - error and ask the user for a local path. -- **Scanned PDFs (no text layer).** Output Markdown will be nearly empty. Re-run - with `--ocr` after asking the user, since OCR adds minutes. -- **No H1 headings despite >20 pages.** The script falls back to a single - `content.md` — that is intentional, do not try to hand-split. -- **Very large docs (>100 pages).** First-run conversion can take several - minutes on CPU; warn the user before starting so they do not cancel. diff --git a/.claude/skills/pdf-to-knowledge/hooks/README.md b/.claude/skills/pdf-to-knowledge/hooks/README.md deleted file mode 100644 index da65ed3..0000000 --- a/.claude/skills/pdf-to-knowledge/hooks/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# pdf-to-knowledge hooks - -`.claude/settings.json` wires a `PostToolUse` hook that auto-regenerates -`references/CONCEPTS.md` whenever an `INDEX.md` under a `references/` tree -is edited. The hook is optional — nothing else in the skill depends on it. - -## Files - -- `on_index_change.py` — the hook implementation (stdlib-only). -- `README.md` — this file. - -## How the wiring works - -`.claude/settings.json` contains: - -```json -{ - "hooks": { - "PostToolUse": [ - { - "matcher": "Edit|Write|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "sh -c 'script=\"${CLAUDE_PROJECT_DIR}/.claude/skills/pdf-to-knowledge/hooks/on_index_change.py\"; [ -f \"$script\" ] && exec python3 \"$script\" || exit 0'" - } - ] - } - ] - } -} -``` - -Important details: - -- **`$CLAUDE_PROJECT_DIR`** is provided by Claude Code in every hook - subprocess. It resolves to the project root that contains `.claude/`, - regardless of the editor's current working directory. The command - does **not** hardcode `/workspaces/quantum-system` anywhere — copy - this tree into another project and the hook continues to work without - edits. -- **Existence guard** (`[ -f "$script" ]`): if the hook script has been - moved or deleted, the shell exits 0 instead of erroring. The skill - author can delete `hooks/on_index_change.py` to disable the - behaviour without also editing `settings.json`. -- **`exec python3`**: replaces the shell process with the Python one, - minimising PID churn. -- **POSIX `sh`**: no Bash-isms, so the command runs under any POSIX - shell Claude Code picks. - -## What the hook does - -1. Reads the `PostToolUse` JSON payload from stdin. -2. Extracts `tool_input.file_path`. -3. If the path ends in `INDEX.md` and is under a `references/` directory, - the hook invokes - `.claude/skills/pdf-to-knowledge/scripts/update_concepts.py ` - to rebuild `CONCEPTS.md`. -4. **Fixture paths are skipped** — edits under `skill-creator-tests/` or - any `iteration-*/` ancestor do not trigger regeneration, so frozen - eval outputs stay stable. -5. Any exception is caught and the script exits 0. The hook never blocks - an Edit tool call on its own error. - -## Portability / disabling - -- **Move to a different project**: copy `.claude/skills/pdf-to-knowledge/` - verbatim AND keep the `hooks.PostToolUse` stanza in the new project's - `.claude/settings.json`. No path edits required. -- **Disable**: delete the `hooks` stanza from `.claude/settings.json`, - or delete `hooks/on_index_change.py` itself (the existence guard - makes this a clean no-op). -- **Debug**: add a one-liner inside `main()` that writes to - `/tmp/hook.log`. The hook's stderr surfaces in the Claude Code - transcript as `[concepts-hook]` lines. - -## Limitations - -- The hook relies on `$CLAUDE_PROJECT_DIR` being set. If a future - Claude Code release drops that variable, the `[ -f "$script" ]` - guard turns the hook into a no-op (exit 0) — no crash, but the - auto-refresh stops silently. Monitor `CONCEPTS.md` freshness via - `update_concepts.py --check-fresh` in that case. -- The hook runs on **every** `Edit|Write|NotebookEdit`. For files that - are not INDEX.md, it returns early at step 2 above — one cheap - stdin-JSON parse per tool call. If you notice hook latency, profile - `update_concepts.py` on your references tree; it is stdlib-only and - typically runs in < 200 ms. diff --git a/.claude/skills/pdf-to-knowledge/hooks/on_index_change.py b/.claude/skills/pdf-to-knowledge/hooks/on_index_change.py deleted file mode 100644 index 6c2280d..0000000 --- a/.claude/skills/pdf-to-knowledge/hooks/on_index_change.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python3 -"""PostToolUse hook: refresh ``references/CONCEPTS.md`` after an INDEX.md edit. - -Wired from ``.claude/settings.json`` via: - - { - "hooks": { - "PostToolUse": [ - { - "matcher": "Edit|Write|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "sh -c 'script=\"${CLAUDE_PROJECT_DIR}/.claude/skills/pdf-to-knowledge/hooks/on_index_change.py\"; [ -f \"$script\" ] && exec python3 \"$script\" || exit 0'" - } - ] - } - ] - } - } - -See ``hooks/README.md`` for the rationale behind the ``sh -c`` wrapper -(CLAUDE_PROJECT_DIR portability + graceful disable when the script is -removed). The hook is deliberately permissive: - -- It exits 0 on any exception so a bad hook never blocks Claude's edit. -- It ignores edits that do not target a ``references//INDEX.md``. -- It does nothing when the edited INDEX.md is inside a skill snapshot or - test-iteration tree (``skill-creator-tests/`` / ``iteration-*/``) — those - dirs contain frozen fixtures that should not auto-refresh. -- Output goes to stderr so the user sees "[concepts-hook] regenerated ..." - inline with their session. -""" - -from __future__ import annotations - -import json -import os -import re -import subprocess -import sys -from pathlib import Path - - -SKIP_PARTS = frozenset({"skill-snapshot", "gap-filler-snapshot", "web-to-knowledge-snapshot"}) -SKIP_PREFIXES = ("iteration-", "iter-") - - -def _is_index_md(path: Path) -> bool: - return path.name == "INDEX.md" and any(p.name == "references" for p in path.parents) - - -def _is_fixture(path: Path) -> bool: - parts = set(path.parts) - if parts & SKIP_PARTS: - return True - # Skip iteration-N style test artefacts so regenerated CONCEPTS.md does - # not disturb frozen eval outputs. - for parent in path.parents: - if parent.name.startswith(SKIP_PREFIXES) and parent.parent.name == "skill-creator-tests" or ( - parent.name == "skill-creator-tests" - ): - return True - return False - - -def _references_root(path: Path) -> Path | None: - """Return the ``references/`` directory that owns this INDEX.md, or None.""" - for parent in path.parents: - if parent.name == "references": - return parent - return None - - -def _run_update_concepts(root: Path) -> None: - script = ( - Path(__file__).resolve().parents[1] / "scripts" / "update_concepts.py" - ) - try: - result = subprocess.run( - ["python3", str(script), str(root)], - capture_output=True, - text=True, - timeout=30, - ) - except Exception as exc: - print(f"[concepts-hook] failed to invoke update_concepts.py: {exc}", file=sys.stderr) - return - message = (result.stdout or result.stderr).strip().splitlines() - for line in message[-3:]: - print(f"[concepts-hook] {line}", file=sys.stderr) - - -def main() -> int: - try: - payload = json.load(sys.stdin) - except (json.JSONDecodeError, OSError): - return 0 - - tool_input = payload.get("tool_input") or {} - raw = tool_input.get("file_path") or "" - if not raw: - # Edit/Write with no resolvable path — nothing to do. - return 0 - - path = Path(raw) - if not path.is_absolute(): - cwd = payload.get("cwd") or os.getcwd() - path = (Path(cwd) / path).resolve() - else: - path = path.resolve() - - if not _is_index_md(path): - return 0 - if _is_fixture(path): - return 0 - - root = _references_root(path) - if root is None or not root.is_dir(): - return 0 - - _run_update_concepts(root) - return 0 - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except Exception as exc: - # Hook must never block the session on its own errors. - print(f"[concepts-hook] unexpected error: {exc}", file=sys.stderr) - raise SystemExit(0) diff --git a/.claude/skills/pdf-to-knowledge/references/output-format.md b/.claude/skills/pdf-to-knowledge/references/output-format.md deleted file mode 100644 index 7f2995c..0000000 --- a/.claude/skills/pdf-to-knowledge/references/output-format.md +++ /dev/null @@ -1,207 +0,0 @@ -# Output format: `references//` - -Detailed specification of what the skill writes to disk. Read this when you -need to tweak the converter or answer a user question about where something -lives. - -## Directory layout - -``` -references// -├── INDEX.md -├── content.md (page count <= 20, OR > 20 but no H1 headings to split on) -├── sections/ (page count > 20 and the PDF has H1 headings) -│ ├── 01-.md -│ └── 02-.md -├── assets/ -│ ├── image_000001_.jpg -│ └── image_000002_.jpg -└── mineru-raw/ (only with --keep-raw; see the last section for contents) -``` - -Exactly one of `content.md` or `sections/` exists — never both. Keeps the -agent's mental model simple. - -## Slug derivation - -- arXiv URLs (`arxiv.org/abs/2501.12345v1`, `arxiv.org/pdf/2501.12345`) → - `arxiv-2501.12345`. Version suffix is stripped so re-fetching v2 lands in - the same directory. -- Other URLs → slugified filename from the URL path (`.pdf` stripped). -- Local paths → slugified basename. -- `--slug` flag always wins. - -## `INDEX.md` structure - -```markdown ---- -title: "..." -source: "" -pages: -slug: -assets: # number of extracted image files -authors: ["Name1", "Name2"] # populated by Claude in step 4a; omitted if unknown -bibliography: # populated by Claude in step 4e; empty list if the paper has no References - - key: "" - title: "" - authors: ["Name1", ...] - venue: "" - year: - arxiv: "" - doi: "" - ingested: false # true when the referenced paper is already under references/; used by the concept index ---- - -# - -## Summary -<!-- 3-5 sentences, filled in by Claude after conversion --> - -## Key concepts -<!-- bullet list of identifiers; deleted entirely if not applicable. - Each bullet may end with a tier annotation: - - `<term>` — definition/description → formalized: `QuantumSystem.A.b` - - `<term>` — definition/description → mathlib: `Mathlib.A.B.c` - - `<term>` — definition/description → needs formalization ---> - -## Contents -- [<section title>](sections/NN-<slug>.md) -- ... -``` - -Frontmatter is plain YAML — machine-readable. The body is human/agent-readable -navigation. Summary and Key concepts are scaffolded as `<!-- TODO -->` blocks; -Claude replaces them. `authors` is filled by Claude after scanning the first -page of `content.md`; when present it powers author-name-based related-work -search in step 4d. `bibliography` is populated in step 4e and drives the -cross-document "next papers to ingest" suggestions (currently manual, -automated in a future iteration). - -### Concept annotations - -Cross-references live inline on each Key concepts bullet as a trailing -arrow annotation. Three forms are recognised by `update_concepts.py`, -`detect_gaps.py`, and `verify_mathlib_refs.py`: - -- `→ formalized: QuantumSystem.X.y` — locally proven in this repository. - Strongest tier; outranks `resolved` for prioritisation. -- `→ mathlib: Mathlib.X.y` — present in mathlib (term or author search hit - that passed `lean_verify`). Tier `resolved`. -- `→ needs formalization` — no match in either search axis. Tier `gap`. - -A `[UNVERIFIED] (reason)` suffix is appended by -`verify_mathlib_refs.py mark-unverified` when the candidate failed -`lean_verify`; both `mathlib` and `formalized` annotations participate in -that loop. - -They are plain Markdown — agents can `grep -n "→ formalized:"`, -`grep -n "→ mathlib:"`, `grep -n "→ needs formalization"`, or -`grep -n "[UNVERIFIED]"` to slice an INDEX.md by tier. The annotation is -added only when the session has Lean MCP tooling; otherwise it is -omitted. - -### ToC detail - -- **Split mode (sections/)**: one entry per section file in document order. -- **Monolith mode (content.md)**: the "Full content" link, followed by - indented child links for each H2/H3 heading (up to 20) with GitHub-style - anchor fragments — e.g. ``[3 Model Architecture](content.md#3-model-architecture)``. - This lets an agent jump straight to the relevant section without scanning - the whole file. - -## Section splitting rules - -Trigger: `page_count > --max-pages-per-section` (default 20). - -Algorithm: -1. Walk the raw Markdown line by line. -2. Each `# ` line starts a new section. `## `, `### `, etc. are body. -3. Content before the first `# ` (if non-empty) becomes a `front-matter` - section, numbered first. -4. If only one real section is produced, fall back to a single `content.md` - (no splitting, ToC points at the monolith). - -Section filenames are `NN-<heading-slug>.md` where `NN` is a zero-padded -1-based index and the slug is derived the same way as the top-level slug -(lowercase, ASCII-ish, max 60 chars). - -## Image handling - -- MinerU writes extracted images into `<scratch>/<name>/auto/images/` with - hash-named JPG files and references them from the Markdown as - `images/<hash>.jpg`. The post-processor in `scripts/convert.py` rewrites - these references to `assets/<hash>.jpg`, copies **only the referenced** - images into `assets/`, and drops any orphan clips MinerU may have left - behind (mostly per-formula crops MinerU keeps as debugging spare data). -- For pure math papers with no figures MinerU's `images/` directory still - gets populated with formula clips. None of them are referenced from the - Markdown (LaTeX handles the equations), so `assets/` ends up empty — the - converter does not create it in that case. - -## Formulas - -Always on. MinerU emits LaTeX for both inline (`$...$`) and display (`$$...$$`) -math. Equation numbering is preserved via `\tag{...}`. No opt-in flag is -needed; the formula recogniser runs as part of the `pipeline` backend at -modest additional CPU cost (~2 minutes on an 18-page paper). - -## OCR - -Off by default (`--ocr` to enable). Running OCR on a text-native PDF is slow -and often introduces transcription errors. Switch MinerU's method to `ocr` -only when the user confirms the PDF is scanned or when the initial -conversion returned near-empty Markdown. - -## `CONCEPTS.md` (cross-document index) - -Sibling of the per-slug subdirs under `references/`. Regenerated by -`scripts/update_concepts.py` at the end of step 4f in the workflow. - -``` -references/ -├── CONCEPTS.md # this file -├── arxiv-2202.03357/ -│ └── INDEX.md -├── arxiv-1706.03762/ -│ └── INDEX.md -└── ... -``` - -Content: - -```markdown -# Concepts index - -Auto-generated from references/*/INDEX.md. Do not edit by hand — rerun -`.claude/skills/pdf-to-knowledge/scripts/update_concepts.py references/`. - -## <Concept title> - -- [<slug>](<slug>/INDEX.md) — <description from Key concepts bullet> → mathlib: Mathlib.A.B.c -- [<another slug>](<another slug>/INDEX.md) — <description> → needs formalization -``` - -Each section header is a concept title (the backtick-quoted identifier at -the head of a `Key concepts` bullet). Entries are grouped by concept so a -glance reveals which papers cover each term and whether any of them gives -a mathlib mapping. The file is fully derived — editing it by hand is -overwritten on the next rebuild. - -Implementation note: concept keys are normalised to lowercase for -deduplication but displayed in their original case. Bullets with no -backtick-quoted lead identifier fall under a synthetic -"`Unnamed concepts`" heading to avoid silent loss. - -## `mineru-raw/` (optional debug artefacts) - -- **Off by default** since iteration-6; pass `--keep-raw` to the converter - to retain them. When enabled, `<slug>/mineru-raw/` holds MinerU's - auxiliary outputs: - - `<name>_middle.json` — raw DocumentAnalysis JSON (2+ MB) - - `<name>_content_list.json` and `_v2` — per-span structured content - - `<name>_model.json` — layout model outputs - - `<name>_layout.pdf`, `_span.pdf`, `_origin.pdf` — annotated PDFs useful - when triaging a conversion bug -- Not intended for agents to `Read`; the useful signal is already in - `content.md` / `INDEX.md`. Safe to delete. diff --git a/.claude/skills/pdf-to-knowledge/scripts/convert.py b/.claude/skills/pdf-to-knowledge/scripts/convert.py deleted file mode 100755 index 8a73657..0000000 --- a/.claude/skills/pdf-to-knowledge/scripts/convert.py +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -"""Convert a PDF into agent-friendly Markdown + image assets using MinerU. - -Produces under ``<output-dir>/<slug>/``: - -- ``INDEX.md`` Metadata, ToC, and scaffolded Summary / Key concepts / Bibliography - frontmatter sections that the caller (Claude) fills in after - reading the content. -- ``content.md`` Full Markdown (if total pages <= max-pages-per-section). -- ``sections/`` Split Markdown files (if total pages exceed the threshold and - the document has top-level ``#`` / ``## `` headings to split on). -- ``assets/`` Images referenced from the Markdown. - -This script is a thin post-processor around the MinerU CLI. MinerU's -``pipeline`` backend runs entirely on CPU and, unlike Docling's formula VLM, -decodes mathematical formulas into LaTeX in a few minutes per paper. We gave -up on Docling in iteration-6 after its formula VLM crawled on CPU. - -Usage: - uv run convert.py <pdf-url-or-path> [--output-dir DIR] [--slug SLUG] - [--max-pages-per-section N] [--ocr] - [--keep-raw] - -Prerequisite: - ``mineru`` must be on PATH. One-off install: - uv tool install "mineru[all]" -""" - -from __future__ import annotations - -import argparse -import json -import re -import shutil -import subprocess -import sys -import tempfile -import urllib.parse -import urllib.request -from pathlib import Path - - -def slugify(text: str) -> str: - """Lowercase, ASCII-friendly filesystem slug, capped at 60 chars.""" - text = text.lower().strip() - text = re.sub(r"[^\w\s-]", "", text, flags=re.UNICODE) - text = re.sub(r"[\s_-]+", "-", text) - return text[:60].strip("-") or "document" - - -def derive_slug(source: str) -> str: - """Pick a readable slug from a URL or local path.""" - m = re.search(r"arxiv\.org/(?:pdf|abs)/([\w.-]+?)(?:v\d+)?(?:\.pdf)?(?:[?#]|$)", source) - if m: - return f"arxiv-{m.group(1)}" - if source.startswith(("http://", "https://")): - parsed = urllib.parse.urlparse(source) - basename = Path(parsed.path).stem or parsed.netloc - return slugify(basename) - return slugify(Path(source).stem) - - -def normalise_pdf_url(url: str) -> str: - """Rewrite arxiv ``abs/`` URLs to their ``pdf/`` counterparts.""" - m = re.match(r"^(https?://arxiv\.org)/abs/([\w.-]+?)(?:v\d+)?/?$", url) - if m: - return f"{m.group(1)}/pdf/{m.group(2)}" - return url - - -def download_pdf(url: str, dest: Path) -> None: - req = urllib.request.Request(url, headers={"User-Agent": "pdf-to-knowledge/1.0"}) - with urllib.request.urlopen(req, timeout=120) as response, dest.open("wb") as out: - while chunk := response.read(65536): - out.write(chunk) - - -def _heading_level(line: str) -> int: - """Return the Markdown heading level (1..6) of ``line``, or 0 if not a heading.""" - m = re.match(r"^(#{1,6}) \S", line) - return len(m.group(1)) if m else 0 - - -def split_markdown_by_top_headings(md: str) -> list[tuple[str, str]]: - """Split Markdown at its top-most heading level. Returns ``[(title, body), ...]``.""" - has_h1 = any(_heading_level(line) == 1 for line in md.splitlines()) - split_level = 1 if has_h1 else 2 - - sections: list[tuple[str, str]] = [] - current_title: str | None = None - current_body: list[str] = [] - for line in md.splitlines(keepends=True): - if _heading_level(line.rstrip("\n")) == split_level: - if current_title is not None: - sections.append((current_title, "".join(current_body))) - current_title = line.lstrip("#").strip() - current_body = [line] - else: - if current_title is None: - current_title = "front-matter" - current_body = [] - current_body.append(line) - if current_title is not None: - sections.append((current_title, "".join(current_body))) - return sections - - -def extract_document_title(md: str, fallback: str) -> str: - """Return the first heading (any level) in ``md``, or ``fallback``.""" - for line in md.splitlines(): - m = re.match(r"^#{1,6} (.+)", line) - if m: - return m.group(1).strip() - return fallback - - -def _github_anchor(heading: str) -> str: - """Compute a GitHub-style Markdown anchor for a heading.""" - slug = heading.strip().lower() - slug = re.sub(r"[^\w\s-]", "", slug, flags=re.UNICODE) - slug = re.sub(r"\s+", "-", slug) - return slug.strip("-") - - -def extract_toc_headings(md: str, max_entries: int = 20) -> list[tuple[int, str]]: - """Extract H2/H3 headings from ``md`` for navigation.""" - entries: list[tuple[int, str]] = [] - for line in md.splitlines(): - m = re.match(r"^(##{1,2}) (.+)", line) - if m: - level = len(m.group(1)) - title = m.group(2).strip() - entries.append((level, title)) - if len(entries) >= max_entries: - break - return entries - - -def _flat_toc_for_content(md: str) -> list[str]: - """Build ToC Markdown lines for the single-file ``content.md`` case.""" - lines = ["- [Full content](content.md)"] - for level, title in extract_toc_headings(md): - indent = " " if level == 2 else " " - anchor = _github_anchor(title) - lines.append(f"{indent}- [{title}](content.md#{anchor})") - return lines - - -def _has_gpu() -> bool: - """Detect an NVIDIA GPU via ``nvidia-smi``. Returns False on any error. - - MinerU's `hybrid-auto-engine` backend uses GPU when available and is - dramatically faster than `pipeline` for the formula-recognition stage. - Falls back to CPU `pipeline` cleanly when `nvidia-smi` is absent. - """ - if shutil.which("nvidia-smi") is None: - return False - try: - result = subprocess.run( - ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], - capture_output=True, - text=True, - timeout=5, - ) - except (subprocess.TimeoutExpired, OSError): - return False - return result.returncode == 0 and bool(result.stdout.strip()) - - -def run_mineru(pdf_path: Path, output_base: Path, ocr: bool) -> tuple[Path, Path, Path]: - """Invoke the MinerU CLI. Returns (md_path, images_dir, content_list_json).""" - if shutil.which("mineru") is None: - print( - "[error] 'mineru' not found on PATH. Install with: " - "uv tool install \"mineru[all]\"", - file=sys.stderr, - ) - sys.exit(3) - - method = "ocr" if ocr else "auto" - # Auto-select backend: hybrid-auto-engine uses GPU when available and - # can be >5x faster for formula-heavy papers; pipeline is CPU-only. - backend = "hybrid-auto-engine" if _has_gpu() else "pipeline" - print(f"[info] MinerU backend: {backend}", file=sys.stderr) - cmd = [ - "mineru", - "-p", str(pdf_path), - "-o", str(output_base), - "-b", backend, - "-l", "en", - "-m", method, - ] - print(f"[info] Running: {' '.join(cmd)}", file=sys.stderr) - subprocess.run(cmd, check=True) - - name = pdf_path.stem - auto_dir = output_base / name / "auto" - md_path = auto_dir / f"{name}.md" - images_dir = auto_dir / "images" - content_list_json = auto_dir / f"{name}_content_list.json" - if not md_path.is_file(): - print(f"[error] MinerU did not produce {md_path}", file=sys.stderr) - sys.exit(4) - return md_path, images_dir, content_list_json - - -def page_count_from_content_list(content_list_json: Path) -> int: - """Read max ``page_idx`` from MinerU's content_list.json and return page count.""" - try: - data = json.loads(content_list_json.read_text(encoding="utf-8")) - except Exception: - return 0 - max_idx = 0 - for item in data: - idx = item.get("page_idx") - if isinstance(idx, int): - max_idx = max(max_idx, idx) - return max_idx + 1 if data else 0 - - -_IMAGE_REF = re.compile(r"!\[[^\]]*\]\(images/([^)]+)\)") - - -def rewrite_and_collect_image_refs(md: str) -> tuple[str, set[str]]: - """Rewrite ``images/...`` references to ``assets/...`` and return referenced names.""" - referenced: set[str] = set() - - def _sub(match: re.Match) -> str: - name = match.group(1) - referenced.add(name) - return match.group(0).replace("images/", "assets/", 1) - - return _IMAGE_REF.sub(_sub, md), referenced - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("source", help="PDF URL or local path") - parser.add_argument( - "--output-dir", - default="references", - help="Parent directory; output is placed under <output-dir>/<slug>/", - ) - parser.add_argument("--slug", default=None, help="Override the auto-derived slug") - parser.add_argument( - "--max-pages-per-section", - type=int, - default=20, - help="Split into sections/ if the document exceeds this many pages (default: 20)", - ) - parser.add_argument( - "--ocr", - action="store_true", - help="Use MinerU's OCR method (for scanned PDFs). Default is 'auto'.", - ) - parser.add_argument( - "--keep-raw", - action="store_true", - help=( - "Keep MinerU's raw auxiliary outputs (middle.json, layout.pdf, span.pdf, " - "model.json, content_list_v2.json) under <output-dir>/<slug>/mineru-raw/. " - "Off by default — they are debugging artefacts unsuitable for agents." - ), - ) - args = parser.parse_args() - - source: str = args.source - slug = args.slug or derive_slug(source) - output_root = Path(args.output_dir).expanduser().resolve() - output_dir = output_root / slug - output_dir.mkdir(parents=True, exist_ok=True) - assets_dir = output_dir / "assets" - - # Resolve input to a local path. - if source.startswith(("http://", "https://")): - fetch_url = normalise_pdf_url(source) - tmpdir = Path(tempfile.mkdtemp(prefix="pdf-to-knowledge-")) - pdf_path = tmpdir / f"{slug}.pdf" - print(f"[info] Downloading {fetch_url}", file=sys.stderr) - download_pdf(fetch_url, pdf_path) - else: - pdf_path = Path(source).expanduser().resolve() - if not pdf_path.exists(): - print(f"[error] Not found: {pdf_path}", file=sys.stderr) - return 2 - - # Run MinerU into a fresh scratch directory so we fully own the layout. - mineru_scratch = Path(tempfile.mkdtemp(prefix="mineru-")) - md_path, images_src, content_list_json = run_mineru( - pdf_path, mineru_scratch, ocr=args.ocr - ) - - page_count = page_count_from_content_list(content_list_json) - print(f"[info] Pages: {page_count}", file=sys.stderr) - - md_text = md_path.read_text(encoding="utf-8") - md_text, referenced_images = rewrite_and_collect_image_refs(md_text) - - # Copy referenced images only — MinerU occasionally extracts formula clips - # that are not referenced from the Markdown; keeping them clutters agents. - image_count = 0 - if referenced_images and images_src.is_dir(): - assets_dir.mkdir(exist_ok=True) - for name in referenced_images: - src = images_src / name - if src.is_file(): - shutil.copy(src, assets_dir / name) - image_count += 1 - - # Optionally keep MinerU's raw auxiliary outputs for debugging. - if args.keep_raw: - raw_dir = output_dir / "mineru-raw" - raw_dir.mkdir(exist_ok=True) - for aux in md_path.parent.iterdir(): - if aux.name == md_path.name or aux == images_src: - continue - if aux.is_file(): - shutil.copy(aux, raw_dir / aux.name) - - # Clean up the scratch tree now that we have what we need. - shutil.rmtree(mineru_scratch, ignore_errors=True) - - # Write content.md / sections/ based on page count. - content_md = output_dir / "content.md" - title = extract_document_title(md_text, slug.replace("-", " ").title()) - - sectioned = False - toc_lines: list[str] = [] - if page_count > args.max_pages_per_section: - parts = split_markdown_by_top_headings(md_text) - real_parts = [(t, b) for t, b in parts if t != "front-matter" or b.strip()] - if len(real_parts) > 1: - sections_dir = output_dir / "sections" - sections_dir.mkdir(exist_ok=True) - for i, (section_title, body) in enumerate(real_parts, start=1): - sec_slug = slugify(section_title) - sec_file = sections_dir / f"{i:02d}-{sec_slug}.md" - sec_file.write_text(body, encoding="utf-8") - toc_lines.append(f"- [{section_title}](sections/{sec_file.name})") - sectioned = True - else: - content_md.write_text(md_text, encoding="utf-8") - toc_lines.extend(_flat_toc_for_content(md_text)) - else: - content_md.write_text(md_text, encoding="utf-8") - toc_lines.extend(_flat_toc_for_content(md_text)) - - # Scaffold INDEX.md (Claude fills Summary / Key concepts / authors / - # bibliography / mathlib annotations per SKILL.md steps 4a-4f). - index = [ - "---", - f"title: {json.dumps(title, ensure_ascii=False)}", - f"source: {json.dumps(source, ensure_ascii=False)}", - f"pages: {page_count}", - f"slug: {slug}", - f"assets: {image_count}", - "---", - "", - f"# {title}", - "", - "## Summary", - "", - "<!-- TODO: 3-5 sentence summary of what this document covers and why a", - " coding agent would consult it. Fill in after reading the content. -->", - "", - "## Key concepts", - "", - "<!-- TODO: Bullet list of identifiers an agent would grep for. Each bullet", - " MUST start with a `backtick-quoted` identifier — this drives the", - " cross-document concept index. Omit the section if no greppable", - " terminology exists (e.g. pure prose papers). -->", - "", - "## Contents", - "", - *toc_lines, - "", - ] - (output_dir / "INDEX.md").write_text("\n".join(index), encoding="utf-8") - - summary = { - "slug": slug, - "output_dir": str(output_dir), - "index_path": str(output_dir / "INDEX.md"), - "page_count": page_count, - "image_count": image_count, - "sectioned": sectioned, - } - print(json.dumps(summary, indent=2, ensure_ascii=False)) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.claude/skills/pdf-to-knowledge/scripts/update_concepts.py b/.claude/skills/pdf-to-knowledge/scripts/update_concepts.py deleted file mode 100755 index 80bae8a..0000000 --- a/.claude/skills/pdf-to-knowledge/scripts/update_concepts.py +++ /dev/null @@ -1,344 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -"""Rebuild ``<references-root>/CONCEPTS.md`` from every ``INDEX.md`` under it. - -Runs after a new PDF is ingested so concepts mentioned across multiple -documents appear in one cross-document index. The script is intentionally -dependency-free so it can execute with ``python3 update_concepts.py``. - -Usage: - python3 update_concepts.py <references-root> - -Example: - python3 update_concepts.py ./references - -Behaviour: -- Walks each subdirectory of ``<references-root>`` that contains an - ``INDEX.md`` and extracts bullets under ``## Key concepts``. -- Groups entries by the leading backtick-quoted identifier, so - ``- `modular automorphism group` via Tomita-Takesaki ... → needs formalization`` - is keyed by ``modular automorphism group``. -- Writes ``<references-root>/CONCEPTS.md`` with one section per concept, - sorted alphabetically by display name; existing file is overwritten. -- Bullets without a backtick-led identifier fall under - ``Unnamed concepts`` so nothing is silently lost. -""" - -from __future__ import annotations - -import argparse -import re -import sys -from collections import defaultdict -from pathlib import Path - - -KEY_CONCEPTS_HEADER = re.compile(r"^##\s+Key concepts\s*$", re.IGNORECASE) -NEXT_H2 = re.compile(r"^##\s+") -BULLET = re.compile(r"^\s*-\s+(.*)$") -LEADING_CODE = re.compile(r"^`([^`]+)`(.*)$") -# Characters that plausibly separate a concept name from its description when -# the author forgot to wrap the name in backticks (iteration-5 fallback). -PLAIN_SEPARATOR = re.compile(r"\s*(?:[—–:]|\s-\s|\()\s*") -ANNOTATION_SPLIT = re.compile(r"\s*→\s") - - -def _fallback_concept_name(body: str) -> tuple[str, str]: - r"""Best-effort concept extraction for bullets that lack a backtick head. - - Strategy: strip any trailing ``→ mathlib:`` / ``→ needs formalization`` - annotation, then split on the first em-dash, en-dash, colon, " - ", or - opening parenthesis. The left side becomes the concept name; the right - side (plus the original annotation) becomes the body. If no separator is - found, collapse names longer than 60 chars so they do not dominate the - concept index header. - """ - # Preserve the annotation so it travels with the bullet in CONCEPTS.md. - annotation = "" - parts = ANNOTATION_SPLIT.split(body, maxsplit=1) - head = parts[0].strip() - if len(parts) == 2: - annotation = "→ " + parts[1].strip() - - m = PLAIN_SEPARATOR.search(head) - if m: - name = head[: m.start()].strip() - rest = head[m.end() :].strip() - # If we split on "(" leave the content so the user sees the full - # phrasing, but close a dangling paren if the close-paren was the - # last char. - if m.group(0).startswith("(") and rest.endswith(")"): - rest = rest[:-1].rstrip() - else: - name = head - rest = "" - - # Avoid absurdly long "names" when the bullet is really one long sentence. - if len(name) > 60: - name = name[:60].rstrip(" -") + "…" - - body_parts = [p for p in (rest, annotation) if p] - return name, " ".join(body_parts) - - -def extract_key_concepts(md: str) -> list[tuple[str, str]]: - """Return ``(concept_name, rest_of_bullet)`` pairs from an INDEX.md body. - - Preference order: - 1. Leading ```backtick``-quoted identifier (contracted format from step 4c). - 2. Heuristic fallback (see ``_fallback_concept_name``). - 3. Empty name — bullet lands under ``Unnamed concepts``. - """ - lines = md.splitlines() - inside = False - collected: list[tuple[str, str]] = [] - - for line in lines: - if KEY_CONCEPTS_HEADER.match(line): - inside = True - continue - if inside and NEXT_H2.match(line): - break - if not inside: - continue - bullet = BULLET.match(line) - if not bullet: - continue - body = bullet.group(1).strip() - if not body or body.startswith("<!--"): - continue - m = LEADING_CODE.match(body) - if m: - name = m.group(1).strip() - rest = m.group(2).lstrip(" -—:").rstrip() - else: - name, rest = _fallback_concept_name(body) - collected.append((name, rest)) - return collected - - -def load_index_files(references_root: Path) -> dict[str, Path]: - """Return ``{slug: index_md_path}`` for every ``<slug>/INDEX.md`` under the root.""" - mapping: dict[str, Path] = {} - for entry in sorted(references_root.iterdir()): - if not entry.is_dir(): - continue - index = entry / "INDEX.md" - if index.is_file(): - mapping[entry.name] = index - return mapping - - -def build_concepts_md(references_root: Path, script_rel: str) -> str: - """Render the final ``CONCEPTS.md`` text.""" - # group[display_name] = list of (slug, rest_of_bullet) - grouped: dict[str, list[tuple[str, str]]] = defaultdict(list) - display_name: dict[str, str] = {} - - for slug, index_path in load_index_files(references_root).items(): - text = index_path.read_text(encoding="utf-8", errors="replace") - for name, rest in extract_key_concepts(text): - key = name.lower() if name else "" - if name and key not in display_name: - display_name[key] = name - grouped[key].append((slug, rest)) - - out: list[str] = [ - "# Concepts index", - "", - "Auto-generated from references/*/INDEX.md. Do not edit by hand —", - f"rerun `{script_rel} references/` to refresh.", - "", - ] - - if not grouped: - out.append("_No concepts found yet._") - out.append("") - return "\n".join(out) - - def sort_key(k: str) -> tuple[int, str]: - # Non-empty names first, sorted alphabetically; unnamed bucket last. - return (1 if k == "" else 0, display_name.get(k, "Unnamed concepts").lower()) - - for key in sorted(grouped, key=sort_key): - header = display_name.get(key, "Unnamed concepts") if key else "Unnamed concepts" - out.append(f"## {header}") - out.append("") - for slug, rest in grouped[key]: - link = f"[{slug}]({slug}/INDEX.md)" - if rest: - out.append(f"- {link} — {rest}") - else: - out.append(f"- {link}") - out.append("") - - return "\n".join(out) - - -def audit_freshness(references_root: Path) -> dict: - """Return the list of ``<slug>/INDEX.md`` newer than ``CONCEPTS.md``. - - Used by ``--check-fresh`` to surface staleness caused by edits that - skipped the concept-index refresh (T3-A guard). ``CONCEPTS.md`` absent - is itself a staleness signal. - """ - concepts = references_root / "CONCEPTS.md" - missing_concepts = not concepts.is_file() - concepts_mtime = concepts.stat().st_mtime if concepts.is_file() else 0.0 - newer: list[dict] = [] - for slug, index_path in load_index_files(references_root).items(): - idx_mtime = index_path.stat().st_mtime - # Small skew tolerance (1 s) so a CONCEPTS.md written in the same - # second as the INDEX.md still passes. - if idx_mtime > concepts_mtime + 1: - newer.append( - { - "slug": slug, - "path": str(index_path), - "index_mtime": idx_mtime, - "concepts_mtime": concepts_mtime, - } - ) - return { - "concepts_present": not missing_concepts, - "concepts_path": str(concepts), - "concepts_mtime": concepts_mtime, - "newer_index_files": newer, - "is_fresh": not missing_concepts and not newer, - } - - -def audit_strict(references_root: Path) -> list[dict]: - r"""Return a list of ``{slug, line, body}`` violations of the format contract. - - The contract (SKILL.md step 4c) says every Key concepts bullet must - start with a ``\`backtick\`-quoted`` identifier. This auditor flags: - - - Bullets that do not start with a backtick token at all (the ones - that collapse into the synthetic ``Unnamed concepts`` bucket). - - Bullets whose leading backtick contains whitespace but no - punctuation (ambiguous identifier). - - The returned list is empty when the tree complies. - """ - violations: list[dict] = [] - for slug, index_path in load_index_files(references_root).items(): - text = index_path.read_text(encoding="utf-8", errors="replace") - lines = text.splitlines() - inside = False - for idx, line in enumerate(lines, start=1): - if KEY_CONCEPTS_HEADER.match(line): - inside = True - continue - if inside and NEXT_H2.match(line): - break - if not inside: - continue - bullet = BULLET.match(line) - if not bullet: - continue - body = bullet.group(1).strip() - if not body or body.startswith("<!--"): - continue - if not LEADING_CODE.match(body): - violations.append( - { - "slug": slug, - "index_path": str(index_path), - "line": idx, - "body": body, - } - ) - return violations - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("references_root", help="Directory that contains per-slug subdirs") - parser.add_argument( - "--strict", - action="store_true", - help=( - "Exit non-zero if any Key concepts bullet does not start with a " - "backtick-quoted identifier. Use in CI / post-ingestion hooks " - "to catch format drift that would otherwise silently collapse " - "into the 'Unnamed concepts' bucket." - ), - ) - parser.add_argument( - "--check-fresh", - action="store_true", - help=( - "Read-only staleness check: exit 1 if any references/<slug>/INDEX.md " - "was modified after references/CONCEPTS.md (or CONCEPTS.md is " - "missing). Does not regenerate — combine with a separate " - "invocation to refresh. Use in hooks / CI to fail fast when the " - "concept index falls out of sync." - ), - ) - args = parser.parse_args() - - references_root = Path(args.references_root).expanduser().resolve() - if not references_root.is_dir(): - print(f"[error] not a directory: {references_root}", file=sys.stderr) - return 2 - - if args.check_fresh: - report = audit_freshness(references_root) - if report["is_fresh"]: - print(f"[ok] CONCEPTS.md fresh: {report['concepts_path']}") - return 0 - if not report["concepts_present"]: - print( - f"[fail] {report['concepts_path']} does not exist — run " - "update_concepts.py without --check-fresh to generate it.", - file=sys.stderr, - ) - else: - print( - f"[fail] {len(report['newer_index_files'])} INDEX.md file(s) " - "newer than CONCEPTS.md — re-run update_concepts.py to refresh:", - file=sys.stderr, - ) - for item in report["newer_index_files"]: - print(f" {item['slug']} {item['path']}", file=sys.stderr) - return 1 - - if args.strict: - violations = audit_strict(references_root) - if violations: - print( - f"[fail] {len(violations)} Key concepts bullet(s) miss the " - "leading `backtick` identifier contract:", - file=sys.stderr, - ) - for v in violations: - snippet = v["body"][:100] + ("…" if len(v["body"]) > 100 else "") - print( - f" {v['slug']} INDEX.md:{v['line']} {snippet}", - file=sys.stderr, - ) - print( - "[hint] rewrite each offending bullet so it starts with a " - "`backtick-quoted` concept name — this is what " - "scripts/update_concepts.py keys off for the cross-document " - "index (SKILL.md step 4c).", - file=sys.stderr, - ) - return 1 - - script_rel = ".claude/skills/pdf-to-knowledge/scripts/update_concepts.py" - md = build_concepts_md(references_root, script_rel) - target = references_root / "CONCEPTS.md" - target.write_text(md.rstrip() + "\n", encoding="utf-8") - - concept_count = sum(1 for line in md.splitlines() if line.startswith("## ")) - print(f"[ok] wrote {target} ({concept_count} concepts)") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py b/.claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py deleted file mode 100644 index 6920f42..0000000 --- a/.claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py +++ /dev/null @@ -1,576 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -r"""Audit ``→ mathlib: ...`` and ``→ formalized: ...`` annotations. - -This script does not itself call the Lean toolchain — the actual existence -check is performed by the caller (Claude) via the -``mcp__lean-lsp__lean_verify`` MCP tool, one symbol at a time. The script -is the mechanical half: - -- ``extract`` Walk the references root, pull every ``→ mathlib: ...`` and - ``→ formalized: ...`` annotation into a JSON worklist - (each item carries a ``kind`` field discriminating the - two). The caller feeds each candidate symbol to - ``lean_verify`` and records failures in a ``failed.json``. -- ``mark-unverified`` Given the caller's ``failed.json``, rewrite each - offending INDEX.md bullet so the annotation becomes - ``→ mathlib: \`<path>\` [UNVERIFIED]`` (or - ``→ formalized: \`<path>\` [UNVERIFIED]``) — a marker that - ``gap-filler``'s ``detect_gaps.py`` reads as ``suspect`` - status. - -Rationale: we do not want to trust Claude's judgement on whether a Lean -declaration exists. The T1-A remediation is to externalise verification -to the Lean MCP and mark anything that can not be proven to exist. The -same loop applies to ``→ formalized:`` — local declarations rot when -files are renamed, so verifying them on every ingestion catches drift. - -Usage: - python3 verify_mathlib_refs.py extract <references-root> [--output worklist.json] - python3 verify_mathlib_refs.py mark-unverified <references-root> \\ - --from failed.json [--dry-run] - -The ``failed.json`` schema expected by ``mark-unverified`` is: - - [ - { - "slug": "arxiv-2202.03357", - "line": 47, - "reason": "Mathlib.FakeName.notAReal not found by lean_verify" - }, - ... - ] -""" - -from __future__ import annotations - -import argparse -import datetime as _dt -import json -import re -import subprocess -import sys -from pathlib import Path - - -# Path to the sibling skill's ``issues.py`` (gap-filler owns the tracker -# format; this script is its biggest auto-producer). The lookup is -# best-effort: if the file is missing we silently skip issue creation so -# the verification cycle still works on a partial install. -_ISSUES_SCRIPT = ( - Path(__file__).resolve().parents[2] / "gap-filler" / "scripts" / "issues.py" -) - - -KEY_CONCEPTS_HEADER = re.compile(r"^##\s+Key concepts\s*$", re.IGNORECASE) -NEXT_H2 = re.compile(r"^##\s+") -BULLET = re.compile(r"^\s*-\s+(.*)$") -# Splits a bullet body around a ``→ mathlib:`` or ``→ formalized:`` marker. -# Group 2 captures which kind matched so each worklist item carries a -# ``kind`` field (``mathlib`` vs ``formalized``). -ANNOT_SPLIT = re.compile( - r"(\s*→\s*(mathlib|formalized)\s*:\s*)", re.IGNORECASE -) -TICKED = re.compile(r"`([^`]+)`") -UNVERIFIED_MARKER = "[UNVERIFIED]" -VERIFIED_FIELD = "mathlib_verified" -STALE_SKEW_SECONDS = 5 - - -def _read_slug(md_text: str, fallback: str) -> str: - in_front = False - for line in md_text.splitlines(): - if line.strip() == "---": - if not in_front: - in_front = True - continue - break - if in_front: - m = re.match(r"^slug\s*:\s*(.+)$", line) - if m: - return m.group(1).strip().strip('"').strip("'") - return fallback - - -def _extract_concept_name(body: str) -> str: - m = re.match(r"^`([^`]+)`", body) - if m: - return m.group(1).strip() - head = body.split("—", 1)[0].split(":", 1)[0].split("(", 1)[0].strip() - return head[:80] - - -IDENT_OR_QUALIFIED = re.compile(r"^[A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*$") - - -def _collect_candidates(annotation_body: str, concept: str) -> list[str]: - """Enumerate things the caller should try passing to ``lean_verify``. - - Order of preference: - 1. Backticked tokens in the annotation (both module paths and decl names). - 2. Bare ``Foo.Bar.baz`` tokens in the annotation (typical of bullets - where the author wrapped only the concept, not the mathlib path). - 3. The bullet's leading backticked concept head itself — often a decl - name (e.g. ``VonNeumannAlgebra``) that exists without any extra - hint in the annotation. - - Duplicates are preserved (order matters for the verifier; we try the - more specific candidate first) but obvious module-path tokens are - kept because ``lean_verify`` can also check a namespace. - """ - candidates: list[str] = [] - - for token in TICKED.findall(annotation_body): - token = token.strip() - if IDENT_OR_QUALIFIED.match(token): - candidates.append(token) - - for bare in re.findall(r"[A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)+", annotation_body): - if bare not in candidates: - candidates.append(bare) - - concept = concept.strip() - if concept and IDENT_OR_QUALIFIED.match(concept) and concept not in candidates: - candidates.append(concept) - - return candidates - - -def iter_index_files(root: Path): - for entry in sorted(root.iterdir()): - if not entry.is_dir(): - continue - index = entry / "INDEX.md" - if index.is_file(): - yield entry.name, index - - -def extract(root: Path) -> dict: - items: list[dict] = [] - for slug_dirname, index_path in iter_index_files(root): - text = index_path.read_text(encoding="utf-8", errors="replace") - slug = _read_slug(text, slug_dirname) - lines = text.splitlines() - inside = False - for idx, line in enumerate(lines, start=1): - if KEY_CONCEPTS_HEADER.match(line): - inside = True - continue - if inside and NEXT_H2.match(line): - break - if not inside: - continue - bullet = BULLET.match(line) - if not bullet: - continue - body = bullet.group(1).strip() - if not body or body.startswith("<!--"): - continue - parts = ANNOT_SPLIT.split(body, maxsplit=1) - # ANNOT_SPLIT has two capture groups: ``(full_marker, kind)`` — - # so ``re.split`` returns ``[before, full_marker, kind, after]``. - if len(parts) < 4: - continue - full_marker, kind, after = parts[1], parts[2].lower(), parts[3] - annotation = full_marker + after - if UNVERIFIED_MARKER in annotation: - continue # already flagged; leave alone - concept = _extract_concept_name(body) - candidates = _collect_candidates(after, concept) - if not candidates: - continue - items.append( - { - "slug": slug, - "index_path": str(index_path), - "line": idx, - "kind": kind, - "concept": concept, - "raw_annotation": annotation.strip(), - "candidates": candidates, - } - ) - return { - "references_root": str(root), - "total_items": len(items), - "items": items, - } - - -def _frontmatter_span(text: str) -> tuple[int, int] | None: - """Return ``(open_line, close_line)`` of the YAML fences (1-indexed, inclusive).""" - lines = text.splitlines() - if not lines or lines[0].strip() != "---": - return None - for i in range(1, len(lines)): - if lines[i].strip() == "---": - return (1, i + 1) - return None - - -def _set_frontmatter_field(index_path: Path, field: str, value: str) -> bool: - text = index_path.read_text(encoding="utf-8", errors="replace") - span = _frontmatter_span(text) - if span is None: - return False - had_trailing_nl = text.endswith("\n") - lines = text.splitlines(keepends=True) - open_ln, close_ln = span - field_re = re.compile(rf"^{re.escape(field)}\s*:\s*.*$") - # Replace existing field if present. - for idx in range(open_ln, close_ln - 1): - stripped = lines[idx].rstrip("\n") - if field_re.match(stripped): - lines[idx] = f"{field}: {value}\n" - index_path.write_text("".join(lines), encoding="utf-8") - return True - # Otherwise insert directly before the closing fence. - insert_at = close_ln - 1 - lines.insert(insert_at, f"{field}: {value}\n") - patched = "".join(lines) - if not had_trailing_nl and patched.endswith("\n"): - patched = patched.rstrip("\n") - index_path.write_text(patched, encoding="utf-8") - return True - - -def _read_frontmatter_field(index_path: Path, field: str) -> str | None: - text = index_path.read_text(encoding="utf-8", errors="replace") - span = _frontmatter_span(text) - if span is None: - return None - lines = text.splitlines() - field_re = re.compile(rf"^{re.escape(field)}\s*:\s*(.+)$") - for idx in range(span[0], span[1] - 1): - m = field_re.match(lines[idx]) - if m: - return m.group(1).strip().strip('"').strip("'") - return None - - -def _bullet_metadata(line: str) -> dict: - """Extract the kind / concept / candidate visible on a Key concepts bullet.""" - info = {"kind": "mathlib", "concept": "", "candidate": ""} - m_kind = re.search( - r"→\s*(formalized|mathlib)\s*:\s*(.*)$", line, re.IGNORECASE - ) - if m_kind: - info["kind"] = m_kind.group(1).lower() - # First backticked or qualified token after the marker is the - # candidate the verifier rejected. - tail = m_kind.group(2) - m_tick = re.search(r"`([^`]+)`", tail) - if m_tick: - info["candidate"] = m_tick.group(1).strip() - else: - m_bare = re.search(r"[A-Za-z_][\w.]+", tail) - if m_bare: - info["candidate"] = m_bare.group(0).strip() - m_concept = re.search(r"`([^`]+)`", line) - if m_concept: - info["concept"] = m_concept.group(1).strip() - return info - - -def _mark_one( - index_path: Path, line_no: int, reason: str, *, dry_run: bool -) -> dict | None: - """Patch the bullet at *line_no* with ``[UNVERIFIED]``. - - Returns ``None`` if no patch was applied (out-of-range or already - flagged). Otherwise returns a record carrying the bullet's - ``kind`` / ``concept`` / ``candidate`` metadata so the caller can - open a matching tracker issue. - """ - text = index_path.read_text(encoding="utf-8", errors="replace") - lines = text.splitlines(keepends=True) - if line_no < 1 or line_no > len(lines): - print(f"[warn] out-of-range line {line_no} in {index_path}", file=sys.stderr) - return None - original = lines[line_no - 1] - if UNVERIFIED_MARKER in original: - return None # nothing to do - had_trailing_nl = original.endswith("\n") - stripped = original.rstrip("\n") - metadata = _bullet_metadata(stripped) - # Append the marker at the very end of the bullet; reason optional. - if reason: - patched = f"{stripped} {UNVERIFIED_MARKER} ({reason})" - else: - patched = f"{stripped} {UNVERIFIED_MARKER}" - lines[line_no - 1] = patched + ("\n" if had_trailing_nl else "") - if dry_run: - print(f"[dry-run] {index_path}:{line_no}: {stripped!r} -> {patched!r}") - return metadata - index_path.write_text("".join(lines), encoding="utf-8") - return metadata - - -def _open_issue_for_failure( - references_root: Path, - *, - slug: str, - metadata: dict, - reason: str, -) -> dict | None: - """Best-effort issue creation via the sibling ``issues.py`` CLI. - - Returns the parsed JSON output of ``issues.py add`` on success, or - ``None`` when the script is unavailable (partial install) or the - invocation fails. - """ - if not _ISSUES_SCRIPT.is_file(): - return None - kind = "unverified-formalized-ref" if metadata.get("kind") == "formalized" else "unverified-mathlib-ref" - cmd = [ - sys.executable, - str(_ISSUES_SCRIPT), - "add", - str(references_root), - "--kind", - kind, - "--opened-by", - "verify_mathlib_refs.mark_unverified", - ] - if slug: - cmd += ["--slug", slug] - if metadata.get("concept"): - cmd += ["--concept", metadata["concept"]] - if metadata.get("candidate"): - cmd += ["--candidate", metadata["candidate"]] - if reason: - cmd += ["--reason", reason] - cmd += [ - "--suggested-action", - "Re-search a candidate or open gap-filler to ingest a better source.", - ] - try: - result = subprocess.run( - cmd, capture_output=True, text=True, check=True, timeout=15 - ) - except (subprocess.SubprocessError, OSError) as exc: - print(f"[warn] issues.py add failed for {slug}: {exc}", file=sys.stderr) - return None - out = result.stdout.strip() - try: - return json.loads(out) if out else None - except json.JSONDecodeError: - return None - - -def mark_unverified( - root: Path, failures: list[dict], *, dry_run: bool, create_issues: bool = True -) -> dict: - marked = 0 - skipped = 0 - per_slug: dict[str, list[int]] = {} - issues_opened: list[dict] = [] - for idx, failure in enumerate(failures, start=1): - if not isinstance(failure, dict): - print(f"[warn] failure #{idx} is not an object", file=sys.stderr) - skipped += 1 - continue - slug_raw = failure.get("slug") - if not isinstance(slug_raw, str) or not slug_raw.strip(): - print(f"[warn] failure #{idx} has no usable slug", file=sys.stderr) - skipped += 1 - continue - slug = slug_raw.strip() - line_raw = failure.get("line") - try: - if isinstance(line_raw, bool): - raise ValueError - line_no = int(line_raw) - except (TypeError, ValueError): - print( - f"[warn] failure #{idx} has invalid line {line_raw!r}", - file=sys.stderr, - ) - skipped += 1 - continue - if line_no < 1: - print( - f"[warn] failure #{idx} has out-of-range line {line_no}", - file=sys.stderr, - ) - skipped += 1 - continue - reason_raw = failure.get("reason") - reason = reason_raw.strip() if isinstance(reason_raw, str) else "" - index_path = root / slug / "INDEX.md" - if not index_path.is_file(): - print(f"[warn] missing INDEX.md for slug {slug!r}", file=sys.stderr) - skipped += 1 - continue - metadata = _mark_one(index_path, line_no, reason, dry_run=dry_run) - if metadata is not None: - marked += 1 - per_slug.setdefault(slug, []).append(line_no) - if create_issues and not dry_run: - opened = _open_issue_for_failure( - root, slug=slug, metadata=metadata, reason=reason - ) - if opened: - issues_opened.append({"slug": slug, **opened}) - else: - skipped += 1 - # After patching (real mode), stamp every INDEX.md with a fresh - # ``mathlib_verified`` marker so ``check-done`` can prove the - # verification cycle actually ran on this tree. - stamped: list[str] = [] - if not dry_run: - timestamp = _dt.datetime.now(_dt.timezone.utc).isoformat(timespec="seconds") - for slug_dirname, index_path in iter_index_files(root): - if _set_frontmatter_field(index_path, VERIFIED_FIELD, timestamp): - stamped.append(slug_dirname) - return { - "marked": marked, - "skipped": skipped, - "per_slug": per_slug, - "dry_run": dry_run, - "stamped_slugs": stamped, - "issues_opened": issues_opened, - } - - -def check_done(root: Path) -> dict: - """Confirm every INDEX.md under ``root`` carries a fresh verification marker. - - Returns a report with ``ok`` (True when the tree is verified clean), - ``unverified`` (slugs whose INDEX.md lacks the stamp or has a - malformed timestamp) and ``stale`` (slugs whose INDEX.md was edited - after the last verification). - """ - unverified: list[dict] = [] - stale: list[dict] = [] - ok_slugs: list[str] = [] - for slug_dirname, index_path in iter_index_files(root): - stamp_raw = _read_frontmatter_field(index_path, VERIFIED_FIELD) - if not stamp_raw: - unverified.append( - {"slug": slug_dirname, "path": str(index_path), "reason": "no mathlib_verified field"} - ) - continue - try: - stamp = _dt.datetime.fromisoformat(stamp_raw) - if stamp.tzinfo is None: - stamp = stamp.replace(tzinfo=_dt.timezone.utc) - except ValueError: - unverified.append( - { - "slug": slug_dirname, - "path": str(index_path), - "reason": f"unparseable timestamp {stamp_raw!r}", - } - ) - continue - mtime = _dt.datetime.fromtimestamp( - index_path.stat().st_mtime, _dt.timezone.utc - ) - if mtime > stamp + _dt.timedelta(seconds=STALE_SKEW_SECONDS): - stale.append( - { - "slug": slug_dirname, - "path": str(index_path), - "verified_at": stamp.isoformat(), - "mtime": mtime.isoformat(), - } - ) - continue - ok_slugs.append(slug_dirname) - return { - "ok": not unverified and not stale, - "verified_slugs": ok_slugs, - "unverified": unverified, - "stale": stale, - } - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - sub = parser.add_subparsers(dest="cmd", required=True) - - p_extract = sub.add_parser("extract", help="Extract mathlib annotation worklist") - p_extract.add_argument("references_root") - p_extract.add_argument("--output", default=None) - - p_mark = sub.add_parser("mark-unverified", help="Patch INDEX.md with [UNVERIFIED]") - p_mark.add_argument("references_root") - p_mark.add_argument("--from", dest="failures_path", required=True) - p_mark.add_argument("--dry-run", action="store_true") - p_mark.add_argument( - "--no-issues", - action="store_true", - help=( - "Suppress automatic issue creation under <root>/issues/. By " - "default each newly stamped [UNVERIFIED] bullet opens an " - "idempotent tracker entry so the false positive is not " - "forgotten across sessions." - ), - ) - - p_check = sub.add_parser( - "check-done", - help="Exit 1 if any INDEX.md lacks a fresh mathlib_verified stamp", - ) - p_check.add_argument("references_root") - - args = parser.parse_args() - - root = Path(args.references_root).expanduser().resolve() - if not root.is_dir(): - print(f"[error] not a directory: {root}", file=sys.stderr) - return 2 - - if args.cmd == "extract": - report = extract(root) - payload = json.dumps(report, indent=2, ensure_ascii=False) - if args.output: - Path(args.output).write_text(payload + "\n", encoding="utf-8") - print( - f"[ok] wrote {args.output}: {report['total_items']} mathlib annotations", - file=sys.stderr, - ) - else: - print(payload) - return 0 - - if args.cmd == "mark-unverified": - failures_raw = Path(args.failures_path).read_text(encoding="utf-8") - try: - failures = json.loads(failures_raw) - except json.JSONDecodeError as exc: - print(f"[error] bad JSON: {exc}", file=sys.stderr) - return 2 - if not isinstance(failures, list): - print("[error] failures JSON must be a list of objects", file=sys.stderr) - return 2 - summary = mark_unverified( - root, - failures, - dry_run=args.dry_run, - create_issues=not args.no_issues, - ) - print(json.dumps(summary, indent=2, ensure_ascii=False)) - return 0 - - if args.cmd == "check-done": - report = check_done(root) - print(json.dumps(report, indent=2, ensure_ascii=False)) - if report["ok"]: - return 0 - print( - f"[fail] {len(report['unverified'])} unverified + " - f"{len(report['stale'])} stale INDEX.md under {root}", - file=sys.stderr, - ) - return 1 - - return 2 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.claude/skills/web-to-knowledge/SKILL.md b/.claude/skills/web-to-knowledge/SKILL.md deleted file mode 100644 index 2531f73..0000000 --- a/.claude/skills/web-to-knowledge/SKILL.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -name: web-to-knowledge -description: Convert an HTML web page (Wikipedia article, nLab page, textbook chapter, blog post, documentation page) into agent-friendly Markdown with preserved LaTeX math and downloaded image assets, saved under `references/<slug>/` so coding agents can consult it across sessions. Use this skill whenever the user includes a URL that points at a human-readable HTML page (links like `en.wikipedia.org/wiki/...`, `ncatlab.org/nlab/show/...`, textbook TOC pages, software docs) or asks to "read", "reference", "import", "ingest", "use as knowledge", or "make available" a web page, even when they do not explicitly say "convert". Also trigger when the user wants to expand their existing `references/` with related articles that cite-or-are-cited-by a paper already under `references/`. Do NOT trigger for PDF URLs — those belong to the `pdf-to-knowledge` skill. ---- - -# web-to-knowledge - -Turn a web page into Markdown + images that a coding agent can navigate -efficiently. Output is shape-compatible with `pdf-to-knowledge` so the -shared `scripts/update_concepts.py` (lives in `pdf-to-knowledge`) indexes -concepts across both skills. - -## When to invoke - -- The user's message contains a URL ending in `/wiki/...`, `ncatlab.org/...`, - a documentation host, or anything that clearly resolves to an HTML page - (not `.pdf`). -- The user asks to "use this wiki/article/page as reference", "add this to - knowledge", "ingest this doc", etc. -- A previous `pdf-to-knowledge` ingestion referenced a Wikipedia or - textbook page as prerequisite knowledge and the user wants to pull it in - too — e.g. "also grab the Wikipedia article on modular automorphism group - from the references I just ingested". - -Do **not** invoke for: -- **PDF URLs** — use `pdf-to-knowledge` instead. This skill's parser assumes - HTML and will fail on `application/pdf`. -- One-shot "summarise this page" requests where the user does not want - persistent reference material — `WebFetch` is sufficient. - -## Output contract - -Everything lands under `<cwd>/references/<slug>/`, matching the -`pdf-to-knowledge` layout so `update_concepts.py` aggregates both. - -``` -references/<slug>/ -├── INDEX.md # metadata + Summary + Key concepts + External links + ToC (you fill 3 sections) -├── content.md # page Markdown with preserved LaTeX math and relative image links -└── assets/ # downloaded images referenced from content.md -``` - -Slug conventions: -- Wikipedia → `wiki-<kebab-title>` (e.g. `wiki-tomita-takesaki-theory`). -- nLab → `nlab-<kebab-title>` (e.g. `nlab-relative-entropy`). -- Other hosts → `web-<basehost>-<basename>`. - -Full format spec: `references/output-format.md`. - -## Workflow - -1. **Extract the URL.** Pull the web-page URL out of the user's message. - If multiple are present, ask which one to process unless the user - clearly meant all of them (then loop). - -2. **Decide on the output root.** Default to `references/` in the current - working directory (same convention as `pdf-to-knowledge` — already - gitignored in this project). - -3. **Run the fetcher.** Invoke the bundled script via `uv run` so the HTML - parsing dependencies install on demand into a cached virtualenv: - - ```bash - uv run .claude/skills/web-to-knowledge/scripts/fetch.py "<url>" - ``` - - Useful flags: - - `--output-dir <dir>` — override the `references/` root. - - `--slug <name>` — override the auto-derived slug. - - The script prints a JSON summary with `slug`, `output_dir`, `image_count`, - `formula_count`, and `final_url` (after redirects). - -4. **Fill in the INDEX.md scaffold.** The script leaves three sections as - `<!-- TODO -->`: - - a. **Summary** — 3–5 sentences answering "what does this page cover and - why would a coding agent consult it?". Base it on the actual content, - not the title alone. Read `content.md` first. - - b. **Key concepts** — bullet list of identifiers an agent would grep - for. **Each bullet must start with a `` `backtick-quoted` `` - identifier** — this is a hard format requirement so that - `scripts/update_concepts.py` (in `pdf-to-knowledge`) can aggregate - concepts across web and PDF sources under unified headers. Skip the - section entirely if the page has no greppable terminology. - - c. **External links** — optional free-form list of adjacent references - the page links to. Especially useful for Wikipedia / nLab articles - that contain "See also" sections pointing at related concepts: list - them here so a future agent knows what to ingest next. Two formats - are acceptable: - ``` - - [Modular conjugation](https://en.wikipedia.org/wiki/Modular_conjugation) — J operator on standard form - - [KMS state](https://ncatlab.org/nlab/show/KMS+state) — companion thermodynamic condition - ``` - or a single paragraph. Skip if the page has no meaningful outbound links. - - d. **Mathlib / local cross-reference** — same technique as - `pdf-to-knowledge` step 4d. For each Key concepts bullet, pick the - strongest tier that applies: - - - `→ formalized: QuantumSystem.X.y` if the concept is already proven - locally in this repository (verified via `lean_verify`). - - `→ mathlib: Mathlib.X.y` if a `lean_local_search <term>` or - `lean_local_search <author-name>` hit verifies cleanly. - - `→ needs formalization` if both searches miss. - - Skip entirely if the Lean MCP toolchain is unavailable. - - **Every annotation must pass through the step-6 verification - loop** — do not trust `lean_local_search` hits at face value. - - Keep `INDEX.md` concise (under ~80 lines). - -5. **Refresh the concept index (strict mode).** Call - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/update_concepts.py \ - --strict <references-root> - ``` - - (The script lives in `pdf-to-knowledge` — it is source-agnostic and - indexes any `<slug>/INDEX.md` under the root.) `--strict` fails with - exit 1 if any Key concepts bullet does not start with a - `` `backtick-quoted` `` identifier. Fix the offending bullets and - re-run; never leave format drift unfixed. - -6. **Verify every mathlib annotation** (only when Lean MCP tools are - available). Run - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py \ - extract <references-root> --output /tmp/mathlib-worklist.json - ``` - - Feed each candidate symbol to `mcp__lean-lsp__lean_verify`. Record - every item whose candidates all fail into a `failed.json`, then: - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py \ - mark-unverified <references-root> --from /tmp/failed.json - ``` - - This appends `[UNVERIFIED]` markers so `gap-filler` treats the - concepts as `suspect` rather than trusting the raw search hit, and - stamps every INDEX.md with a `mathlib_verified` timestamp in its - frontmatter. **Always run `mark-unverified`, even with an empty - `failed.json`** — the empty case is the happy path but still needs - to stamp the tree. Finish with - - ```bash - python3 .claude/skills/pdf-to-knowledge/scripts/verify_mathlib_refs.py \ - check-done <references-root> - ``` - - It exits 0 only when every INDEX.md carries a fresh stamp; treat - a non-zero exit as a hard failure. Re-run step 5 after patching so - `CONCEPTS.md` reflects the markers. - -7. **Report back to the user.** Tell them the `INDEX.md` path, the - formula/image counts, and whether any mathlib matches surfaced - (and how many were downgraded to `[UNVERIFIED]` in step 6). Do not - paste the full summary into chat — they can read the file. - -## Why this design - -- **Share the output shape with `pdf-to-knowledge`.** A single - `references/<slug>/` convention and a single `CONCEPTS.md` across both - skills means an agent does not have to know whether a concept came from - a paper or a wiki — only that it was ingested. -- **Preserve LaTeX from HTML.** BeautifulSoup lets us surgically unwrap - MediaWiki's `<span class="mwe-math-element">` (which bundles MathML + - fallback image + `{\displaystyle ...}` annotation) into plain - `$...$`/`$$...$$` LaTeX. MathJax `<script>` tags and nLab's iTeX-rendered - `<math>` are handled similarly. A single-pass approach with - `trafilatura` silently drops every math element, so we skip it. -- **No full-text summarisation in the script.** Same rationale as - `pdf-to-knowledge`: Claude fills Summary / Key concepts / Mathlib - annotations because those are judgement calls that a regex cannot make - correctly. -- **GPL-free dependencies.** `beautifulsoup4`, `markdownify`, `lxml` are - all MIT/BSD. - -## Runtime prerequisites - -- **`uv`** on `PATH`. First invocation installs `beautifulsoup4`, - `markdownify`, `lxml` into a cached environment (~50 MB). -- **Network access** for both the page fetch and downloaded images. -- No external binaries or OS-level packages are required. - -## Failure modes to watch for - -- **Paywalled / login-gated pages.** The fetcher sends no cookies. If the - page returns HTML that omits the real content (common on Elsevier, - Springer, IEEE), the resulting `content.md` will be mostly nav / abstract. - Prefer the open-access version, or hand the user the paywall URL back. -- **JS-rendered pages.** MathJax rendered purely at client side (with no - `<math>` tag and no `<script type="math/tex">`) will lose formulas. - Wikipedia pages are safe; nLab is safe; some personal blogs and MkDocs - sites are not. Warn the user if `formula_count: 0` on a page you expected - to contain math. -- **arxiv.org URLs.** Route the user to `pdf-to-knowledge` — the arXiv - abstract page is low-signal and the companion PDF is much richer. -- **Image hotlinking failures.** Some CDNs block non-browser user agents. - Individual image failures are logged but the conversion still succeeds - with the original `<img src>` URL left in place for the affected image. diff --git a/.claude/skills/web-to-knowledge/references/output-format.md b/.claude/skills/web-to-knowledge/references/output-format.md deleted file mode 100644 index 42aff66..0000000 --- a/.claude/skills/web-to-knowledge/references/output-format.md +++ /dev/null @@ -1,119 +0,0 @@ -# Output format: `references/<slug>/` - -Per-page layout produced by `scripts/fetch.py`. Matches the -`pdf-to-knowledge` output contract so `update_concepts.py` can treat PDF -and web sources uniformly. - -## Directory layout - -``` -references/<slug>/ -├── INDEX.md # metadata + scaffolded Summary / Key concepts / External links + ToC -├── content.md # full page Markdown with preserved LaTeX math -└── assets/ # downloaded images referenced from content.md (only present when the page has images) -``` - -Exactly `INDEX.md` and `content.md` always exist. `assets/` is created -only when at least one image was downloaded. - -## Slug derivation - -- Wikipedia (`en.wikipedia.org/wiki/<Title>`) → - `wiki-<kebab-title>`. Hyphens and underscores unify, en-dashes collapse - (e.g. `Tomita–Takesaki_theory` → `wiki-tomita-takesaki-theory`). -- nLab (`ncatlab.org/nlab/show/<title>`) → `nlab-<kebab-title>` - (e.g. `relative+entropy` → `nlab-relative-entropy`). -- Everything else → `web-<basehost>-<path-basename>` - (e.g. `docs.python.org/3/library/pathlib.html` → - `web-python-pathlib`). -- `--slug` flag always wins. - -## `INDEX.md` structure - -```markdown ---- -title: "Page title" -source: "<original-url-given-to-the-tool>" -final_url: "<final-url-after-redirects>" -slug: <str> -assets: <int> -formulas: <int> # count of LaTeX math spans recovered from the HTML ---- - -# <title> - -## Summary -<!-- 3-5 sentences, filled in by Claude --> - -## Key concepts -<!-- bullet list; each bullet MUST start with `backtick-quoted` identifier --> - -## External links -<!-- optional: adjacent articles / related pages an agent may want to ingest next --> - -## Contents -- [Full content](content.md) - - [<H2 title>](content.md#<anchor>) - - ... -``` - -Frontmatter is plain YAML — machine-readable. The body is -human/agent-readable navigation. `Summary`, `Key concepts`, and -`External links` are scaffolded as `<!-- TODO -->` blocks; Claude replaces -them when filling in the workflow step 4. - -### ToC - -Always `- [Full content](content.md)` followed by indented entries for the -page's `##`/`###` headings (up to 30) with GitHub-style anchor fragments -(`content.md#foo-bar`). - -## Math handling - -- `<span class="mwe-math-element">` (Wikipedia wrapper): the MathML child - is parsed for `<annotation encoding="application/x-tex">TeX</annotation>` - or `alttext="TeX"`. The whole span — including the fallback `<img>` — - collapses to a single `$...$` / `$$...$$`. -- `<math display="block">` and plain `<math>` (nLab, some pages): same - parsing. -- `<img class="mwe-math-fallback-image-{inline,display}" alt="TeX">`: - handled as a last resort (for pages that do not inline MathML). -- MathJax `<script type="math/tex">...</script>` and - `<script type="math/tex; mode=display">...</script>`: extracted. -- `{\displaystyle ... }` wrappers injected by Wikipedia's MathML renderer - are unwrapped so the emitted LaTeX reads naturally. - -If a page appears to render math entirely client-side (no `<math>` / no -`math/tex` scripts), the `formulas` count drops to 0; the conversion still -succeeds for the prose but formulae are lost. - -## Image handling - -- Every `![alt](src)` in the generated Markdown triggers a fetch. `src` is - URL-joined to the page's final URL to resolve relative links. -- Images save to `assets/<slugified-stem>.<ext>` (max 60 chars). Collisions - are disambiguated with `-1`, `-2`, etc. -- Inline `data:` URIs are dropped — they usually represent small icons - (bullets, separators) that agents do not care about. -- Supported extensions: `.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, `.webp`. - Anything else is written with `.img` extension and still referenced, - but agents should check content-type manually. - -Image download failures log a warning and leave the original `src` URL in -place, so the conversion never aborts mid-run because of a dead CDN. - -## Cross-document concept index - -`web-to-knowledge` does **not** ship its own `update_concepts.py`. The -`pdf-to-knowledge` script is source-agnostic — it scans every -`<slug>/INDEX.md` under the references root regardless of whether the -slug originated from a PDF or a web page. Run it once after any new -ingestion: - -```bash -python3 .claude/skills/pdf-to-knowledge/scripts/update_concepts.py references/ -``` - -The resulting `references/CONCEPTS.md` groups bullets from papers and -wikis under unified concept headers, which is the whole point of the -shared output shape. diff --git a/.claude/skills/web-to-knowledge/scripts/fetch.py b/.claude/skills/web-to-knowledge/scripts/fetch.py deleted file mode 100755 index 6bdf3ef..0000000 --- a/.claude/skills/web-to-knowledge/scripts/fetch.py +++ /dev/null @@ -1,481 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [ -# "beautifulsoup4>=4.12", -# "markdownify>=0.14", -# "lxml>=5.0", -# ] -# /// -"""Fetch a web page and save it as agent-friendly Markdown + image assets. - -Mirrors the output layout of ``pdf-to-knowledge``'s ``convert.py`` so that -``scripts/update_concepts.py`` (from that skill) aggregates concepts across -PDF and web sources into a single ``references/CONCEPTS.md``. - -Produces under ``<output-dir>/<slug>/``: - -- ``INDEX.md`` Metadata, ToC, scaffolded Summary / Key concepts / bibliography - sections that the caller (Claude) fills in after reading - ``content.md``. -- ``content.md`` Full page Markdown with preserved LaTeX math (``$...$`` / - ``$$...$$``) and relative image links. -- ``assets/`` Downloaded images referenced from ``content.md``. - -Design choices: -- HTML parsing uses BeautifulSoup + markdownify (both permissive licenses). - ``trafilatura`` was considered for content extraction but it strips - ``<math>`` elements silently; doing the cleanup ourselves lets us preserve - LaTeX via ``alt`` attributes and ``annotation encoding="application/x-tex"``. -- No section splitting: web pages do not have a natural page count; agents - jump via the H2/H3 anchors in the INDEX.md ToC instead. - -Usage: - uv run fetch.py <url> [--output-dir DIR] [--slug SLUG] -""" - -from __future__ import annotations - -import argparse -import json -import re -import sys -import urllib.parse -import urllib.request -from pathlib import Path -from typing import Iterable - - -def slugify(text: str) -> str: - text = text.lower().strip() - # Treat connectors as word separators BEFORE stripping non-word chars so - # nLab titles like "relative+entropy" stay "relative-entropy" and - # Wikipedia titles like "Tomita–Takesaki_theory" (with en-dash) keep - # the split. - text = re.sub(r"[\s_+\-\u2010-\u2015]+", "-", text) - text = re.sub(r"[^\w-]", "", text, flags=re.UNICODE) - text = re.sub(r"-+", "-", text) - return text[:80].strip("-") or "page" - - -def derive_slug(url: str) -> str: - """Pick a descriptive slug based on known hosts and URL path.""" - parsed = urllib.parse.urlparse(url) - host = parsed.netloc.lower() - path = urllib.parse.unquote(parsed.path) - - # Wikipedia: https://en.wikipedia.org/wiki/<Title> - m = re.match(r"^/wiki/([^/?#]+)$", path) - if m and "wikipedia.org" in host: - return f"wiki-{slugify(m.group(1))}" - - # nLab: https://ncatlab.org/nlab/show/<title> - m = re.match(r"^/nlab/show/(.+)$", path) - if m and "ncatlab.org" in host: - return f"nlab-{slugify(m.group(1))}" - - # Generic: host-path slug - base_host = host.split(".")[-2] if "." in host else host - tail = Path(path).name or Path(path).stem or "index" - return f"web-{base_host}-{slugify(tail)}" - - -def fetch_html(url: str) -> tuple[str, str]: - """Download HTML. Returns (html_text, final_url) — the URL may redirect.""" - req = urllib.request.Request( - url, - headers={ - "User-Agent": "web-to-knowledge/1.0 (+https://github.com/anthropics/claude-code)" - }, - ) - with urllib.request.urlopen(req, timeout=60) as resp: - final_url = resp.url - raw = resp.read() - charset = resp.headers.get_content_charset() or "utf-8" - return raw.decode(charset, errors="replace"), final_url - - -def find_main_content(soup): - """Locate the substantive body of the page using common conventions.""" - for selector in [ - "main", - "article", - "[role=main]", - ".mw-parser-output", - "#mw-content-text", - "#content", - ]: - found = soup.select_one(selector) - if found: - return found - return soup.body or soup - - -def strip_non_content(root) -> None: - """Remove navigation, footers, scripts, styles, and known sidebars.""" - noisy_tags = ["script", "style", "nav", "footer", "aside", "noscript", "iframe"] - for tag in root.find_all(noisy_tags): - tag.decompose() - # Wikipedia / nLab specific noise. - noise_class_patterns = [ - r"mw-editsection", - r"mw-cite-backlink", - r"navbox", - r"navigation-not-searchable", - r"reference-list-only", - r"printfooter", - r"toc\b", - r"sidebar", - r"noprint", - r"catlinks", - ] - compiled = re.compile("|".join(noise_class_patterns)) - for tag in root.find_all(class_=compiled): - tag.decompose() - for tag in root.find_all(id=re.compile(r"^(toc|siteSub|contentSub|footer|mw-navigation|catlinks|jump-to-nav)$")): - tag.decompose() - - -_MATHML_TEX_ENCODING = re.compile(r"x-tex|TeX", re.IGNORECASE) -_DISPLAYSTYLE_WRAPPER = re.compile(r"^\s*\{\\displaystyle\s+(.+)\}\s*$", re.DOTALL) - - -def _strip_displaystyle(tex: str) -> str: - """Unwrap ``{\\displaystyle ...}`` added by Wikipedia MathML rendering.""" - tex = tex.strip() - m = _DISPLAYSTYLE_WRAPPER.match(tex) - if m: - inner = m.group(1).strip() - # Only unwrap when braces balance in the inner body, to avoid breaking - # LaTeX with intentional outer braces. - if inner.count("{") == inner.count("}"): - return inner - return tex - - -def _extract_tex_from_math(math) -> str | None: - ann = math.find("annotation", attrs={"encoding": _MATHML_TEX_ENCODING}) - if ann and ann.get_text(strip=True): - return ann.get_text(strip=True) - if math.get("alttext"): - return math["alttext"].strip() - return None - - -def preserve_math_tags(root, NavigableString) -> int: - """Rewrite common math embeddings to inline/display LaTeX. - - Returns the number of formulas found. Handles: - - - Wikipedia wrapper ``<span class="mwe-math-element">`` containing both a - ``<math>`` and a fallback ``<img>`` — collapsed to a single LaTeX span. - - Bare ``<math>`` with ``<annotation encoding="application/x-tex">TeX</annotation>`` - or ``alttext="TeX"`` (nLab, MediaWiki without the wrapper). - - Bare ``<img class="mwe-math-fallback-image-*" alt="TeX">`` without the - wrapper span. - - MathJax ``<script type="math/tex">...</script>`` / - ``<script type="math/tex; mode=display">``. - - ``{\\displaystyle ...}`` wrappers that Wikipedia injects around every - inline MathML expression are unwrapped so the emitted LaTeX reads - naturally. - """ - count = 0 - - # 1. Wikipedia math-element wrappers — unify the MathML + image fallback. - for span in root.find_all("span", class_="mwe-math-element"): - math = span.find("math") - tex = _extract_tex_from_math(math) if math else None - if not tex: - img = span.find("img", class_=re.compile(r"mwe-math-fallback-image")) - if img and img.get("alt"): - tex = img["alt"].strip() - if not tex: - continue - classes = span.get("class") or [] - display = any("mwe-math-element" in c and "display" in c for c in classes) - if not display and math is not None: - display = math.get("display") == "block" - tex = _strip_displaystyle(tex) - wrapped = f"$$\n{tex}\n$$" if display else f"${tex}$" - span.replace_with(NavigableString(wrapped)) - count += 1 - - # 2. Bare MathML elements not wrapped by MediaWiki. - for math in root.find_all("math"): - tex = _extract_tex_from_math(math) - if not tex: - continue - display = math.get("display") == "block" - tex = _strip_displaystyle(tex) - wrapped = f"$$\n{tex}\n$$" if display else f"${tex}$" - math.replace_with(NavigableString(wrapped)) - count += 1 - - # 3. Bare Wikipedia fallback images. - for img in root.find_all("img", class_=re.compile(r"mwe-math-fallback-image")): - alt = img.get("alt", "").strip() - if not alt: - continue - classes = img.get("class") or [] - display = any("display" in c for c in classes) - alt = _strip_displaystyle(alt) - wrapped = f"$$\n{alt}\n$$" if display else f"${alt}$" - img.replace_with(NavigableString(wrapped)) - count += 1 - - # 4. MathJax scripts. - for script in root.find_all( - "script", attrs={"type": re.compile(r"math/tex", re.IGNORECASE)} - ): - tex = script.get_text().strip() - if not tex: - continue - type_attr = script.get("type") or "" - display = "display" in type_attr.lower() - tex = _strip_displaystyle(tex) - wrapped = f"$$\n{tex}\n$$" if display else f"${tex}$" - script.replace_with(NavigableString(wrapped)) - count += 1 - - return count - - -def download_image(url: str, dest: Path) -> bool: - """Fetch ``url`` to ``dest``. Returns True on success, False otherwise.""" - try: - req = urllib.request.Request( - url, headers={"User-Agent": "web-to-knowledge/1.0"} - ) - with urllib.request.urlopen(req, timeout=30) as resp: - data = resp.read() - dest.write_bytes(data) - return True - except Exception as exc: - print(f"[warn] image download failed: {url} ({exc})", file=sys.stderr) - return False - - -def safe_image_name(url: str) -> str: - """Derive a filename from an image URL, preserving the extension.""" - parsed = urllib.parse.urlparse(url) - raw = Path(urllib.parse.unquote(parsed.path)).name or "image" - # Collapse overly long / weird chars; keep extension. - stem = Path(raw).stem - suffix = Path(raw).suffix.lower() - if suffix not in {".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"}: - suffix = ".img" - return slugify(stem)[:60] + suffix - - -def collect_and_rewrite_images( - md_text: str, base_url: str, assets_dir: Path -) -> tuple[str, int]: - """Download ``![...](src)`` images to ``assets/`` and rewrite refs. - - Returns the rewritten Markdown and the number of images saved. - """ - pattern = re.compile(r"!\[([^\]]*)\]\(([^)\s]+)(?:\s+\"[^\"]*\")?\)") - seen: dict[str, str] = {} - saved = 0 - - def replace(match: re.Match) -> str: - nonlocal saved - alt = match.group(1) - src = match.group(2) - if src.startswith("data:"): - return "" # drop inline data URIs - if src in seen: - return f"![{alt}](assets/{seen[src]})" - abs_url = urllib.parse.urljoin(base_url, src) - name = safe_image_name(abs_url) - # Avoid collisions with an incrementing counter. - candidate = name - n = 1 - while (assets_dir / candidate).exists(): - candidate = f"{Path(name).stem}-{n}{Path(name).suffix}" - n += 1 - assets_dir.mkdir(parents=True, exist_ok=True) - if download_image(abs_url, assets_dir / candidate): - seen[src] = candidate - saved += 1 - return f"![{alt}](assets/{candidate})" - return f"![{alt}]({src})" # keep original on failure - - return pattern.sub(replace, md_text), saved - - -def extract_page_title(soup, fallback: str) -> str: - for selector in ["h1.firstHeading", "h1", "title"]: - el = soup.select_one(selector) - if el and el.get_text(strip=True): - return el.get_text(strip=True) - return fallback - - -# Common LaTeX control sequences that survive markdownify only when the page -# already served inline ``$...$`` text (rare) or when MathJax rendered to -# HTML without an accompanying ``<math>`` / ``<script type=math/tex>`` node. -# Seeing many of these with ``formula_count == 0`` strongly suggests the -# page uses JS-only rendering and our math preservation layer missed it. -_MATH_HINTS = re.compile( - r"\\(?:log|frac|sum|int|prod|sqrt|alpha|beta|gamma|delta|sigma|tau|phi|psi|lambda|rho|Omega|Delta|partial|times|cdot|mapsto|rightarrow|Rightarrow|forall|exists|mathbb|mathcal|mathrm|operatorname|ldots|cdots)\b" -) - - -def diagnose_math_loss(md_text: str, formula_count: int) -> str | None: - """Return a warning string when formulas appear to be silently lost. - - Heuristic: fetch.py preserved zero math blocks, but the body still - contains many raw LaTeX control sequences. This is the - pattern you get from a page whose math was rendered purely by - client-side MathJax without a paired ``<math>`` or - ``<script type=math/tex>`` element — our server-side HTML parsing - cannot see the result, so nothing gets wrapped in ``$...$``. - """ - if formula_count > 0: - return None - hits = len(_MATH_HINTS.findall(md_text)) - if hits < 5: - return None - return ( - f"{hits} LaTeX-like tokens (e.g. \\log, \\frac, \\sum) appear in the " - "markdown but formula_count is 0 — the page likely renders math " - "entirely client-side. Formulas will NOT round-trip as LaTeX; " - "treat the extracted content.md as lossy for equations." - ) - - -def _heading_level(line: str) -> int: - m = re.match(r"^(#{1,6}) \S", line) - return len(m.group(1)) if m else 0 - - -def _github_anchor(heading: str) -> str: - slug = heading.strip().lower() - slug = re.sub(r"[^\w\s-]", "", slug, flags=re.UNICODE) - slug = re.sub(r"\s+", "-", slug) - return slug.strip("-") - - -def _build_toc(md: str, max_entries: int = 30) -> list[str]: - lines = ["- [Full content](content.md)"] - count = 0 - for line in md.splitlines(): - m = re.match(r"^(##{1,2}) (.+)", line) - if not m: - continue - level = len(m.group(1)) - title = m.group(2).strip() - indent = " " if level == 2 else " " - anchor = _github_anchor(title) - lines.append(f"{indent}- [{title}](content.md#{anchor})") - count += 1 - if count >= max_entries: - break - return lines - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("url", help="URL of the page to fetch") - parser.add_argument( - "--output-dir", - default="references", - help="Parent directory; output goes under <output-dir>/<slug>/", - ) - parser.add_argument("--slug", default=None, help="Override the auto-derived slug") - args = parser.parse_args() - - # Lazy imports so --help works without deps installed. - from bs4 import BeautifulSoup, NavigableString - from markdownify import markdownify - - print(f"[info] Fetching {args.url}", file=sys.stderr) - html_text, final_url = fetch_html(args.url) - slug = args.slug or derive_slug(final_url) - output_root = Path(args.output_dir).expanduser().resolve() - output_dir = output_root / slug - output_dir.mkdir(parents=True, exist_ok=True) - - soup = BeautifulSoup(html_text, "lxml") - title = extract_page_title(soup, slug.replace("-", " ").title()) - - article = find_main_content(soup) - # Work on a fresh parsed copy to avoid mutating the original for title lookup. - article_soup = BeautifulSoup(str(article), "lxml") - strip_non_content(article_soup) - formula_count = preserve_math_tags(article_soup, NavigableString) - print(f"[info] Preserved {formula_count} math blocks", file=sys.stderr) - - md_text = markdownify( - str(article_soup), - heading_style="ATX", - escape_asterisks=False, - escape_underscores=False, - strip=["a"] if False else None, # keep links by default - ) - md_text = re.sub(r"\n{3,}", "\n\n", md_text).strip() + "\n" - - assets_dir = output_dir / "assets" - md_text, image_count = collect_and_rewrite_images(md_text, final_url, assets_dir) - - warning = diagnose_math_loss(md_text, formula_count) - if warning: - print(f"[warn] {warning}", file=sys.stderr) - - (output_dir / "content.md").write_text(md_text, encoding="utf-8") - - toc_lines = _build_toc(md_text) - index = [ - "---", - f"title: {json.dumps(title, ensure_ascii=False)}", - f"source: {json.dumps(args.url, ensure_ascii=False)}", - f"final_url: {json.dumps(final_url, ensure_ascii=False)}", - f"slug: {slug}", - f"assets: {image_count}", - f"formulas: {formula_count}", - "---", - "", - f"# {title}", - "", - "## Summary", - "", - "<!-- TODO: 3-5 sentence summary of what this page covers and why a coding", - " agent would consult it. Fill in after reading content.md. -->", - "", - "## Key concepts", - "", - "<!-- TODO: Bullet list of identifiers an agent would grep for. Each bullet", - " MUST start with a `backtick-quoted` identifier — this drives the", - " cross-document concept index shared with pdf-to-knowledge. Omit the", - " section if the page has no greppable terminology. -->", - "", - "## External links", - "", - "<!-- TODO: Optional — list related pages the current one links out to", - " (especially other Wikipedia / nLab articles an agent may want to", - " ingest next). Free-form; not a strict YAML schema. -->", - "", - "## Contents", - "", - *toc_lines, - "", - ] - (output_dir / "INDEX.md").write_text("\n".join(index), encoding="utf-8") - - summary = { - "slug": slug, - "output_dir": str(output_dir), - "index_path": str(output_dir / "INDEX.md"), - "image_count": image_count, - "formula_count": formula_count, - "final_url": final_url, - "math_loss_warning": warning, - } - print(json.dumps(summary, indent=2, ensure_ascii=False)) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) From 9e79362c439186e5162c83d9486af194c6444a9f Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 19:09:18 +0000 Subject: [PATCH 033/113] build: npx skills@latest add mattpocock/skills --- .agents/skills/codebase-design/DEEPENING.md | 37 ++++ .../skills/codebase-design/DESIGN-IT-TWICE.md | 44 ++++ .agents/skills/codebase-design/SKILL.md | 114 ++++++++++ .agents/skills/diagnosing-bugs/SKILL.md | 134 ++++++++++++ .../scripts/hitl-loop.template.sh | 41 ++++ .agents/skills/domain-modeling/ADR-FORMAT.md | 47 +++++ .../skills/domain-modeling/CONTEXT-FORMAT.md | 60 ++++++ .agents/skills/domain-modeling/SKILL.md | 74 +++++++ .agents/skills/grill-me/SKILL.md | 7 + .agents/skills/grill-with-docs/SKILL.md | 7 + .agents/skills/grilling/SKILL.md | 10 + .agents/skills/handoff/SKILL.md | 16 ++ .../HTML-REPORT.md | 123 +++++++++++ .../improve-codebase-architecture/SKILL.md | 66 ++++++ .../skills/writing-great-skills/GLOSSARY.md | 195 ++++++++++++++++++ .agents/skills/writing-great-skills/SKILL.md | 82 ++++++++ .claude/skills/codebase-design | 1 + .claude/skills/diagnosing-bugs | 1 + .claude/skills/domain-modeling | 1 + .claude/skills/grill-me | 1 + .claude/skills/grill-with-docs | 1 + .claude/skills/grilling | 1 + .claude/skills/handoff | 1 + .claude/skills/improve-codebase-architecture | 1 + .claude/skills/writing-great-skills | 1 + skills-lock.json | 59 ++++++ 26 files changed, 1125 insertions(+) create mode 100644 .agents/skills/codebase-design/DEEPENING.md create mode 100644 .agents/skills/codebase-design/DESIGN-IT-TWICE.md create mode 100644 .agents/skills/codebase-design/SKILL.md create mode 100644 .agents/skills/diagnosing-bugs/SKILL.md create mode 100644 .agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh create mode 100644 .agents/skills/domain-modeling/ADR-FORMAT.md create mode 100644 .agents/skills/domain-modeling/CONTEXT-FORMAT.md create mode 100644 .agents/skills/domain-modeling/SKILL.md create mode 100644 .agents/skills/grill-me/SKILL.md create mode 100644 .agents/skills/grill-with-docs/SKILL.md create mode 100644 .agents/skills/grilling/SKILL.md create mode 100644 .agents/skills/handoff/SKILL.md create mode 100644 .agents/skills/improve-codebase-architecture/HTML-REPORT.md create mode 100644 .agents/skills/improve-codebase-architecture/SKILL.md create mode 100644 .agents/skills/writing-great-skills/GLOSSARY.md create mode 100644 .agents/skills/writing-great-skills/SKILL.md create mode 120000 .claude/skills/codebase-design create mode 120000 .claude/skills/diagnosing-bugs create mode 120000 .claude/skills/domain-modeling create mode 120000 .claude/skills/grill-me create mode 120000 .claude/skills/grill-with-docs create mode 120000 .claude/skills/grilling create mode 120000 .claude/skills/handoff create mode 120000 .claude/skills/improve-codebase-architecture create mode 120000 .claude/skills/writing-great-skills create mode 100644 skills-lock.json diff --git a/.agents/skills/codebase-design/DEEPENING.md b/.agents/skills/codebase-design/DEEPENING.md new file mode 100644 index 0000000..3938457 --- /dev/null +++ b/.agents/skills/codebase-design/DEEPENING.md @@ -0,0 +1,37 @@ +# Deepening + +How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**. + +## Dependency categories + +When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam. + +### 1. In-process + +Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed. + +### 2. Local-substitutable + +Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface. + +### 3. Remote but owned (Ports & Adapters) + +Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter. + +Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."* + +### 4. True external (Mock) + +Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter. + +## Seam discipline + +- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection. +- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them. + +## Testing strategy: replace, don't layer + +- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them. +- Write new tests at the deepened module's interface. The **interface is the test surface**. +- Tests assert on observable outcomes through the interface, not internal state. +- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface. diff --git a/.agents/skills/codebase-design/DESIGN-IT-TWICE.md b/.agents/skills/codebase-design/DESIGN-IT-TWICE.md new file mode 100644 index 0000000..49a7c42 --- /dev/null +++ b/.agents/skills/codebase-design/DESIGN-IT-TWICE.md @@ -0,0 +1,44 @@ +# Design It Twice + +When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best. + +Uses the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**, **leverage**. + +## Process + +### 1. Frame the problem space + +Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate: + +- The constraints any new interface would need to satisfy +- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md)) +- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete + +Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel. + +### 2. Spawn sub-agents + +Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module. + +Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint: + +- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point." +- Agent 2: "Maximise flexibility — support many use cases and extension." +- Agent 3: "Optimise for the most common caller — make the default case trivial." +- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies." + +Include both [SKILL.md](SKILL.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language. + +Each sub-agent outputs: + +1. Interface (types, methods, params — plus invariants, ordering, error modes) +2. Usage example showing how callers use it +3. What the implementation hides behind the seam +4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md)) +5. Trade-offs — where leverage is high, where it's thin + +### 3. Present and compare + +Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**. + +After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu. diff --git a/.agents/skills/codebase-design/SKILL.md b/.agents/skills/codebase-design/SKILL.md new file mode 100644 index 0000000..16620c2 --- /dev/null +++ b/.agents/skills/codebase-design/SKILL.md @@ -0,0 +1,114 @@ +--- +name: codebase-design +description: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary. +--- + +# Codebase Design + +Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone. + +## Glossary + +Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point. + +**Module** — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service. + +**Interface** — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow — they refer only to the type-level surface). + +**Implementation** — what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise. + +**Depth** — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation. + +**Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context). + +**Adapter** — a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside). + +**Leverage** — what callers get from depth: more capability per unit of interface they learn. One implementation pays back across N call sites and M tests. + +**Locality** — what maintainers get from depth: change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere. + +## Deep vs shallow + +**Deep module** = small interface + lots of implementation: + +``` +┌─────────────────────┐ +│ Small Interface │ ← Few methods, simple params +├─────────────────────┤ +│ │ +│ Deep Implementation│ ← Complex logic hidden +│ │ +└─────────────────────┘ +``` + +**Shallow module** = large interface + little implementation (avoid): + +``` +┌─────────────────────────────────┐ +│ Large Interface │ ← Many methods, complex params +├─────────────────────────────────┤ +│ Thin Implementation │ ← Just passes through +└─────────────────────────────────┘ +``` + +When designing an interface, ask: + +- Can I reduce the number of methods? +- Can I simplify the parameters? +- Can I hide more complexity inside? + +## Principles + +- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface. +- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep. +- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape. +- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it. + +## Designing for testability + +Good interfaces make testing natural: + +1. **Accept dependencies, don't create them.** + + ```typescript + // Testable + function processOrder(order, paymentGateway) {} + + // Hard to test + function processOrder(order) { + const gateway = new StripeGateway(); + } + ``` + +2. **Return results, don't produce side effects.** + + ```typescript + // Testable + function calculateDiscount(cart): Discount {} + + // Hard to test + function applyDiscount(cart): void { + cart.total -= discount; + } + ``` + +3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup. + +## Relationships + +- A **Module** has exactly one **Interface** (the surface it presents to callers and tests). +- **Depth** is a property of a **Module**, measured against its **Interface**. +- A **Seam** is where a **Module**'s **Interface** lives. +- An **Adapter** sits at a **Seam** and satisfies the **Interface**. +- **Depth** produces **Leverage** for callers and **Locality** for maintainers. + +## Rejected framings + +- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead. +- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know. +- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**. + +## Going deeper + +- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing. +- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement. diff --git a/.agents/skills/diagnosing-bugs/SKILL.md b/.agents/skills/diagnosing-bugs/SKILL.md new file mode 100644 index 0000000..f400de7 --- /dev/null +++ b/.agents/skills/diagnosing-bugs/SKILL.md @@ -0,0 +1,134 @@ +--- +name: diagnosing-bugs +description: Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow. +--- + +# Diagnosing Bugs + +A discipline for hard bugs. Skip phases only when explicitly justified. + +When exploring the codebase, read `CONTEXT.md` (if it exists) to get a clear mental model of the relevant modules, and check ADRs in the area you're touching. + +## Phase 1 — Build a feedback loop + +**This is the skill.** Everything else is mechanical. If you have a **tight** pass/fail signal for the bug — one that goes red on _this_ bug — you will find the cause; bisection, hypothesis-testing, and instrumentation all just consume it. If you don't have one, no amount of staring at code will save you. + +Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.** + +### Ways to construct one — try them in roughly this order + +1. **Failing test** at whatever seam reaches the bug — unit, integration, e2e. +2. **Curl / HTTP script** against a running dev server. +3. **CLI invocation** with a fixture input, diffing stdout against a known-good snapshot. +4. **Headless browser script** (Playwright / Puppeteer) — drives the UI, asserts on DOM/console/network. +5. **Replay a captured trace.** Save a real network request / payload / event log to disk; replay it through the code path in isolation. +6. **Throwaway harness.** Spin up a minimal subset of the system (one service, mocked deps) that exercises the bug code path with a single function call. +7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode. +8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it. +9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs. +10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `scripts/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you. + +Build the right feedback loop, and the bug is 90% fixed. + +### Tighten the loop + +Treat the loop as a product. Once you have _a_ loop, **tighten** it: + +- Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.) +- Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".) +- Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.) + +A 30-second flaky loop is barely better than no loop; a 2-second deterministic one is tight — a debugging superpower. + +### Non-deterministic bugs + +The goal is not a clean repro but a **higher reproduction rate**. Loop the trigger 100×, parallelise, add stress, narrow timing windows, inject sleeps. A 50%-flake bug is debuggable; 1% is not — keep raising the rate until it's debuggable. + +### When you genuinely cannot build a loop + +Stop and say so explicitly. List what you tried. Ask the user for: (a) access to whatever environment reproduces it, (b) a captured artifact (HAR file, log dump, core dump, screen recording with timestamps), or (c) permission to add temporary production instrumentation. Do **not** proceed to hypothesise without a loop. + +### Completion criterion — a tight loop that goes red + +Phase 1 is done when the loop is **tight** and **red-capable**: you can name **one command** — a script path, a test invocation, a curl — that you have **already run at least once** (paste the invocation and its output), and that is: + +- [ ] **Red-capable** — it drives the actual bug code path and asserts the **user's exact symptom**, so it can go red on this bug and green once fixed. Not "runs without erroring" — it must be able to _catch this specific bug_. +- [ ] **Deterministic** — same verdict every run (flaky bugs: a pinned, high reproduction rate, per above). +- [ ] **Fast** — seconds, not minutes. +- [ ] **Agent-runnable** — you can run it unattended; a human in the loop only via `scripts/hitl-loop.template.sh`. + +If you catch yourself reading code to build a theory before this command exists, **stop — jumping straight to a hypothesis is the exact failure this skill prevents.** No red-capable command, no Phase 2. + +## Phase 2 — Reproduce + minimise + +Run the loop. Watch it go red — the bug appears. + +Confirm: + +- [ ] The loop produces the failure mode the **user** described — not a different failure that happens to be nearby. Wrong bug = wrong fix. +- [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against). +- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it. + +### Minimise + +Once it's red, shrink the repro to the **smallest scenario that still goes red**. Cut inputs, callers, config, data, and steps **one at a time**, re-running the loop after each cut — keep only what's load-bearing for the failure. + +Why bother: a minimal repro shrinks the hypothesis space in Phase 3 (fewer moving parts left to suspect) and becomes the clean regression test in Phase 5. + +Done when **every remaining element is load-bearing** — removing any one of them makes the loop go green. + +Do not proceed until you have reproduced **and** minimised. + +## Phase 3 — Hypothesise + +Generate **3–5 ranked hypotheses** before testing any of them. Single-hypothesis generation anchors on the first plausible idea. + +Each hypothesis must be **falsifiable**: state the prediction it makes. + +> Format: "If <X> is the cause, then <changing Y> will make the bug disappear / <changing Z> will make it worse." + +If you cannot state the prediction, the hypothesis is a vibe — discard or sharpen it. + +**Show the ranked list to the user before testing.** They often have domain knowledge that re-ranks instantly ("we just deployed a change to #3"), or know hypotheses they've already ruled out. Cheap checkpoint, big time saver. Don't block on it — proceed with your ranking if the user is AFK. + +## Phase 4 — Instrument + +Each probe must map to a specific prediction from Phase 3. **Change one variable at a time.** + +Tool preference: + +1. **Debugger / REPL inspection** if the env supports it. One breakpoint beats ten logs. +2. **Targeted logs** at the boundaries that distinguish hypotheses. +3. Never "log everything and grep". + +**Tag every debug log** with a unique prefix, e.g. `[DEBUG-a4f2]`. Cleanup at the end becomes a single grep. Untagged logs survive; tagged logs die. + +**Perf branch.** For performance regressions, logs are usually wrong. Instead: establish a baseline measurement (timing harness, `performance.now()`, profiler, query plan), then bisect. Measure first, fix second. + +## Phase 5 — Fix + regression test + +Write the regression test **before the fix** — but only if there is a **correct seam** for it. + +A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence. + +**If no correct seam exists, that itself is the finding.** Note it. The codebase architecture is preventing the bug from being locked down. Flag this for the next phase. + +If a correct seam exists: + +1. Turn the minimised repro into a failing test at that seam. +2. Watch it fail. +3. Apply the fix. +4. Watch it pass. +5. Re-run the Phase 1 feedback loop against the original (un-minimised) scenario. + +## Phase 6 — Cleanup + post-mortem + +Required before declaring done: + +- [ ] Original repro no longer reproduces (re-run the Phase 1 loop) +- [ ] Regression test passes (or absence of seam is documented) +- [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix) +- [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location) +- [ ] The hypothesis that turned out correct is stated in the commit / PR message — so the next debugger learns + +**Then ask: what would have prevented this bug?** If the answer involves architectural change (no good test seam, tangled callers, hidden coupling) hand off to the `/improve-codebase-architecture` skill with the specifics. Make the recommendation **after** the fix is in, not before — you have more information now than when you started. diff --git a/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh b/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh new file mode 100644 index 0000000..40afc46 --- /dev/null +++ b/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Human-in-the-loop reproduction loop. +# Copy this file, edit the steps below, and run it. +# The agent runs the script; the user follows prompts in their terminal. +# +# Usage: +# bash hitl-loop.template.sh +# +# Two helpers: +# step "<instruction>" → show instruction, wait for Enter +# capture VAR "<question>" → show question, read response into VAR +# +# At the end, captured values are printed as KEY=VALUE for the agent to parse. + +set -euo pipefail + +step() { + printf '\n>>> %s\n' "$1" + read -r -p " [Enter when done] " _ +} + +capture() { + local var="$1" question="$2" answer + printf '\n>>> %s\n' "$question" + read -r -p " > " answer + printf -v "$var" '%s' "$answer" +} + +# --- edit below --------------------------------------------------------- + +step "Open the app at http://localhost:3000 and sign in." + +capture ERRORED "Click the 'Export' button. Did it throw an error? (y/n)" + +capture ERROR_MSG "Paste the error message (or 'none'):" + +# --- edit above --------------------------------------------------------- + +printf '\n--- Captured ---\n' +printf 'ERRORED=%s\n' "$ERRORED" +printf 'ERROR_MSG=%s\n' "$ERROR_MSG" diff --git a/.agents/skills/domain-modeling/ADR-FORMAT.md b/.agents/skills/domain-modeling/ADR-FORMAT.md new file mode 100644 index 0000000..da7e78e --- /dev/null +++ b/.agents/skills/domain-modeling/ADR-FORMAT.md @@ -0,0 +1,47 @@ +# ADR Format + +ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc. + +Create the `docs/adr/` directory lazily — only when the first ADR is needed. + +## Template + +```md +# {Short title of the decision} + +{1-3 sentences: what's the context, what did we decide, and why.} +``` + +That's it. An ADR can be a single paragraph. The value is in recording *that* a decision was made and *why* — not in filling out sections. + +## Optional sections + +Only include these when they add genuine value. Most ADRs won't need them. + +- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited +- **Considered Options** — only when the rejected alternatives are worth remembering +- **Consequences** — only when non-obvious downstream effects need to be called out + +## Numbering + +Scan `docs/adr/` for the highest existing number and increment by one. + +## When to offer an ADR + +All three of these must be true: + +1. **Hard to reverse** — the cost of changing your mind later is meaningful +2. **Surprising without context** — a future reader will look at the code and wonder "why on earth did they do it this way?" +3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons + +If a decision is easy to reverse, skip it — you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing." + +### What qualifies + +- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres." +- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP." +- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out. +- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s. +- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate. +- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract." +- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months. diff --git a/.agents/skills/domain-modeling/CONTEXT-FORMAT.md b/.agents/skills/domain-modeling/CONTEXT-FORMAT.md new file mode 100644 index 0000000..eaf2a18 --- /dev/null +++ b/.agents/skills/domain-modeling/CONTEXT-FORMAT.md @@ -0,0 +1,60 @@ +# CONTEXT.md Format + +## Structure + +```md +# {Context Name} + +{One or two sentence description of what this context is and why it exists.} + +## Language + +**Order**: +{A one or two sentence description of the term} +_Avoid_: Purchase, transaction + +**Invoice**: +A request for payment sent to a customer after delivery. +_Avoid_: Bill, payment request + +**Customer**: +A person or organization that places orders. +_Avoid_: Client, buyer, account +``` + +## Rules + +- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`. +- **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does. +- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs. +- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine. + +## Single vs multi-context repos + +**Single context (most repos):** One `CONTEXT.md` at the repo root. + +**Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other: + +```md +# Context Map + +## Contexts + +- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders +- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments +- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping + +## Relationships + +- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking +- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices +- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money` +``` + +The skill infers which structure applies: + +- If `CONTEXT-MAP.md` exists, read it to find contexts +- If only a root `CONTEXT.md` exists, single context +- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved + +When multiple contexts exist, infer which one the current topic relates to. If unclear, ask. diff --git a/.agents/skills/domain-modeling/SKILL.md b/.agents/skills/domain-modeling/SKILL.md new file mode 100644 index 0000000..d0f7e1a --- /dev/null +++ b/.agents/skills/domain-modeling/SKILL.md @@ -0,0 +1,74 @@ +--- +name: domain-modeling +description: Build and sharpen a project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to maintain the domain model. +--- + +# Domain Modeling + +Actively build and sharpen the project's domain model as you design. This is the *active* discipline — challenging terms, inventing edge-case scenarios, and writing the glossary and decisions down the moment they crystallise. (Merely *reading* `CONTEXT.md` for vocabulary is not this skill — that's a one-line habit any skill can do. This skill is for when you're changing the model, not just consuming it.) + +## File structure + +Most repos have a single context: + +``` +/ +├── CONTEXT.md +├── docs/ +│ └── adr/ +│ ├── 0001-event-sourced-orders.md +│ └── 0002-postgres-for-write-model.md +└── src/ +``` + +If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives: + +``` +/ +├── CONTEXT-MAP.md +├── docs/ +│ └── adr/ ← system-wide decisions +├── src/ +│ ├── ordering/ +│ │ ├── CONTEXT.md +│ │ └── docs/adr/ ← context-specific decisions +│ └── billing/ +│ ├── CONTEXT.md +│ └── docs/adr/ +``` + +Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed. + +## During the session + +### Challenge against the glossary + +When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?" + +### Sharpen fuzzy language + +When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things." + +### Discuss concrete scenarios + +When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts. + +### Cross-reference with code + +When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?" + +### Update CONTEXT.md inline + +When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md). + +`CONTEXT.md` should be totally devoid of implementation details. Do not treat `CONTEXT.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else. + +### Offer ADRs sparingly + +Only offer to create an ADR when all three are true: + +1. **Hard to reverse** — the cost of changing your mind later is meaningful +2. **Surprising without context** — a future reader will wonder "why did they do it this way?" +3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons + +If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md). diff --git a/.agents/skills/grill-me/SKILL.md b/.agents/skills/grill-me/SKILL.md new file mode 100644 index 0000000..9470cfc --- /dev/null +++ b/.agents/skills/grill-me/SKILL.md @@ -0,0 +1,7 @@ +--- +name: grill-me +description: A relentless interview to sharpen a plan or design. +disable-model-invocation: true +--- + +Run a `/grilling` session. diff --git a/.agents/skills/grill-with-docs/SKILL.md b/.agents/skills/grill-with-docs/SKILL.md new file mode 100644 index 0000000..bed05d2 --- /dev/null +++ b/.agents/skills/grill-with-docs/SKILL.md @@ -0,0 +1,7 @@ +--- +name: grill-with-docs +description: A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go. +disable-model-invocation: true +--- + +Run a `/grilling` session, using the `/domain-modeling` skill. diff --git a/.agents/skills/grilling/SKILL.md b/.agents/skills/grilling/SKILL.md new file mode 100644 index 0000000..fe3569d --- /dev/null +++ b/.agents/skills/grilling/SKILL.md @@ -0,0 +1,10 @@ +--- +name: grilling +description: Interview the user relentlessly about a plan or design. Use when the user wants to stress-test a plan before building, or uses any 'grill' trigger phrases. +--- + +Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. + +Ask the questions one at a time, waiting for feedback on each question before continuing. Asking multiple questions at once is bewildering. + +If a question can be answered by exploring the codebase, explore the codebase instead. diff --git a/.agents/skills/handoff/SKILL.md b/.agents/skills/handoff/SKILL.md new file mode 100644 index 0000000..ec762d9 --- /dev/null +++ b/.agents/skills/handoff/SKILL.md @@ -0,0 +1,16 @@ +--- +name: handoff +description: Compact the current conversation into a handoff document for another agent to pick up. +argument-hint: "What will the next session be used for?" +disable-model-invocation: true +--- + +Write a handoff document summarising the current conversation so a fresh agent can continue the work. Save to the temporary directory of the user's OS - not the current workspace. + +Include a "suggested skills" section in the document, which suggests skills that the agent should invoke. + +Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead. + +Redact any sensitive information, such as API keys, passwords, or personally identifiable information. + +If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly. diff --git a/.agents/skills/improve-codebase-architecture/HTML-REPORT.md b/.agents/skills/improve-codebase-architecture/HTML-REPORT.md new file mode 100644 index 0000000..17f6d2c --- /dev/null +++ b/.agents/skills/improve-codebase-architecture/HTML-REPORT.md @@ -0,0 +1,123 @@ +# HTML Report Format + +The architectural review is rendered as a single self-contained HTML file in the OS temp directory. Tailwind and Mermaid both come from CDNs. Mermaid handles graph-shaped diagrams reliably; hand-built divs and inline SVG handle the more editorial visuals (mass diagrams, cross-sections). Mix the two — don't lean on Mermaid for everything, it'll start to look generic. + +## Scaffold + +```html +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <title>Architecture review — {{repo name}} + + + + + +
+
...
+
...
+
...
+
+ + +``` + +## Header + +Repo name, date, and a compact legend: solid box = module, dashed line = seam, red arrow = leakage, thick dark box = deep module. No introduction paragraph — straight into the candidates. + +## Candidate card + +The diagrams carry the weight. Prose is sparse, plain, and uses the glossary terms (from the `/codebase-design` skill) without ceremony. + +Each candidate is one `
`: + +- **Title** — short, names the deepening (e.g. "Collapse the Order intake pipeline"). +- **Badge row** — recommendation strength (`Strong` = emerald, `Worth exploring` = amber, `Speculative` = slate), plus a tag for the dependency category (`in-process`, `local-substitutable`, `ports & adapters`, `mock`). +- **Files** — monospaced list, `font-mono text-sm`. +- **Before / After diagram** — the centrepiece. Two columns, side by side. See patterns below. +- **Problem** — one sentence. What hurts. +- **Solution** — one sentence. What changes. +- **Wins** — bullets, ≤6 words each. e.g. "Tests hit one interface", "Pricing logic stops leaking", "Delete 4 shallow wrappers". +- **ADR callout** (if applicable) — one line in an amber-tinted box. + +No paragraphs of explanation. If the diagram needs a paragraph to be understood, redraw the diagram. + +## Diagram patterns + +Pick the pattern that fits the candidate. Mix them. Don't make every diagram look the same — variety is part of the point. + +### Mermaid graph (the workhorse for dependencies / call flow) + +Use a Mermaid `flowchart` or `graph` when the point is "X calls Y calls Z, and look at the mess." Wrap it in a Tailwind-styled card so it doesn't feel parachuted in. Style with classDef to colour leakage edges red and the deep module dark. Sequence diagrams work well for "before: 6 round-trips; after: 1." + +```html +
+
+    flowchart LR
+      A[OrderHandler] --> B[OrderValidator]
+      B --> C[OrderRepo]
+      C -.leak.-> D[PricingClient]
+      classDef leak stroke:#dc2626,stroke-width:2px;
+      class C,D leak
+  
+
+``` + +### Hand-built boxes-and-arrows (when Mermaid's layout fights you) + +Modules as `
`s with borders and labels. Arrows as inline SVG `` or `` elements positioned absolutely over a relative container. Reach for this when you want the "after" diagram to feel like one thick-bordered deep module with greyed-out internals — Mermaid won't render that with the right weight. + +### Cross-section (good for layered shallowness) + +Stack horizontal bands (`h-12 border-l-4`) to show layers a call passes through. Before: 6 thin layers each doing nothing. After: 1 thick band labelled with the consolidated responsibility. + +### Mass diagram (good for "interface as wide as implementation") + +Two rectangles per module — one for interface surface area, one for implementation. Before: interface rectangle is nearly as tall as the implementation rectangle (shallow). After: interface rectangle is short, implementation rectangle is tall (deep). + +### Call-graph collapse + +Before: a tree of function calls rendered as nested boxes. After: the same tree collapsed into one box, with the now-internal calls shown faded inside it. + +## Style guidance + +- Lean editorial, not corporate-dashboard. Generous whitespace. Serif optional for headings (`font-serif` works well with stone/slate). +- Colour sparingly: one accent (emerald or indigo) plus red for leakage and amber for warnings. +- Keep diagrams ~320px tall so before/after sits comfortably side by side without scrolling. +- Use `text-xs uppercase tracking-wider` for module labels inside diagrams — they should read as schematic, not as UI. +- The only scripts are the Tailwind CDN and the Mermaid ESM import. The report is otherwise static — no app code, no interactivity beyond Mermaid's own rendering. + +## Top recommendation section + +One larger card. Candidate name, one sentence on why, anchor link to its card. That's it. + +## Tone + +Plain English, concise — but the architectural nouns and verbs come straight from the `/codebase-design` skill. Concision is not an excuse to drift. + +**Use exactly:** module, interface, implementation, depth, deep, shallow, seam, adapter, leverage, locality. + +**Never substitute:** component, service, unit (for module) · API, signature (for interface) · boundary (for seam) · layer, wrapper (for module, when you mean module). + +**Phrasings that fit the style:** + +- "Order intake module is shallow — interface nearly matches the implementation." +- "Pricing leaks across the seam." +- "Deepen: one interface, one place to test." +- "Two adapters justify the seam: HTTP in prod, in-memory in tests." + +**Wins bullets** name the gain in glossary terms: *"locality: bugs concentrate in one module"*, *"leverage: one interface, N call sites"*, *"interface shrinks; implementation absorbs the wrappers"*. Don't write *"easier to maintain"* or *"cleaner code"* — those terms aren't in the glossary and don't earn their place. + +No hedging, no throat-clearing, no "it's worth noting that…". If a sentence could be a bullet, make it a bullet. If a bullet could be cut, cut it. If a term isn't in the `/codebase-design` glossary, reach for one that is before inventing a new one. diff --git a/.agents/skills/improve-codebase-architecture/SKILL.md b/.agents/skills/improve-codebase-architecture/SKILL.md new file mode 100644 index 0000000..a79b493 --- /dev/null +++ b/.agents/skills/improve-codebase-architecture/SKILL.md @@ -0,0 +1,66 @@ +--- +name: improve-codebase-architecture +description: Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick. +disable-model-invocation: true +--- + +# Improve Codebase Architecture + +Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability. + +This command is _informed_ by the project's domain model and built on a shared design vocabulary: + +- Run the `/codebase-design` skill for the architecture vocabulary (**module**, **interface**, **depth**, **seam**, **adapter**, **leverage**, **locality**) and its principles (the deletion test, "the interface is the test surface", "one adapter = hypothetical seam, two = real"). Use these terms exactly in every suggestion — don't drift into "component," "service," "API," or "boundary." +- The domain language in `CONTEXT.md` gives names to good seams; ADRs in `docs/adr/` record decisions this command should not re-litigate. + +## Process + +### 1. Explore + +Read the project's domain glossary (`CONTEXT.md`) and any ADRs in the area you're touching first. + +Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction: + +- Where does understanding one concept require bouncing between many small modules? +- Where are modules **shallow** — interface nearly as complex as the implementation? +- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)? +- Where do tightly-coupled modules leak across their seams? +- Which parts of the codebase are untested, or hard to test through their current interface? + +Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want. + +### 2. Present candidates as an HTML report + +Write a self-contained HTML file to the OS temp directory so nothing lands in the repo. Resolve the temp dir from `$TMPDIR`, falling back to `/tmp` (or `%TEMP%` on Windows), and write to `/architecture-review-.html` so each run gets a fresh file. Open it for the user — `xdg-open ` on Linux, `open ` on macOS, `start ` on Windows — and tell them the absolute path. + +The report uses **Tailwind via CDN** for layout and styling, and **Mermaid via CDN** for diagrams where a graph/flow/sequence reliably communicates the structure. Mix Mermaid with hand-crafted CSS/SVG visuals — use Mermaid when relationships are graph-shaped (call graphs, dependencies, sequences), and hand-built divs/SVG when you want something more editorial (mass diagrams, cross-sections, collapse animations). Each candidate gets a **before/after visualisation**. Be visual. + +For each candidate, render a card with: + +- **Files** — which files/modules are involved +- **Problem** — why the current architecture is causing friction +- **Solution** — plain English description of what would change +- **Benefits** — explained in terms of locality and leverage, and how tests would improve +- **Before / After diagram** — side-by-side, custom-drawn, illustrating the shallowness and the deepening +- **Recommendation strength** — one of `Strong`, `Worth exploring`, `Speculative`, rendered as a badge + +End the report with a **Top recommendation** section: which candidate you'd tackle first and why. + +**Use CONTEXT.md vocabulary for the domain, and the `/codebase-design` vocabulary for the architecture.** If `CONTEXT.md` defines "Order," talk about "the Order intake module" — not "the FooBarHandler," and not "the Order service." + +**ADR conflicts**: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly in the card (e.g. a warning callout: _"contradicts ADR-0007 — but worth reopening because…"_). Don't list every theoretical refactor an ADR forbids. + +See [HTML-REPORT.md](HTML-REPORT.md) for the full HTML scaffold, diagram patterns, and styling guidance. + +Do NOT propose interfaces yet. After the file is written, ask the user: "Which of these would you like to explore?" + +### 3. Grilling loop + +Once the user picks a candidate, run the `/grilling` skill to walk the design tree with them — constraints, dependencies, the shape of the deepened module, what sits behind the seam, what tests survive. + +Side effects happen inline as decisions crystallize — run the `/domain-modeling` skill to keep the domain model current as you go: + +- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md`. Create the file lazily if it doesn't exist. +- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there. +- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. +- **Want to explore alternative interfaces for the deepened module?** Run the `/codebase-design` skill and use its design-it-twice parallel sub-agent pattern. diff --git a/.agents/skills/writing-great-skills/GLOSSARY.md b/.agents/skills/writing-great-skills/GLOSSARY.md new file mode 100644 index 0000000..969c699 --- /dev/null +++ b/.agents/skills/writing-great-skills/GLOSSARY.md @@ -0,0 +1,195 @@ +# Glossary — Building Great Skills + +The domain model for what makes a skill great. A skill exists to wrangle determinism out of a stochastic system; the root virtue is **Predictability**, and every term below is a lever on it. This is the disclosed reference for [`writing-great-skills`](SKILL.md). + +The terms are grouped by axis: **Invocation** (how a skill is reached), **Information Hierarchy** (how its content is arranged), **Steering** (how the agent's runtime behaviour is shaped), and **Pruning** (how it is kept lean). Each **failure mode** lives beside the lever that cures it, tagged _failure mode_. + +**Bold terms** in any definition are themselves defined in this glossary; find them by their heading. + +## Predictability + +The degree to which a skill makes the agent behave the same _way_ on every run — the same process, not the same output (a brainstorming skill should _predictably_ diverge; its tokens vary, its behaviour doesn't). The root virtue every other term serves — cost and maintainability are symptoms of it, not rivals. + +_Avoid_: consistency, reliability, robustness, output-determinism + +## Invocation + +How a skill is reached — and the two loads you pay for the choice. + +### Model-Invoked + +A skill that keeps its **description** field, so the agent can see it and fire it autonomously — and the human can still type its name, so model-invocation always _includes_ user reach. There is no model-only state: a description only ever _adds_ agent discovery, never removes the human's. Pays a permanent **context load** on every turn in exchange for that discoverability. Reachable by other skills, because the description that makes it agent-discoverable makes it invocable. A model-invoked skill whose content is all **reference** is also one home for shared reference: another skill can invoke it, so reference needed by several skills lives in one place. Pick model-invocation only when the agent must reach the skill on its own; if it never fires except by hand, drop the description and pay no context load. + +_Avoid_: ability, tool, capability + +### User-Invoked + +A skill with its **description** stripped — invisible to the agent and reachable only by the human typing its name (user-_only_, where **model-invoked** is user-_and-agent_). Trades agent-discoverability for zero **context load**. Because it has no description, nothing but the human can reach it: no other skill can fire it. + +_Avoid_: procedure, workflow, command + +### Description + +The skill's machine-readable trigger, and the one **context pointer** a **model-invoked** skill is forced to keep loaded at all times. Its mere presence _is_ the invocation axis: keep it and the skill is model-invoked (and reachable by other skills); delete it and the skill is **user-invoked**, reachable only by the human. The source of a model-invoked skill's **context load**. + +_Avoid_: frontmatter, summary + +### Context Pointer + +A reference held in the agent's context that names some out-of-context material and encodes the condition for reaching it. The **description** is the top-level context pointer (context window → skill); pointers to disclosed files are the same object one level down. Its wording, not the target, decides _when_ the agent reaches — and _how reliably_. A must-have target behind a weakly worded pointer is a variance bug: fix the wording first, and inline the material only if sharpening fails. + +_Avoid_: link, reference, import + +### Context Load + +The cost a **model-invoked** skill imposes on the agent's context window — its **description**, always loaded, spending both tokens and attention. What **user-invoked** skills escape by having no description, and the brake on splitting into more model-invoked skills. + +_Avoid_: token cost, context bloat + +### Cognitive Load + +The cost a **user-invoked** skill imposes on the human — what they must hold in their head: which skills exist and when to reach for each (the human is the index). What **model-invocation** removes by being agent-discoverable, and the brake on splitting into more user-invoked skills. Not a cost to minimise: it is the price of human agency, the reason some skills stay user-invoked. Spend it where human judgement matters; remove it where it does not. + +_Avoid_: human index, burden, overhead + +### Router Skill + +A **user-invoked** skill whose job is to point at your other user-invoked skills — naming each and when to reach for it — so the human has one skill to remember instead of many. It can only hint, never fire them: user-invoked skills have no **description**, so nothing but the human can reach them. The cure for **cognitive load** when user-invoked skills multiply. + +_Avoid_: dispatcher, menu, registry, index, router procedure + +### Granularity + +How finely you divide skills. Finer division spends one of the two loads: more **model-invoked** skills spend **context load** (more descriptions crowding the window and competing for attention); more **user-invoked** skills spend **cognitive load** (more for the human to remember and reach for). Two cuts guide the division. By **invocation**, split off a model-invoked skill where you have a distinct **leading word** to trigger it — a trigger word you actually use in your prompts. By **sequence**, split a run of **steps** where a step's **post-completion steps** need hiding, since isolating it in its own context clears what follows. Beware the reverse: merging sequences exposes each step's post-completion steps to what follows, inviting premature completion. + +_Avoid_: chunking, modularity + +## Information Hierarchy + +How a skill's content is arranged, and how far down the ladder each piece sits. + +### Information Hierarchy + +A skill's content ranked by how immediately the agent needs it — a single ladder, produced by two cuts: in-file or behind a pointer, and step or reference. The rungs: + +- **Steps** — in-file, primary +- **Reference**, in-file — secondary +- **Reference**, disclosed — behind a **context pointer** + +A skill with no **steps** uses just the bottom two rungs — often a legitimately flat peer-set (e.g. every rule of a review on one rung), which is a fine arrangement, not a smell. The hierarchy is independent of invocation: a skill can be model- or user-invoked whether it is all steps, all reference, or both. When a skill has steps, in-file reference that should be disclosed buries them and turns attending to them into a coin-flip — a variance lever, not just a legibility one. Keep the top of the ladder legible; push down it whatever you can. + +_Avoid_: structure, organization, layout + +### Steps + +The ordered actions the agent performs — when a skill has them, the primary tier of its content, and the part that earns its place in SKILL.md. Not every skill has steps: a skill can be all steps (`tdd`), all **reference** (a review), or both, independent of invocation. Every step ends on a **completion criterion**, clear or vague. + +_Avoid_: workflow, instructions, choreography + +### Reference + +Material the agent refers to on demand — definitions, facts, parameters, examples, conditional instructions. When a skill has **steps** it is secondary to them; when a skill has none it is the entire content; or it lives outside any skill entirely — see **External Reference**. Reached via **context pointers**, and the prime candidate for **progressive disclosure**. + +_Avoid_: supporting material, docs, background + +### External Reference + +**Reference** that lives outside the skill system — a plain file, no **description**, no **steps**, not invocable — that any skill can point at. The home for shared reference that needn't fire on its own, and the only shared home two **user-invoked** skills can use, since neither has a description and so neither can fire the other. + +_Avoid_: doc, resource, knowledge base + +### Progressive Disclosure + +Moving **reference** down the ladder — out of SKILL.md and behind a **context pointer** — so the top stays legible. Not primarily a token optimisation; it is how the **information hierarchy** is protected. Licensed by **branching**: disclose what only some branches need, inline what every path needs, and if a pointer fires unreliably on must-have material, sharpen its wording, and pull it back inline only if that fails. + +_Avoid_: lazy loading, chunking + +### Co-location + +Keeping the material an agent needs at once in one place — a concept's definition, rules, and caveats under a single heading, not scattered across the file — so reading one part brings its neighbours with it. The within-file companion to the **Information Hierarchy**: the hierarchy ranks _how far down_ a piece sits; co-location decides _what sits beside it_ once there. There is no formula for the right format of a body of **reference**; the test is that a skill should read like documentation written for the agent, and grouped material reads that way where scattered material does not. Distinct from **Duplication**: that repeats one meaning in two places, where scattering fragments a single meaning across many. + +_Avoid_: grouping, clustering, cohesion + +### Sprawl + +_Failure mode._ A skill that is simply too long — too many lines in SKILL.md — independent of whether they are stale or repeated. Even an all-live, all-unique skill can sprawl. It costs readability (the agent wades through more before it can act, and attention thins across the excess), maintainability (every extra line is one more to keep **relevant**), and tokens. The cure is the **information hierarchy**: push **reference** down behind **context pointers**, and split by **branch** or sequence so each path carries only what it needs. Distinct from **sediment** (length from stale accumulation) and **duplication** (length from repeated meaning) — sprawl is length itself, whatever its cause. + +_Avoid_: bloat, length, size, verbosity + +## Steering + +The levers that shape the agent's runtime behaviour toward **Predictability**. + +### Branch + +A distinct way a skill can be invoked — a case the skill handles — so different runs take different paths through it. A skill with many steps may carry many branches; a linear one has none. + +_Avoid_: path, case, fork + +### Leading Word + +A compact concept — also called a _Leitwort_ — already living in the model's pretraining, that the agent thinks with while running the skill. It encodes a behavioural principle in the fewest possible tokens by invoking priors the model already holds (e.g. _lesson_, _proximal zone of development_, _fog of war_, _tracer bullets_). Repeated as a token, never as a sentence, it accumulates a distributed definition across the skill and anchors a whole region of behaviour. Coining your own works if you define it clearly, but a made-up word recruits no priors — you pay in definition tokens what a pretrained word gives free. Reach for an existing word first. + +A leading word serves **predictability** twice. In the body it anchors **execution** — the agent reaches for the same behaviour every time the concept appears, and inside flat reference it focuses attention on a class of thing to look for, recruiting the right checks each run. In the **description** it anchors **invocation** — and not only within the skill: when the same word lives in your prompts, your docs, and your codebase, the agent links that shared language to the skill and fires it more reliably. Word a description with the leading words you actually use when you want the skill. + +_Avoid_: keyword, term, motif + +### Completion Criterion + +The condition that tells the agent a unit of work is done — the target it judges against. Two properties make it a lever, not just a quality. Its **clarity** (can the agent tell done from not-done?) resists **premature completion** — a vague bound ("understanding reached") lets the agent declare done and slip to the next step; this axis needs _steps_ to bite, since premature completion is a between-steps failure. Its **demand** (how much it requires) sets **legwork** — "every modified model accounted for" forces thorough work where "produce a change list" does not — and this axis is _not_ step-bound: it can bind a body of flat reference too, which is how a skill with no steps still carries an exhaustiveness bar ("every rule applied"). The strongest criteria are both checkable and exhaustive. + +_Avoid_: done condition, exit condition, stopping rule + +### Legwork + +The work an agent does behind the scenes within a single step — reading files, exploring the codebase, making changes, digging up what it needs rather than offloading to the user. It lives below the step structure: never written as its own step, latent in the wording, controlled by the agent rather than the skill. The within-step counterpart to **post-completion steps**' across-step pull. Raised by a **leading word** (_comprehensive_, _thorough_) or a **completion criterion** that demands the work be exhaustive — including the demand axis applied to flat reference, which is what drives a skill of flat reference to cover all its rungs. Goes thin either when that demand is missing or when **premature completion** cuts the step short. + +_Avoid_: scope, effort, diligence, coverage + +### Post-Completion Steps + +The **steps** that follow the current step. Visible, they pull the agent forward into **premature completion** — the more it sees, the stronger the tug; the defence is to hide them by splitting the sequence of steps into two. + +_Avoid_: horizon, fog of war, lookahead + +### Premature Completion + +_Failure mode._ Ending the current step before it is genuinely done, because the agent's attention slips to being done rather than to the work. A between-steps failure: it needs **steps** to occur — a skill with no steps that quits early isn't premature completion but thin **legwork** under an unmet demand. A tug-of-war between two forces: visible **post-completion steps** (the pull forward) and the **completion criterion**'s clarity (the resistance — a sharp, checkable bar holds; a vague one gives way). Fuzziness is the necessary condition: a sharp bound resists the pull no matter how many later steps are visible, so a step that never rushes needs no defending. Two levers hold a step that does, but reach for them in order: **sharpen the bound first** — it is local and cheap. Only when the criterion is irreducibly fuzzy _and_ you actually observe the rush do you **hide the later steps** — and hiding only works across a real context boundary (a user-invoked hand-off or a subagent dispatch; an inline model-invoked call leaves the later steps in context and clears nothing). One cause of thin legwork, but distinct from it: legwork can be thin even when a step runs to full completion. + +_Avoid_: premature closure, the rush, rushing, shortcutting + +## Pruning + +Keeping a skill lean — each remedy paired with the failure it cures. + +### Single Source of Truth + +The desired state where each meaning lives in exactly one authoritative place, so a change to the skill's behaviour is a change in one place. **Duplication** is its violation. + +_Avoid_: home, canonical location + +### Duplication + +_Failure mode._ The same meaning given more than one **single source of truth**. It costs maintenance (change one place, you must change the others), costs tokens, and inflates prominence — repeating a meaning weights it on the ladder past its real rank. The accidental inverse of a **leading word**, which raises attention on purpose by repeating a token, never the meaning. + +_Avoid_: repetition, redundancy + +### Relevance + +Whether a line still bears on what the skill does — the lens for what to keep. A line loses relevance either by never bearing on the task (mere exposition, or a **branch** that should be disclosed) or by going stale: drifting out of date as the behaviour or world it describes changes. Shorter skills are easier to keep relevant, because each line is cheaper to check. Distinct from **no-op**: relevance asks whether a line bears on the task, not whether it changes behaviour. + +_Avoid_: load-bearing, staleness, freshness + +### Sediment + +_Failure mode._ Layers of old content that settle in a skill and are never cleared, because adding feels safe and removing feels risky — so stale and irrelevant lines accumulate and you must core down through them to find what is still live. The default fate of any skill without a pruning discipline; the slow erosion of **relevance**, as opposed to **duplication**'s repeated meaning. + +_Avoid_: accretion, bloat, cruft, rot + +### No-Op + +_Failure mode._ An instruction that changes nothing because the model already does it by default — you pay load to tell the agent what it would do anyway. The test: does a line change behaviour versus the default? A line can be perfectly **relevant** and still be a no-op. The same priors that make a **leading word** free make a no-op worthless. + +A leading word is a _technique_; No-Op is a _verdict_ on a line — and they cross. A leading word too weak to beat the default is a no-op (_be thorough_ when the agent is already thorough-ish), and the fix is a stronger word that passes the verdict (_relentless_), not a different technique. So the No-Op test — does it change behaviour versus the default? — is also how you grade whether a leading word is earning its repetitions. This is model-relative, not reader-relative: two people disagreeing over whether a line is a no-op disagree about the default, and settle it by running the skill, not by debate. + +_Avoid_: redundant instruction, restating the obvious, belaboring diff --git a/.agents/skills/writing-great-skills/SKILL.md b/.agents/skills/writing-great-skills/SKILL.md new file mode 100644 index 0000000..61abad4 --- /dev/null +++ b/.agents/skills/writing-great-skills/SKILL.md @@ -0,0 +1,82 @@ +--- +name: writing-great-skills +description: Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable. +disable-model-invocation: true +--- + +A skill exists to wrangle determinism out of a stochastic system. **Predictability** — the agent taking the same _process_ every run, not producing the same output — is the root virtue; every lever below serves it. + +**Bold terms** are defined in [`GLOSSARY.md`](GLOSSARY.md); look them up there for the full meaning. + +## Invocation + +Two choices, trading different costs: + +- A **model-invoked** skill keeps a **description**, so the agent can fire it autonomously _and_ other skills can reach it (you can still type its name too). It contributes to **context load** — the description sits in the window every turn. Mechanics: omit `disable-model-invocation`, and write a model-facing description with rich trigger phrasing ("Use when the user wants…, mentions…"). +- A **user-invoked** skill strips the description from the agent's reach: only you, typing its name, can invoke it — and no other skill can. Zero context load, but it spends **cognitive load**: _you_ are the index that must remember it exists. Mechanics: set `disable-model-invocation: true`; the `description` becomes human-facing — a one-line summary, trigger lists stripped. + +Pick model-invocation only when the agent must reach the skill on its own, or another skill must. If it only ever fires by hand, make it user-invoked and pay no context load. + +When user-invoked skills multiply past what you can remember, that piled-up cognitive load is cured by a **router skill**: one user-invoked skill that names the others and when to reach for each. + +## Writing the description + +A model-invoked **description** does two jobs — state what the skill is, and list the **branches** that should trigger it. Every word increases **context load**, so a description earns even harder pruning than the body: + +- **Front-load the skill's leading word** — the description is where it does its invocation work. +- **One trigger per branch.** Synonyms that rename a single branch are **duplication** — "build features using TDD … asks for test-first development" is one branch written twice. Collapse them; keep only genuinely distinct branches. +- **Cut identity that's already in the body.** Keep the description to triggers, plus any "when another skill needs…" reach clause. + +## Information hierarchy + +A skill is built from two content types — **steps** and **reference** — that mix freely: a skill can be all steps, all reference, or both. The core decision is which to use and where each sits on the **information hierarchy**, a ladder ranked by how immediately the agent needs the material: + +1. **In-skill step** — an ordered action in `SKILL.md`, the primary tier: what the agent does, in order. Each step ends on a **completion criterion**, the condition that tells the agent the work is done. Make it _checkable_ (can the agent tell done from not-done?) and, where it matters, _exhaustive_ ("every modified model accounted for", not "produce a change list") — a vague criterion invites **premature completion**. +2. **In-skill reference** — a definition, rule, or fact in `SKILL.md`, consulted on demand. Often a legitimately flat peer-set (every rule of a review on one rung) — a fine arrangement, not a smell. _This skill is all reference._ +3. **External reference** — reference pushed out of `SKILL.md` into a separate file, reached by a **context pointer**, loaded only when the pointer fires. (Spans _disclosed_ reference — a sibling file like `GLOSSARY.md`, still part of the skill — through fully **external reference** that lives outside the skill system and any skill can point at.) + +A demanding completion criterion drives thorough **legwork** — the digging the agent does within the work — whether the skill has steps or not, since "every rule applied" binds flat reference just as "every step done" binds a sequence. + +Push too little down and the top bloats; push too much and you hide material the agent actually needs. That tension is the whole decision. + +**Progressive disclosure** is the move down the ladder — out of `SKILL.md` into a linked file — so the top stays legible. Mechanics: a linked `.md` file in the skill folder, named for what it holds (this skill discloses its full definitions to `GLOSSARY.md`). Some skills are used in more than one way, and each distinct way is a **branch** — different runs taking different paths through the skill. Branching is the cleanest disclosure test: inline what every branch needs, and push behind a pointer what only some branches reach. A **context pointer**'s _wording_, not its target, decides when and how reliably the agent reaches the material. + +Where the ladder decides _how far down_ a piece sits, **co-location** decides _what sits beside it_ once there: keep a concept's definition, rules, and caveats under one heading rather than scattered, so reading one part brings its neighbours with it. + +## When to split + +**Granularity** is how finely you divide skills, and each cut spends one of the two loads, so split only when the cut earns it. Two cuts: + +- **By invocation** — split off a **model-invoked** skill when you have a distinct **leading word** that should trigger it on its own, or another skill must reach it. You pay **context load** for the new always-loaded **description**, so that independent reach has to be worth it. +- **By sequence** — split a run of **steps** when the steps still ahead (a step's **post-completion steps**) tempt the agent to rush the one in front of it (**premature completion**). Keeping them out of view encourages the agent to do more **legwork** on the current task. + +## Pruning + +Keep each meaning in a **single source of truth**: one authoritative place, so changing the behaviour is a one-place edit. + +Check every line for **relevance**: does it still bear on what the skill does? + +Then hunt **no-ops** sentence by sentence, not just line by line: run the no-op test on each sentence in isolation, and when one fails, delete the whole sentence rather than trim words from it. Be aggressive — most prose that fails should go, not be rewritten. + +## Leading words + +A **leading word** is a compact concept already living in the model's pretraining that the agent thinks with while running the skill (e.g. _lesson_, _fog of war_, _tracer bullets_). Repeated throughout the text (though not necessarily - a strong leading word might only be needed once), it accumulates a distributed definition and anchors a whole region of behaviour in the fewest tokens, by recruiting priors the model already holds. + +It serves predictability twice. In the body it anchors _execution_: the agent reaches for the same behaviour every time the word appears. In the description it anchors _invocation_: when the same word lives in your prompts, docs, and code, the agent links that shared language to the skill and fires it more reliably. + +Hunt for opportunities to refactor skills to use leading words. A triad spelled out at three sites (**duplication**), a description spending a sentence to gesture at one idea — each is a passage begging to **collapse** into a single token. Examples include: + +- "fast, deterministic, low-overhead" -> _tight_ — one quality restated across a phase — into a single pretrained word (a _tight_ loop). +- "a loop you believe in" -> _red_ — converts a fuzzy gate into a binary observable state (the loop goes _red_ on the bug, or it doesn't). + +You win twice over: fewer tokens, _and_ a sharper hook for the agent to hang its thinking on. Assume every skill is carrying restatements that leading words retire — go find them. + +## Failure modes + +Use these to diagnose issues the user may be having with the skill. + +- **Premature completion** — ending a step before it's genuinely done, attention slipping to _being done_. Defence, in order: sharpen the completion criterion first (cheap, local); only if it is irreducibly fuzzy _and_ you observe the rush, hide the post-completion steps by splitting (the sequence cut). +- **Duplication** — the same meaning in more than one place. Costs maintenance and tokens, and inflates a meaning's prominence on the ladder past its real rank. +- **Sediment** — stale layers that settle because adding feels safe and removing feels risky. The default fate of any skill without a pruning discipline. +- **Sprawl** — a skill simply too long, even when every line is live and unique. Hurts readability and maintainability and wastes tokens. The cure is the ladder: disclose **reference** behind pointers, and split by **branch** or sequence so each path carries only what it needs. +- **No-op** — a line the model already obeys by default, so you pay load to say nothing. The test: does it change behaviour versus the default? A weak leading word (_be thorough_ when the agent is already thorough-ish) is a no-op; the fix is a stronger word (_relentless_), not a different technique. diff --git a/.claude/skills/codebase-design b/.claude/skills/codebase-design new file mode 120000 index 0000000..08b466e --- /dev/null +++ b/.claude/skills/codebase-design @@ -0,0 +1 @@ +../../.agents/skills/codebase-design \ No newline at end of file diff --git a/.claude/skills/diagnosing-bugs b/.claude/skills/diagnosing-bugs new file mode 120000 index 0000000..b2134ff --- /dev/null +++ b/.claude/skills/diagnosing-bugs @@ -0,0 +1 @@ +../../.agents/skills/diagnosing-bugs \ No newline at end of file diff --git a/.claude/skills/domain-modeling b/.claude/skills/domain-modeling new file mode 120000 index 0000000..e672a60 --- /dev/null +++ b/.claude/skills/domain-modeling @@ -0,0 +1 @@ +../../.agents/skills/domain-modeling \ No newline at end of file diff --git a/.claude/skills/grill-me b/.claude/skills/grill-me new file mode 120000 index 0000000..eea91a8 --- /dev/null +++ b/.claude/skills/grill-me @@ -0,0 +1 @@ +../../.agents/skills/grill-me \ No newline at end of file diff --git a/.claude/skills/grill-with-docs b/.claude/skills/grill-with-docs new file mode 120000 index 0000000..f6cbb9c --- /dev/null +++ b/.claude/skills/grill-with-docs @@ -0,0 +1 @@ +../../.agents/skills/grill-with-docs \ No newline at end of file diff --git a/.claude/skills/grilling b/.claude/skills/grilling new file mode 120000 index 0000000..e712452 --- /dev/null +++ b/.claude/skills/grilling @@ -0,0 +1 @@ +../../.agents/skills/grilling \ No newline at end of file diff --git a/.claude/skills/handoff b/.claude/skills/handoff new file mode 120000 index 0000000..a34a6b2 --- /dev/null +++ b/.claude/skills/handoff @@ -0,0 +1 @@ +../../.agents/skills/handoff \ No newline at end of file diff --git a/.claude/skills/improve-codebase-architecture b/.claude/skills/improve-codebase-architecture new file mode 120000 index 0000000..be3dac9 --- /dev/null +++ b/.claude/skills/improve-codebase-architecture @@ -0,0 +1 @@ +../../.agents/skills/improve-codebase-architecture \ No newline at end of file diff --git a/.claude/skills/writing-great-skills b/.claude/skills/writing-great-skills new file mode 120000 index 0000000..07320a2 --- /dev/null +++ b/.claude/skills/writing-great-skills @@ -0,0 +1 @@ +../../.agents/skills/writing-great-skills \ No newline at end of file diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 0000000..6040479 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,59 @@ +{ + "version": 1, + "skills": { + "codebase-design": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/engineering/codebase-design/SKILL.md", + "computedHash": "2426dc4accf1a85dedfb560edb3a877ec8828b7375ea08c970df2b6c900a2a22" + }, + "diagnosing-bugs": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/engineering/diagnosing-bugs/SKILL.md", + "computedHash": "1a993ce9b2aaa653ee441c8d7efb7f27de03493c722be6dfb8137bcb8db1bc72" + }, + "domain-modeling": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/engineering/domain-modeling/SKILL.md", + "computedHash": "67343881f5def98487d56243155716110afbcbf22ec92421c882d532b941cb17" + }, + "grill-me": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/productivity/grill-me/SKILL.md", + "computedHash": "f321507f77702a54af1db66549ec1685fc625390d06c57d7949cdcda8eb1b5c7" + }, + "grill-with-docs": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/engineering/grill-with-docs/SKILL.md", + "computedHash": "e7ef25bbee50cda2eb7b3a8ef541db0a0396dad7d369f7d14fb610671dd1864b" + }, + "grilling": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/productivity/grilling/SKILL.md", + "computedHash": "ef685a6fa0bbe73b05bbd8dc1ec97258191587f07c6aa7dbc9006675ceb8f90f" + }, + "handoff": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/productivity/handoff/SKILL.md", + "computedHash": "5d0f81e38abe6b984e1feaa731927de5291d040982106ac513cf54ec240e00ec" + }, + "improve-codebase-architecture": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/engineering/improve-codebase-architecture/SKILL.md", + "computedHash": "8bf292143ca93b00276a0de0fc5f84f2381f4690c5b0d32e99fa283a072f392f" + }, + "writing-great-skills": { + "source": "mattpocock/skills", + "sourceType": "github", + "skillPath": "skills/productivity/writing-great-skills/SKILL.md", + "computedHash": "dd555ce552f82784c3d2b8d13a8e26a6677a07ddc00032e142dec33bfd5438c6" + } + } +} From a8201a0392887f198d2f787981242095dd8f6835 Mon Sep 17 00:00:00 2001 From: suzuki Date: Sun, 28 Jun 2026 19:26:16 +0000 Subject: [PATCH 034/113] feat: add ingest-paper skill Convert paper/lecture-note PDFs into agent-navigable Markdown under references// as groundwork for grilling a formalization plan. User-invoked, conversion-focused: reuses the MinerU convert.py from the removed pdf-to-knowledge skill, drops the concept index / mathlib verification / gap-filler layers, and hands off to /grilling. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/ingest-paper/SKILL.md | 51 +++ .../ingest-paper/references/conversion.md | 74 ++++ .../skills/ingest-paper/scripts/convert.py | 397 ++++++++++++++++++ 3 files changed, 522 insertions(+) create mode 100644 .claude/skills/ingest-paper/SKILL.md create mode 100644 .claude/skills/ingest-paper/references/conversion.md create mode 100644 .claude/skills/ingest-paper/scripts/convert.py diff --git a/.claude/skills/ingest-paper/SKILL.md b/.claude/skills/ingest-paper/SKILL.md new file mode 100644 index 0000000..61322c2 --- /dev/null +++ b/.claude/skills/ingest-paper/SKILL.md @@ -0,0 +1,51 @@ +--- +name: ingest-paper +description: Convert a paper or lecture-note PDF into agent-navigable Markdown under references//, as the groundwork for grilling its formalization plan. +disable-model-invocation: true +--- + +# ingest-paper + +Turn a PDF (paper, lecture notes) into Markdown + extracted images + a filled +`INDEX.md` that an agent can navigate across sessions — the durable substrate a +formalization plan gets grilled against afterwards. + +This skill stops at a navigable document. It does **not** plan or formalize; the +last step hands off to `/grilling`. + +## Steps + +1. **Resolve the source.** Pull the PDF URL or local path from the request. If + several are present, process the one the user names; ask only when ambiguous. + *Done when:* you hold exactly one URL or existing local `.pdf` path. + +2. **Run the converter.** From the project root: + + ```bash + uv run .claude/skills/ingest-paper/scripts/convert.py "" + ``` + + Add a flag only when the default fails: `--ocr` (scanned PDF, output came out + nearly empty), `--slug ` (override the derived slug), `--output-dir + ` (override the `references/` root). Other flags and runtime + prerequisites live in `references/conversion.md` — read it only if the + command errors or the layout needs tweaking. + *Done when:* the script prints its JSON summary (`slug`, `output_dir`, + `index_path`, `page_count`, `image_count`, `sectioned`) and exits 0. + +3. **Fill the INDEX.md scaffold.** The script leaves two `` blocks. + Read `content.md` (or the `sections/*.md` files) and replace **both**: + - **Summary** — 3–5 sentences: what this document is and why a formalization + agent would consult it. From the actual content, not the title. + - **Key concepts** — bullet list an agent would grep for. **Every bullet + starts with a `` `backtick-identifier` ``** naming the concept, then a short + gloss. Omit the section only for pure-prose documents with no greppable + terminology. + *Done when:* no `` marker remains anywhere in `INDEX.md`, and + every Key-concepts bullet begins with a backtick identifier. + +4. **Hand off to planning.** Report the `INDEX.md` path and any caveats (OCR + skipped, document split into `sections/`, no images found) — do not paste the + summary into chat. Then tell the user the substrate is ready and the next move + is `/grilling` to stress-test the formalization plan against it. + *Done when:* the user has the INDEX path and the `/grilling` pointer. diff --git a/.claude/skills/ingest-paper/references/conversion.md b/.claude/skills/ingest-paper/references/conversion.md new file mode 100644 index 0000000..c10e247 --- /dev/null +++ b/.claude/skills/ingest-paper/references/conversion.md @@ -0,0 +1,74 @@ +# Conversion reference + +Read this only when the `convert.py` command errors, the output layout needs +tweaking, or you are debugging a bad conversion. The happy path needs nothing +here. + +## Output contract + +Everything lands under `//` (default `references//`, +which this project keeps in `.gitignore`): + +``` +references// +├── INDEX.md # metadata frontmatter + Summary + Key concepts + Contents (you fill 2 sections) +├── content.md # present when page count <= max-pages-per-section (default 20) +├── sections/ # present instead of content.md when pages > threshold AND the PDF has top-level headings +│ ├── 01-.md +│ └── ... +├── assets/ # only images actually referenced from the Markdown, rewritten as assets/... +│ └── image_*.jpg +└── mineru-raw/ # only when --keep-raw is passed; debugging artefacts, not for agents +``` + +`INDEX.md` frontmatter carries `title`, `source`, `pages`, `slug`, `assets`. +`content.md`/`sections/` and `assets/` are read directly by any later agent +without re-running the conversion. + +## All flags + +- `--output-dir <dir>` — parent of `<slug>/`. Default `references/`. +- `--slug <name>` — override the derived slug. arXiv IDs are auto-preserved + (`arxiv-2202.03357`); other sources slugify the filename. +- `--max-pages-per-section N` — split threshold (default 20). Leave alone unless + asked. +- `--ocr` — MinerU OCR mode for scanned PDFs. Default `auto` picks text + extraction when a text layer exists. OCR adds minutes — confirm before using. +- `--keep-raw` — keep MinerU's auxiliary outputs (middle.json, layout.pdf, etc.) + under `mineru-raw/`. Several MB; off by default. + +## Runtime prerequisites + +- **`uv`** on `PATH`. The script is stdlib-only but runs under `uv run` for + invocation hygiene. +- **`mineru` CLI** on `PATH`. One-off install: `uv tool install "mineru[all]"` + (~4 GB of packages + model weights on first run; cached afterwards). +- **Disk + memory.** Budget ~4 GB for the tool environment; per-paper runtime + memory peaks at 3–4 GB. +- **GPU (optional).** When `nvidia-smi` reports a working GPU the script switches + MinerU to its `hybrid-auto-engine` backend (much faster on formula + recognition). Otherwise it silently uses CPU `pipeline`. No flag needed. + +## Failure modes + +- **Download error** — script exits non-zero; ask the user for a local path. +- **Scanned PDF (no text layer)** — output Markdown is nearly empty; re-run with + `--ocr` after confirming with the user. +- **>20 pages but no top-level headings** — falls back to a single `content.md`. + Intentional; do not hand-split. +- **Very large docs (>100 pages)** — first-run CPU conversion takes several + minutes; warn the user so they do not cancel. +- **Parallel runs on CPU** — MinerU's per-task timeout makes concurrent + conversions fail. Convert one PDF at a time; a single paper runs ~30–40 min on + CPU. + +## Why MinerU + +MinerU's `pipeline` backend decodes every formula (display and inline) to LaTeX +on CPU in minutes and preserves equation numbers via `\tag{...}`. Docling was +dropped earlier: its formula VLM emitted `<!-- formula-not-decoded -->` by +default and the opt-in path was GPU-bound and unusable on CPU. The script shells +out to the `mineru` CLI rather than importing its Python API (more stable, lighter +dependency graph). The agent — not the script — writes Summary and Key concepts, +because summarization and identifier extraction are judgement calls a heuristic +would get wrong often enough to harm. diff --git a/.claude/skills/ingest-paper/scripts/convert.py b/.claude/skills/ingest-paper/scripts/convert.py new file mode 100644 index 0000000..8a73657 --- /dev/null +++ b/.claude/skills/ingest-paper/scripts/convert.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.10" +# dependencies = [] +# /// +"""Convert a PDF into agent-friendly Markdown + image assets using MinerU. + +Produces under ``<output-dir>/<slug>/``: + +- ``INDEX.md`` Metadata, ToC, and scaffolded Summary / Key concepts / Bibliography + frontmatter sections that the caller (Claude) fills in after + reading the content. +- ``content.md`` Full Markdown (if total pages <= max-pages-per-section). +- ``sections/`` Split Markdown files (if total pages exceed the threshold and + the document has top-level ``#`` / ``## `` headings to split on). +- ``assets/`` Images referenced from the Markdown. + +This script is a thin post-processor around the MinerU CLI. MinerU's +``pipeline`` backend runs entirely on CPU and, unlike Docling's formula VLM, +decodes mathematical formulas into LaTeX in a few minutes per paper. We gave +up on Docling in iteration-6 after its formula VLM crawled on CPU. + +Usage: + uv run convert.py <pdf-url-or-path> [--output-dir DIR] [--slug SLUG] + [--max-pages-per-section N] [--ocr] + [--keep-raw] + +Prerequisite: + ``mineru`` must be on PATH. One-off install: + uv tool install "mineru[all]" +""" + +from __future__ import annotations + +import argparse +import json +import re +import shutil +import subprocess +import sys +import tempfile +import urllib.parse +import urllib.request +from pathlib import Path + + +def slugify(text: str) -> str: + """Lowercase, ASCII-friendly filesystem slug, capped at 60 chars.""" + text = text.lower().strip() + text = re.sub(r"[^\w\s-]", "", text, flags=re.UNICODE) + text = re.sub(r"[\s_-]+", "-", text) + return text[:60].strip("-") or "document" + + +def derive_slug(source: str) -> str: + """Pick a readable slug from a URL or local path.""" + m = re.search(r"arxiv\.org/(?:pdf|abs)/([\w.-]+?)(?:v\d+)?(?:\.pdf)?(?:[?#]|$)", source) + if m: + return f"arxiv-{m.group(1)}" + if source.startswith(("http://", "https://")): + parsed = urllib.parse.urlparse(source) + basename = Path(parsed.path).stem or parsed.netloc + return slugify(basename) + return slugify(Path(source).stem) + + +def normalise_pdf_url(url: str) -> str: + """Rewrite arxiv ``abs/`` URLs to their ``pdf/`` counterparts.""" + m = re.match(r"^(https?://arxiv\.org)/abs/([\w.-]+?)(?:v\d+)?/?$", url) + if m: + return f"{m.group(1)}/pdf/{m.group(2)}" + return url + + +def download_pdf(url: str, dest: Path) -> None: + req = urllib.request.Request(url, headers={"User-Agent": "pdf-to-knowledge/1.0"}) + with urllib.request.urlopen(req, timeout=120) as response, dest.open("wb") as out: + while chunk := response.read(65536): + out.write(chunk) + + +def _heading_level(line: str) -> int: + """Return the Markdown heading level (1..6) of ``line``, or 0 if not a heading.""" + m = re.match(r"^(#{1,6}) \S", line) + return len(m.group(1)) if m else 0 + + +def split_markdown_by_top_headings(md: str) -> list[tuple[str, str]]: + """Split Markdown at its top-most heading level. Returns ``[(title, body), ...]``.""" + has_h1 = any(_heading_level(line) == 1 for line in md.splitlines()) + split_level = 1 if has_h1 else 2 + + sections: list[tuple[str, str]] = [] + current_title: str | None = None + current_body: list[str] = [] + for line in md.splitlines(keepends=True): + if _heading_level(line.rstrip("\n")) == split_level: + if current_title is not None: + sections.append((current_title, "".join(current_body))) + current_title = line.lstrip("#").strip() + current_body = [line] + else: + if current_title is None: + current_title = "front-matter" + current_body = [] + current_body.append(line) + if current_title is not None: + sections.append((current_title, "".join(current_body))) + return sections + + +def extract_document_title(md: str, fallback: str) -> str: + """Return the first heading (any level) in ``md``, or ``fallback``.""" + for line in md.splitlines(): + m = re.match(r"^#{1,6} (.+)", line) + if m: + return m.group(1).strip() + return fallback + + +def _github_anchor(heading: str) -> str: + """Compute a GitHub-style Markdown anchor for a heading.""" + slug = heading.strip().lower() + slug = re.sub(r"[^\w\s-]", "", slug, flags=re.UNICODE) + slug = re.sub(r"\s+", "-", slug) + return slug.strip("-") + + +def extract_toc_headings(md: str, max_entries: int = 20) -> list[tuple[int, str]]: + """Extract H2/H3 headings from ``md`` for navigation.""" + entries: list[tuple[int, str]] = [] + for line in md.splitlines(): + m = re.match(r"^(##{1,2}) (.+)", line) + if m: + level = len(m.group(1)) + title = m.group(2).strip() + entries.append((level, title)) + if len(entries) >= max_entries: + break + return entries + + +def _flat_toc_for_content(md: str) -> list[str]: + """Build ToC Markdown lines for the single-file ``content.md`` case.""" + lines = ["- [Full content](content.md)"] + for level, title in extract_toc_headings(md): + indent = " " if level == 2 else " " + anchor = _github_anchor(title) + lines.append(f"{indent}- [{title}](content.md#{anchor})") + return lines + + +def _has_gpu() -> bool: + """Detect an NVIDIA GPU via ``nvidia-smi``. Returns False on any error. + + MinerU's `hybrid-auto-engine` backend uses GPU when available and is + dramatically faster than `pipeline` for the formula-recognition stage. + Falls back to CPU `pipeline` cleanly when `nvidia-smi` is absent. + """ + if shutil.which("nvidia-smi") is None: + return False + try: + result = subprocess.run( + ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], + capture_output=True, + text=True, + timeout=5, + ) + except (subprocess.TimeoutExpired, OSError): + return False + return result.returncode == 0 and bool(result.stdout.strip()) + + +def run_mineru(pdf_path: Path, output_base: Path, ocr: bool) -> tuple[Path, Path, Path]: + """Invoke the MinerU CLI. Returns (md_path, images_dir, content_list_json).""" + if shutil.which("mineru") is None: + print( + "[error] 'mineru' not found on PATH. Install with: " + "uv tool install \"mineru[all]\"", + file=sys.stderr, + ) + sys.exit(3) + + method = "ocr" if ocr else "auto" + # Auto-select backend: hybrid-auto-engine uses GPU when available and + # can be >5x faster for formula-heavy papers; pipeline is CPU-only. + backend = "hybrid-auto-engine" if _has_gpu() else "pipeline" + print(f"[info] MinerU backend: {backend}", file=sys.stderr) + cmd = [ + "mineru", + "-p", str(pdf_path), + "-o", str(output_base), + "-b", backend, + "-l", "en", + "-m", method, + ] + print(f"[info] Running: {' '.join(cmd)}", file=sys.stderr) + subprocess.run(cmd, check=True) + + name = pdf_path.stem + auto_dir = output_base / name / "auto" + md_path = auto_dir / f"{name}.md" + images_dir = auto_dir / "images" + content_list_json = auto_dir / f"{name}_content_list.json" + if not md_path.is_file(): + print(f"[error] MinerU did not produce {md_path}", file=sys.stderr) + sys.exit(4) + return md_path, images_dir, content_list_json + + +def page_count_from_content_list(content_list_json: Path) -> int: + """Read max ``page_idx`` from MinerU's content_list.json and return page count.""" + try: + data = json.loads(content_list_json.read_text(encoding="utf-8")) + except Exception: + return 0 + max_idx = 0 + for item in data: + idx = item.get("page_idx") + if isinstance(idx, int): + max_idx = max(max_idx, idx) + return max_idx + 1 if data else 0 + + +_IMAGE_REF = re.compile(r"!\[[^\]]*\]\(images/([^)]+)\)") + + +def rewrite_and_collect_image_refs(md: str) -> tuple[str, set[str]]: + """Rewrite ``images/...`` references to ``assets/...`` and return referenced names.""" + referenced: set[str] = set() + + def _sub(match: re.Match) -> str: + name = match.group(1) + referenced.add(name) + return match.group(0).replace("images/", "assets/", 1) + + return _IMAGE_REF.sub(_sub, md), referenced + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("source", help="PDF URL or local path") + parser.add_argument( + "--output-dir", + default="references", + help="Parent directory; output is placed under <output-dir>/<slug>/", + ) + parser.add_argument("--slug", default=None, help="Override the auto-derived slug") + parser.add_argument( + "--max-pages-per-section", + type=int, + default=20, + help="Split into sections/ if the document exceeds this many pages (default: 20)", + ) + parser.add_argument( + "--ocr", + action="store_true", + help="Use MinerU's OCR method (for scanned PDFs). Default is 'auto'.", + ) + parser.add_argument( + "--keep-raw", + action="store_true", + help=( + "Keep MinerU's raw auxiliary outputs (middle.json, layout.pdf, span.pdf, " + "model.json, content_list_v2.json) under <output-dir>/<slug>/mineru-raw/. " + "Off by default — they are debugging artefacts unsuitable for agents." + ), + ) + args = parser.parse_args() + + source: str = args.source + slug = args.slug or derive_slug(source) + output_root = Path(args.output_dir).expanduser().resolve() + output_dir = output_root / slug + output_dir.mkdir(parents=True, exist_ok=True) + assets_dir = output_dir / "assets" + + # Resolve input to a local path. + if source.startswith(("http://", "https://")): + fetch_url = normalise_pdf_url(source) + tmpdir = Path(tempfile.mkdtemp(prefix="pdf-to-knowledge-")) + pdf_path = tmpdir / f"{slug}.pdf" + print(f"[info] Downloading {fetch_url}", file=sys.stderr) + download_pdf(fetch_url, pdf_path) + else: + pdf_path = Path(source).expanduser().resolve() + if not pdf_path.exists(): + print(f"[error] Not found: {pdf_path}", file=sys.stderr) + return 2 + + # Run MinerU into a fresh scratch directory so we fully own the layout. + mineru_scratch = Path(tempfile.mkdtemp(prefix="mineru-")) + md_path, images_src, content_list_json = run_mineru( + pdf_path, mineru_scratch, ocr=args.ocr + ) + + page_count = page_count_from_content_list(content_list_json) + print(f"[info] Pages: {page_count}", file=sys.stderr) + + md_text = md_path.read_text(encoding="utf-8") + md_text, referenced_images = rewrite_and_collect_image_refs(md_text) + + # Copy referenced images only — MinerU occasionally extracts formula clips + # that are not referenced from the Markdown; keeping them clutters agents. + image_count = 0 + if referenced_images and images_src.is_dir(): + assets_dir.mkdir(exist_ok=True) + for name in referenced_images: + src = images_src / name + if src.is_file(): + shutil.copy(src, assets_dir / name) + image_count += 1 + + # Optionally keep MinerU's raw auxiliary outputs for debugging. + if args.keep_raw: + raw_dir = output_dir / "mineru-raw" + raw_dir.mkdir(exist_ok=True) + for aux in md_path.parent.iterdir(): + if aux.name == md_path.name or aux == images_src: + continue + if aux.is_file(): + shutil.copy(aux, raw_dir / aux.name) + + # Clean up the scratch tree now that we have what we need. + shutil.rmtree(mineru_scratch, ignore_errors=True) + + # Write content.md / sections/ based on page count. + content_md = output_dir / "content.md" + title = extract_document_title(md_text, slug.replace("-", " ").title()) + + sectioned = False + toc_lines: list[str] = [] + if page_count > args.max_pages_per_section: + parts = split_markdown_by_top_headings(md_text) + real_parts = [(t, b) for t, b in parts if t != "front-matter" or b.strip()] + if len(real_parts) > 1: + sections_dir = output_dir / "sections" + sections_dir.mkdir(exist_ok=True) + for i, (section_title, body) in enumerate(real_parts, start=1): + sec_slug = slugify(section_title) + sec_file = sections_dir / f"{i:02d}-{sec_slug}.md" + sec_file.write_text(body, encoding="utf-8") + toc_lines.append(f"- [{section_title}](sections/{sec_file.name})") + sectioned = True + else: + content_md.write_text(md_text, encoding="utf-8") + toc_lines.extend(_flat_toc_for_content(md_text)) + else: + content_md.write_text(md_text, encoding="utf-8") + toc_lines.extend(_flat_toc_for_content(md_text)) + + # Scaffold INDEX.md (Claude fills Summary / Key concepts / authors / + # bibliography / mathlib annotations per SKILL.md steps 4a-4f). + index = [ + "---", + f"title: {json.dumps(title, ensure_ascii=False)}", + f"source: {json.dumps(source, ensure_ascii=False)}", + f"pages: {page_count}", + f"slug: {slug}", + f"assets: {image_count}", + "---", + "", + f"# {title}", + "", + "## Summary", + "", + "<!-- TODO: 3-5 sentence summary of what this document covers and why a", + " coding agent would consult it. Fill in after reading the content. -->", + "", + "## Key concepts", + "", + "<!-- TODO: Bullet list of identifiers an agent would grep for. Each bullet", + " MUST start with a `backtick-quoted` identifier — this drives the", + " cross-document concept index. Omit the section if no greppable", + " terminology exists (e.g. pure prose papers). -->", + "", + "## Contents", + "", + *toc_lines, + "", + ] + (output_dir / "INDEX.md").write_text("\n".join(index), encoding="utf-8") + + summary = { + "slug": slug, + "output_dir": str(output_dir), + "index_path": str(output_dir / "INDEX.md"), + "page_count": page_count, + "image_count": image_count, + "sectioned": sectioned, + } + print(json.dumps(summary, indent=2, ensure_ascii=False)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 155895dcb702e1739fc9d805791c15fa708e6411 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 20:08:10 +0000 Subject: [PATCH 035/113] feat: add grill-formalization skill Add a user-invoked skill that grills a formalization plan after ingest-paper: a survey-first phase, a grill loop, a design tree pointing at AGENTS.md rules, and a fixed plan-output format with an equivalence check. Repoint ingest-paper's handoff to it and align the AGENTS.md "Abstraction first" wording to build the general interface before the concrete model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .claude/skills/grill-formalization/SKILL.md | 79 +++++++++++++++++++++ .claude/skills/ingest-paper/SKILL.md | 6 +- AGENTS.md | 6 +- 3 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 .claude/skills/grill-formalization/SKILL.md diff --git a/.claude/skills/grill-formalization/SKILL.md b/.claude/skills/grill-formalization/SKILL.md new file mode 100644 index 0000000..373a25e --- /dev/null +++ b/.claude/skills/grill-formalization/SKILL.md @@ -0,0 +1,79 @@ +--- +name: grill-formalization +description: Grill a formalization plan against the paper and AGENTS.md before any Lean is written — statement fidelity, abstraction level, deferred hypotheses, Mathlib reuse, proof order. +disable-model-invocation: true +--- + +# grill-formalization + +Interview the user relentlessly about a formalization plan until every decision +that would become permanent sediment in the Lean development is settled — +*before* any tactic is typed. This is `grilling` aimed at one target: the plan to +formalize an ingested paper. + +Run this after `ingest-paper` has left a navigable `references/<slug>/INDEX.md`. +Read that substrate and `AGENTS.md` first; every recommendation you make is +grounded in the paper's actual content and the project's working principles, not +in what Mathlib happens to make easy. + +## Survey first + +Before any question, map the ground you will plan on — a phase that only +understands the architecture, never decides. Read the Lean sources the plan will +touch and write down the existing **structures, typeclasses, and interfaces** +already in play: what each provides, what it assumes, how a new development must +fit them. The grill runs against this written map. + +Ground every line in the **Lean source and mathematical fact** — never in +comments, docstrings, or `.md` notes, which drift. Label each as **fact** (read +off the code, or a proven/standard result) or **inference** (suspected, not yet +verified), and keep the two visibly apart. This discipline holds for the whole +skill. + +*Done when:* the architecture map is written and every line is tagged fact or +inference. + +## The grill loop + +Walk down the design tree below, one axis at a time, resolving dependencies in +order. For each question: + +- Ask **one** question and wait for the answer — multiple at once is bewildering. +- Provide your **recommended** answer, grounded and labelled per *Survey first*. +- If the codebase or the paper answers it, **explore instead of asking** — read + `references/<slug>/`, grep the Lean sources, and use lean-lsp search + (`lean_leansearch`, `lean_loogle`, `lean_local_search`) to check whether an API + already exists. Never invent a plausible-looking lemma name; search, then + report what you found. + +## The design tree + +Grill these decisions in order — later axes depend on earlier ones. Each rule +lives in `AGENTS.md`; read it there, never restate it here. + +1. **Statement fidelity** → *Abstraction first* +2. **Abstraction first** → *Abstraction first* +3. **Deferred hypotheses** → *Prove what is provable; do not defer it* +4. **Mathlib reuse vs. build** → *Project Layout* +5. **Proof skeleton & dependency order** → *Think before coding* +6. **Definition of done** → *Goal-driven verification*, *Prohibited Tokens* + +## Output + +When every axis is settled, write the plan in this format: + +- **Mathematical statement** — the result to formalize, stated in mathematics. +- **Lean statement** — the `theorem` planned for it: the abstract interface, then + its concrete instantiation. +- **Data structures** — the structures / typeclasses the statement and proof need. +- **Hypotheses** — each hypothesis required, justified as model-dependent vs + proven-in-plan (axis 3). +- **Equivalence check** — the points to confirm the Lean statement says *exactly* + the mathematical one. Name where the two could silently diverge — implicit + coercions, hidden finiteness / nonemptiness, quantifier order, hypotheses + weakened to fit Mathlib — and how each is settled, separating what is verified + from what is still inference. + +*Done when:* the plan follows the format above, the Lean statement is argued +equivalent to the mathematical one, and no hypothesis survives axis 3 without +being either proven-in-plan or justified as a model-dependent input. diff --git a/.claude/skills/ingest-paper/SKILL.md b/.claude/skills/ingest-paper/SKILL.md index 61322c2..207bcfe 100644 --- a/.claude/skills/ingest-paper/SKILL.md +++ b/.claude/skills/ingest-paper/SKILL.md @@ -11,7 +11,7 @@ Turn a PDF (paper, lecture notes) into Markdown + extracted images + a filled formalization plan gets grilled against afterwards. This skill stops at a navigable document. It does **not** plan or formalize; the -last step hands off to `/grilling`. +last step hands off to `/grill-formalization`. ## Steps @@ -47,5 +47,5 @@ last step hands off to `/grilling`. 4. **Hand off to planning.** Report the `INDEX.md` path and any caveats (OCR skipped, document split into `sections/`, no images found) — do not paste the summary into chat. Then tell the user the substrate is ready and the next move - is `/grilling` to stress-test the formalization plan against it. - *Done when:* the user has the INDEX path and the `/grilling` pointer. + is `/grill-formalization` to stress-test the formalization plan against it. + *Done when:* the user has the INDEX path and the `/grill-formalization` pointer. diff --git a/AGENTS.md b/AGENTS.md index a011445..e378081 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,8 +23,10 @@ editing. **Abstraction first.** -- Aim for the abstraction level used in the source literature and the mathematically conventional form - from the *first* commit, not as a later refactor. +- Build the general interface before the concrete model — even when the source + literature treats only a specific case. Introduce the abstract structure and + the mathematically conventional form from the *first* commit, not as a later + refactor, then instantiate the concrete model the task needs. - Do not specialise to a concrete model because the immediate task uses only that case, and do not weaken hypotheses to match whatever fragment Mathlib currently has the most lemmas for — From 1660b4d96e62a43c8868b0acacb336d6c02725cb Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 20:39:22 +0000 Subject: [PATCH 036/113] feat: add math-reviewer agent and math-review skill Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .claude/agents/math-reviewer.md | 99 +++++++++++++++++++++++++++++ .claude/skills/math-review/SKILL.md | 35 ++++++++++ 2 files changed, 134 insertions(+) create mode 100644 .claude/agents/math-reviewer.md create mode 100644 .claude/skills/math-review/SKILL.md diff --git a/.claude/agents/math-reviewer.md b/.claude/agents/math-reviewer.md new file mode 100644 index 0000000..39635b8 --- /dev/null +++ b/.claude/agents/math-reviewer.md @@ -0,0 +1,99 @@ +--- +name: math-reviewer +description: >- + Reviews Lean code from a working mathematician's and physicist's viewpoint — + catching what `lake build` cannot: statement fidelity (does the `theorem` + state the intended result?), unfamiliar or deferred data structures and + hypotheses, and hard-to-read notation. Use proactively whenever a theorem has + been stated or proved, an important structure/typeclass has been added, or the + user asks for a mathematical review of Lean code. +tools: Read, Grep, Glob, Bash, mcp__lean-lsp__lean_goal, mcp__lean-lsp__lean_term_goal, mcp__lean-lsp__lean_hover_info, mcp__lean-lsp__lean_diagnostic_messages, mcp__lean-lsp__lean_file_outline, mcp__lean-lsp__lean_local_search, mcp__lean-lsp__lean_leansearch, mcp__lean-lsp__lean_loogle, mcp__lean-lsp__lean_declaration_file +model: inherit +--- + +# math-reviewer + +Review Lean code the way a working mathematician or physicist would read it — +not the way a compiler checks it. Assume `lake build` already passes; your job +is everything the build *cannot* see: whether the Lean says what the author +means, whether it rests on objects and assumptions a mathematician would +recognize, and whether it reads cleanly to a human in the field. + +You never edit files. You inspect and report. Read the rules in `AGENTS.md` and +**reference** them by name in your findings — never restate them here. + +## Survey first + +Map the target before judging it — a phase that only understands the code, +never rewrites it. + +- Identify the review target: from an explicit file/declaration the user names, + or from `git diff` / `git diff --staged` (read-only) when asked to review the + current change. +- For each `theorem` / `def` / `structure` / `class` in scope, read the source, + then confirm the **elaborated** statement with `lean_term_goal`, + `lean_goal`, and `lean_hover_info`. Do not trust the surface syntax, + the declaration name, or the docstring — they drift; the elaborated type is + the fact. +- When you need to know whether an API already exists, search + (`lean_local_search`, `lean_leansearch`, `lean_loogle`) — never invent a + plausible-looking lemma or instance name. + +Ground every line of every finding in the **Lean source or a standard +mathematical fact**, and label each as **fact** (read off the elaborated code, +or a proven/standard result) or **inference** (suspected, not yet verified). +Keep the two visibly apart. + +*Done when:* the target declarations are enumerated and each one's elaborated +type has been inspected, not guessed. + +## Review axes + +Apply all four axes to every declaration in scope. + +1. **Statement fidelity** — does the `theorem` state *exactly* the intended + result? Hunt the places where Lean and mathematics silently diverge: implicit + coercions, quantifier order, hidden finiteness / nonemptiness assumptions, + hypotheses weakened to fit whatever Mathlib makes easy, a statement made + vacuously true by contradictory or unsatisfiable hypotheses, or the + implication pointing the wrong way. Decide from the elaborated type + (`lean_term_goal` / `lean_hover_info`), not the name. See AGENTS.md + *Abstraction first*. + +2. **Unfamiliar or deferred structures & hypotheses** — does the code rest on a + `structure`, `class`, or hypothesis a mathematician or physicist would not + recognize as the conventional object? Flag, as the top priority, any + deferred hypothesis — a `class` / `structure` field or `Prop` argument + standing in for a theorem that has a known proof — which AGENTS.md *Prove + what is provable; do not defer it* forbids. Distinguish it from a genuinely + model-dependent input (acceptable). Before claiming an object is non-standard + or that an alternative exists, confirm with the search tools. + +3. **Readable notation** — would the notation slow a mathematician or physicist + down? Check that established notation from `QuantumSystem/Notation.lean` is + used (`Tr`, `reTr`, and the `Matrix.QuantumInfo` scope: `log ρ`, `S(ρ)`, + `D(ρ ∥ σ)`, `⟪X, Y⟫_HS`) rather than raw Mathlib spellings, and that naming + follows AGENTS.md *Style Guidelines* (`UpperCamelCase` types, + `lowerCamelCase` terms, `_`-separated theorem names). + +4. **Anything else `lake build` cannot catch** — semantic or conventional + problems outside the three axes above: a declaration name that misleads about + what it proves, a docstring that contradicts the statement, an interface that + instantiates a concrete model where the literature works abstractly + (AGENTS.md *Abstraction first*). + +*Done when:* all four axes have been applied to every target declaration. + +## Output + +Return a structured report — you produce findings, not edits. + +- Group findings by axis. For each finding give: a `file_path:line` reference, + the **fact / inference** label, a severity (`blocker` / `should-fix` / + `nit`), what is wrong, and the recommended fix. +- For any axis with nothing to report, say so explicitly. +- Make no edits to any file. + +*Done when:* every one of the four axes carries either findings or an explicit +"no issues", and each finding is tagged fact or inference with a `file:line` +reference. diff --git a/.claude/skills/math-review/SKILL.md b/.claude/skills/math-review/SKILL.md new file mode 100644 index 0000000..7d97c7b --- /dev/null +++ b/.claude/skills/math-review/SKILL.md @@ -0,0 +1,35 @@ +--- +name: math-review +description: Run the mathematician/physicist code review (the `math-reviewer` agent) over explicitly named Lean files or directories — statement fidelity, unfamiliar or deferred structures and hypotheses, and readable notation. +disable-model-invocation: true +--- + +# math-review + +Run the math/physics review on a target the user names explicitly. This skill +only **resolves the target and dispatches** to the `math-reviewer` agent — the +review methodology (the four axes, the elaborated-type discipline, the output +format) lives in `.claude/agents/math-reviewer.md`, never duplicate it here. + +## Steps + +1. **Resolve the target.** Take the file or directory paths from the request + (arguments to the skill, or the paths the user names). Expand each directory + to the `.lean` files under it with Glob; keep explicit file paths as given. + If no path is supplied, ask which file or directory to review — do not guess. + *Done when:* you hold a concrete, non-empty list of `.lean` files to review. + +2. **Dispatch to the `math-reviewer` agent.** Launch the `math-reviewer` agent + (via the Agent tool, `subagent_type: math-reviewer`) on the resolved target: + - A handful of related files → one `math-reviewer` invocation covering the set. + - Many files → one `math-reviewer` per file (or per cohesive module), in parallel + (multiple Agent calls in a single message). + Pass the exact file paths in the prompt and instruct the agent to review only + those. Do not re-implement the review yourself; the agent owns the axes. + *Done when:* every resolved file is covered by a dispatched `reviewer` run. + +3. **Report.** Relay the agents' findings to the user, grouped by file. Preserve + each finding's `file:line` reference, fact/inference label, and severity as + the agent returned them; do not soften or drop findings. If a run found no + issues for a file, say so. + *Done when:* the user has the consolidated findings for every reviewed file. From 36d3695fbff8b26e8f8a5700e9da09b0838de2c7 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 20:54:54 +0000 Subject: [PATCH 037/113] docs: fix relativeEntropy_channel_le docstring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The statement carries no positive-definiteness hypothesis; drop the inaccurate restriction and use the codebase D(· ∥ ·) notation for relative entropy instead of S(·‖·). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- QuantumSystem/Analysis/Entropy/RelativeEntropy.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean index a28da44..6f7048c 100644 --- a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean @@ -1324,8 +1324,8 @@ private lemma trace_rpow_mul_channel_le /-- **Monotonicity of Relative Entropy**: Quantum channels do not increase relative entropy. -For a quantum channel Φ and positive definite density matrices ρ, σ: - S(Φ(ρ) || Φ(σ)) ≤ S(ρ || σ) +For a quantum channel Φ and density matrices ρ, σ: + D(Φ(ρ) ∥ Φ(σ)) ≤ D(ρ ∥ σ) **Proof**: Uses derivative argument on g(s) = F_s(Φρ, Φσ) - F_s(ρ, σ) where F_s(A, B) = Tr (Aˢ B¹⁻ˢ). Since g(s) ≥ 0 on (0,1] and g(1) = 0, we get g'(1) ≤ 0, From 9ab774459154cf94e2f07d06c51972ca10dfa80e Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 21:03:50 +0000 Subject: [PATCH 038/113] docs: relax line-length guideline from 100 to 120 columns The 100-column limit was a guideline only; the longLine linter is disabled in lakefile.toml and the codebase already has many lines past 100. Align the guideline with the codebase at 120 columns. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index e378081..37e8722 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,7 +98,7 @@ The Mathlib contribute templates are authoritative; the bullets below distill wh - Prefer the `_of_` pattern for implications (`continuous_of_lipschitz`); `iff` joins equivalences; `not_` prefixes negations. **Layout.** -- 100-column line limit. +- 120-column line limit. - 2-space indentation; `by` stays on the same line as the goal it opens unless the resulting line would exceed the limit. - Hoist shared hypotheses into `variable` blocks; keep explicit/implicit arity consistent with sibling lemmas. - Align `calc` steps on the relation; use `·` (centered dot) for focused goals, not `case _ =>`. From e726565e3995ad017a11157c8a3cdadbc413227d Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 21:16:56 +0000 Subject: [PATCH 039/113] feat: export microcausality to quasi-local C*-algebra MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `ιLocalCStar_commute_of_disjoint`: observables in disjoint regions commute inside the completed quasi-local C*-algebra. Transports the pre-completion `ιLocal_commute_of_disjoint` along the completion ring-hom coercion via `Commute.map`, so the headline object carries the microcausality property a physicist invokes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .../Algebra/LocalNet/QuasiLocalAlgebra.lean | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean index 5b2b7bc..ff48d94 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean @@ -20,11 +20,11 @@ The **algebra of local observables** and the **quasi-local C⋆-algebra** of an embeddings `ιLocalCStar`. A `LocalNet.Covariance` (defined in `LocalNet.Covariance`) acts on these algebras: its per-region -`*`-isomorphisms assemble into a `*`-endomorphism `quasiLocalCovariance` of the algebra of local -observables, which is functorial, `ℂ`-linear and `*`-preserving — hence a `*`-automorphism -`quasiLocalCovarianceEquiv`, assembled into a group homomorphism `quasiLocalCovarianceHom`. For a -`Faithful` net it is isometric and extends to a `*`-automorphism `quasiLocalCStarCovarianceEquiv` of -the quasi-local C⋆-algebra. +`*`-isomorphisms assemble into a ring endomorphism `quasiLocalCovariance` of the algebra of local +observables, which is functorial and is shown `ℂ`-linear and `*`-preserving — hence bundled as a +`*`-automorphism `quasiLocalCovarianceEquiv`, assembled into a group homomorphism +`quasiLocalCovarianceHom`. For a `Faithful` net it is isometric and extends to a `*`-automorphism +`quasiLocalCStarCovarianceEquiv` of the quasi-local C⋆-algebra. -/ @[expose] public section @@ -153,6 +153,13 @@ theorem denseRange_iUnion_ιLocalCStar : obtain ⟨Λ, X, rfl⟩ := N.exists_ιLocal z exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ +/-- **Locality in the quasi-local C⋆-algebra**: observables localised in disjoint regions commute + inside `𝔄`. Transports `ιLocal_commute_of_disjoint` along the completion coercion. -/ +theorem ιLocalCStar_commute_of_disjoint {Λ₁ Λ₂ : Finset sites} (hd : Disjoint Λ₁ Λ₂) + (X : N.algebra Λ₁) (Y : N.algebra Λ₂) : + Commute (N.ιLocalCStar Λ₁ X) (N.ιLocalCStar Λ₂ Y) := + (N.ιLocal_commute_of_disjoint hd X Y).map UniformSpace.Completion.coeRingHom + end CStar namespace Covariance From b0d94bccf322039365d66dcf48b6731f1f3982fa Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 28 Jun 2026 21:17:06 +0000 Subject: [PATCH 040/113] docs: align covariance docstrings with types and group-action boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reconcile the QuasiLocalAlgebra module docstring with the actual type of `quasiLocalCovariance` (a ring endomorphism shown C-linear and *-preserving, then bundled as `quasiLocalCovarianceEquiv`), and note in the Covariance module docstring how a symmetry group `G` acts via a `G →* Covariance` composed with `quasiLocalCovarianceHom`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- QuantumSystem/Algebra/LocalNet/Covariance.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 9f7ed80..0f0c9bd 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -14,7 +14,10 @@ covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp` This file isolates the abstract covariance *data* and its group structure. Its *action* on the quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism `quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local -C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. +C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. A symmetry group `G` acts on the net by +supplying a group homomorphism `G →* N.Covariance` (whose `σ`-component is the geometric action +`G → sites ≃ sites`); composing it with `quasiLocalCovarianceHom` — or, for a `Faithful` net, +`quasiLocalCStarCovarianceHom` — yields the automorphic action of `G` on the (quasi-local) algebra. -/ @[expose] public section From c2b3d061e7b28906927631fc1ad2e57ea5d26ec0 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Mon, 29 Jun 2026 08:55:54 +0000 Subject: [PATCH 041/113] feat: capture paper dependency DAG in ingest-paper INDEX.md Add Main results (as a dependency DAG) and Load-bearing assumptions sections to the INDEX.md scaffold so the paper's derivation skeleton is distilled once, instead of grill-formalization re-reading the content each session. Each result node carries a depends-on edge referencing other nodes, assumptions, and cited external results; assumptions are recorded neutrally with classification left to grill-formalization. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .claude/skills/ingest-paper/SKILL.md | 36 +++++++++++++++---- .../skills/ingest-paper/scripts/convert.py | 33 ++++++++++++++--- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/.claude/skills/ingest-paper/SKILL.md b/.claude/skills/ingest-paper/SKILL.md index 207bcfe..11d5a15 100644 --- a/.claude/skills/ingest-paper/SKILL.md +++ b/.claude/skills/ingest-paper/SKILL.md @@ -11,7 +11,10 @@ Turn a PDF (paper, lecture notes) into Markdown + extracted images + a filled formalization plan gets grilled against afterwards. This skill stops at a navigable document. It does **not** plan or formalize; the -last step hands off to `/grill-formalization`. +last step hands off to `/grill-formalization`. The structured sections it fills +(Main results, Load-bearing assumptions) **record** what the paper states — they +never judge formalizability or classify hypotheses; that judgement belongs to +`/grill-formalization`. ## Steps @@ -33,19 +36,40 @@ last step hands off to `/grill-formalization`. *Done when:* the script prints its JSON summary (`slug`, `output_dir`, `index_path`, `page_count`, `image_count`, `sectioned`) and exits 0. -3. **Fill the INDEX.md scaffold.** The script leaves two `<!-- TODO -->` blocks. - Read `content.md` (or the `sections/*.md` files) and replace **both**: +3. **Fill the INDEX.md scaffold.** The script leaves four `<!-- TODO -->` blocks. + Read `content.md` (or the `sections/*.md` files) and replace **all four**: - **Summary** — 3–5 sentences: what this document is and why a formalization agent would consult it. From the actual content, not the title. - **Key concepts** — bullet list an agent would grep for. **Every bullet starts with a `` `backtick-identifier` ``** naming the concept, then a short gloss. Omit the section only for pure-prose documents with no greppable terminology. - *Done when:* no `<!-- TODO -->` marker remains anywhere in `INDEX.md`, and - every Key-concepts bullet begins with a backtick identifier. + - **Main results** — the results this document targets for formalization, + recorded as a **dependency DAG** so the proof skeleton survives. List the + headline theorems **and** the intermediate lemmas/propositions they rest on, + so every edge resolves. **Every bullet starts with a + `` `backtick-identifier` ``** (the candidate Lean name), then a one-line + *mathematical* statement and a pointer to where it lives (`sections/NN-*.md` + or `content.md#anchor`), followed by a `depends on:` line referencing other + nodes, `` `assumption-id` ``s, and external results as `[cited: ...]` (Mathlib + reuse candidates). Drop the `depends on:` line for a leaf with no stated + dependencies. Record what the paper states; do **not** judge formalizability + or proof order. + - **Load-bearing assumptions** — the hypotheses the Main results depend on, + recorded **neutrally** from the paper. **Every bullet starts with a + `` `backtick-identifier` ``** (referenced from the Main-results `depends on:` + lines), then the assumption and which result(s) rely on it. Do **not** + classify model-dependent vs provable — that is `/grill-formalization`'s call. + Omit only if the document states no explicit hypotheses. + *Done when:* no `<!-- TODO -->` marker remains anywhere in `INDEX.md`, every + Key-concepts, Main-results, and Load-bearing-assumptions bullet (in the + sections that are present) begins with a backtick identifier, and every + Main-results `depends on:` reference resolves to a node/assumption id in the + document or a `[cited: ...]` external result. 4. **Hand off to planning.** Report the `INDEX.md` path and any caveats (OCR skipped, document split into `sections/`, no images found) — do not paste the summary into chat. Then tell the user the substrate is ready and the next move - is `/grill-formalization` to stress-test the formalization plan against it. + is `/grill-formalization`, which reads Main results and Load-bearing + assumptions to stress-test the formalization plan against the paper. *Done when:* the user has the INDEX path and the `/grill-formalization` pointer. diff --git a/.claude/skills/ingest-paper/scripts/convert.py b/.claude/skills/ingest-paper/scripts/convert.py index 8a73657..ff32080 100644 --- a/.claude/skills/ingest-paper/scripts/convert.py +++ b/.claude/skills/ingest-paper/scripts/convert.py @@ -7,9 +7,9 @@ Produces under ``<output-dir>/<slug>/``: -- ``INDEX.md`` Metadata, ToC, and scaffolded Summary / Key concepts / Bibliography - frontmatter sections that the caller (Claude) fills in after - reading the content. +- ``INDEX.md`` Metadata, ToC, and scaffolded Summary / Key concepts / + Main results / Load-bearing assumptions sections that the caller + (Claude) fills in after reading the content. - ``content.md`` Full Markdown (if total pages <= max-pages-per-section). - ``sections/`` Split Markdown files (if total pages exceed the threshold and the document has top-level ``#`` / ``## `` headings to split on). @@ -349,8 +349,8 @@ def main() -> int: content_md.write_text(md_text, encoding="utf-8") toc_lines.extend(_flat_toc_for_content(md_text)) - # Scaffold INDEX.md (Claude fills Summary / Key concepts / authors / - # bibliography / mathlib annotations per SKILL.md steps 4a-4f). + # Scaffold INDEX.md (Claude fills Summary / Key concepts / Main results / + # Load-bearing assumptions per SKILL.md step 3). index = [ "---", f"title: {json.dumps(title, ensure_ascii=False)}", @@ -374,6 +374,29 @@ def main() -> int: " cross-document concept index. Omit the section if no greppable", " terminology exists (e.g. pure prose papers). -->", "", + "## Main results", + "", + "<!-- TODO: The results this document targets for formalization, recorded as a", + " dependency DAG so the proof skeleton survives. Include the headline", + " theorems AND the intermediate lemmas/propositions they rest on, so every", + " edge resolves. Each bullet:", + " - `result-id` — one-line MATHEMATICAL statement (sections/NN-*.md#anchor)", + " depends on: `other-result-id`, `assumption-id`, [cited: Author Year, Thm N]", + " `assumption-id` points at a Load-bearing-assumptions bullet; [cited: ...]", + " names an external result (a Mathlib-reuse candidate). Drop the `depends on:`", + " line for a leaf with no stated dependencies. Record what the paper states;", + " do not judge formalizability or proof order — that is grill-formalization's", + " job. -->", + "", + "## Load-bearing assumptions", + "", + "<!-- TODO: The hypotheses the Main results depend on, recorded NEUTRALLY from", + " the paper. Each bullet starts with a `backtick-identifier` (referenced from", + " the Main-results `depends on:` lines), then the assumption and which", + " result(s) rely on it. Do NOT classify model-dependent vs provable —", + " grill-formalization decides that (AGENTS.md: \"Prove what is provable\").", + " Omit only if the document states no explicit hypotheses. -->", + "", "## Contents", "", *toc_lines, From 29db0e79cc4a4da4ce0f0bf125c7382c5879e0cb Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Mon, 29 Jun 2026 23:18:09 +0000 Subject: [PATCH 042/113] docs: require matching code to docs when docs overclaim Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- AGENTS.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 37e8722..f11ebe5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,6 +47,15 @@ irreducible (a) inputs — and proving or descoping everything else — is what keeps that base bounded. +**Match the code to the docs, not the docs to the code.** +- When a docstring or module comment claims more than the code actually + establishes, raise the code to meet the claim — strengthen the statement, + discharge the missing hypothesis, or generalise the definition. Do not + weaken the documentation to match a thinner implementation. + **Why:** the documentation records the *intended* theorem; trimming it to + match a shortfall silently shrinks the goal and hides the gap instead of + closing it. + **Goal-driven verification (Definition of Done).** - A change is done only when `lake build` completes with no new errors or warnings on the edited modules and their downstream importers. From 4ccce22dbb17fe49ee9ebf0014d22c676dc7244f Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:10:57 +0000 Subject: [PATCH 043/113] feat: add type I factor structure theory and Hilbert tensor factors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 12 + QuantumSystem/Algebra/Star/TensorProduct.lean | 239 ++++++ .../VonNeumannAlgebra/CentralProjection.lean | 144 ++++ .../Algebra/VonNeumannAlgebra/Comparison.lean | 229 ++++++ .../VonNeumannAlgebra/CoveringFamily.lean | 173 +++++ .../Algebra/VonNeumannAlgebra/Factor.lean | 140 ++++ .../GeneratedByMatrixUnits.lean | 247 ++++++ .../VonNeumannAlgebra/MatrixUnits.lean | 158 ++++ .../SpatialDecomposition.lean | 317 ++++++++ .../TensorIdentification.lean | 388 ++++++++++ .../Algebra/Star/PartialIsometry.lean | 137 ++++ .../TensorProductCompletion.lean | 712 ++++++++++++++++++ .../Analysis/VonNeumannAlgebra/Commutant.lean | 188 +++++ 13 files changed, 3084 insertions(+) create mode 100644 QuantumSystem/Algebra/Star/TensorProduct.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean create mode 100644 QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean create mode 100644 QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean create mode 100644 QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 77c7aed..93c78ed 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -22,6 +22,15 @@ public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra +public import QuantumSystem.Algebra.Star.TensorProduct +public import QuantumSystem.Algebra.VonNeumannAlgebra.CentralProjection +public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison +public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily +public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor +public import QuantumSystem.Algebra.VonNeumannAlgebra.GeneratedByMatrixUnits +public import QuantumSystem.Algebra.VonNeumannAlgebra.MatrixUnits +public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition +public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification public import QuantumSystem.Analysis.CFC.Diagonal public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.MutualInformation @@ -36,6 +45,7 @@ public import QuantumSystem.Analysis.Matrix.Pinching public import QuantumSystem.Analysis.Matrix.PosDef public import QuantumSystem.Channel public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar +public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry public import QuantumSystem.ForMathlib.Analysis.Calculus.Deriv.Sign public import QuantumSystem.ForMathlib.Analysis.Complex.Basic public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.DirectLimit @@ -48,11 +58,13 @@ public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotatio public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.DiagonalAmplification public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.InvariantSubspace public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.StrongOperatorTopology public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.WeakOperatorTopology public import QuantumSystem.ForMathlib.Analysis.Matrix.Basic public import QuantumSystem.ForMathlib.Analysis.Matrix.Hermitian public import QuantumSystem.ForMathlib.Analysis.Matrix.Order +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PosDef diff --git a/QuantumSystem/Algebra/Star/TensorProduct.lean b/QuantumSystem/Algebra/Star/TensorProduct.lean new file mode 100644 index 0000000..2c2fb2f --- /dev/null +++ b/QuantumSystem/Algebra/Star/TensorProduct.lean @@ -0,0 +1,239 @@ +module + +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import Mathlib.Analysis.InnerProductSpace.Adjoint + +/-! +# The tensor von Neumann factors `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)` + +Using the operator amplifications `amplifyLeft : B(H₁) → B(H₁ ⊗̂ H₂)` and +`amplifyRight : B(H₂) → B(H₁ ⊗̂ H₂)` (from `TensorProductCompletion`), this file defines the two +von Neumann factors on the completed Hilbert tensor product: + +* `HilbertTensor.vnTensorLeft = B(H₁) ⊗̄ 1` — the von Neumann algebra generated by the image of + `amplifyLeft`, +* `HilbertTensor.vnTensorRight = 1 ⊗̄ B(H₂)` — the von Neumann algebra generated by the image of + `amplifyRight`. + +These are the objects in the split-property tensor decomposition `A₁ ⊆ B(H₁)⊗̄1`, +`A₂ ⊆ 1⊗̄B(H₂)` (paper eq. (39)). The file culminates in the **tensor commutation theorem** +`vnTensorLeft.commutant = vnTensorRight` (von Neumann's commutation theorem for a full factor on +the first leg): the commutant of `B(H₁)⊗̄1` is exactly `1⊗̄B(H₂)`. + +## Main definitions + +* `HilbertTensor.vnTensorLeft`, `HilbertTensor.vnTensorRight`. +* `HilbertTensor.tmulRightL f` — the inclusion `H₂ → H₁ ⊗̂ H₂`, `z ↦ f ⊗ z`. + +## Main results + +* `HilbertTensor.amplifyLeft_mem_vnTensorLeft` / `amplifyRight_mem_vnTensorRight` — the + amplified operators lie in the corresponding factor. +* `HilbertTensor.amplifyLeft_comp_amplifyRight` — the two amplifications commute. +* `HilbertTensor.mem_vnTensorRight_of_commutes` — the slice lemma: an operator commuting with all + `A ⊗̂ 1` is of the form `1 ⊗̂ S`. +* `HilbertTensor.vnTensorLeft_commutant` — the tensor commutation theorem + `(B(H₁)⊗̄1)' = 1⊗̄B(H₂)`. +-/ + +@[expose] public section + +open scoped TensorProduct + +namespace HilbertTensor + +variable {H₁ H₂ : Type*} + [NormedAddCommGroup H₁] [InnerProductSpace ℂ H₁] + [NormedAddCommGroup H₂] [InnerProductSpace ℂ H₂] + +/-- The von Neumann factor `B(H₁) ⊗̄ 1` acting on `HilbertTensor H₁ H₂`: the von Neumann algebra +generated by the image of the left amplification `A ↦ A ⊗̂ 1`. -/ +noncomputable def vnTensorLeft : VonNeumannAlgebra (HilbertTensor H₁ H₂) := + VonNeumannAlgebra.generated (Set.range (amplifyLeft (H₂ := H₂))) + +/-- The von Neumann factor `1 ⊗̄ B(H₂)` acting on `HilbertTensor H₁ H₂`: the von Neumann algebra +generated by the image of the right amplification `B ↦ 1 ⊗̂ B`. -/ +noncomputable def vnTensorRight : VonNeumannAlgebra (HilbertTensor H₁ H₂) := + VonNeumannAlgebra.generated (Set.range (amplifyRight (H₁ := H₁))) + +/-- Every left amplification `A ⊗̂ 1` lies in the factor `B(H₁) ⊗̄ 1`. -/ +theorem amplifyLeft_mem_vnTensorLeft (A : H₁ →L[ℂ] H₁) : + amplifyLeft (H₂ := H₂) A ∈ vnTensorLeft := + VonNeumannAlgebra.mem_generated_of_mem ⟨A, rfl⟩ + +/-- Every right amplification `1 ⊗̂ B` lies in the factor `1 ⊗̄ B(H₂)`. -/ +theorem amplifyRight_mem_vnTensorRight (B : H₂ →L[ℂ] H₂) : + amplifyRight (H₁ := H₁) B ∈ vnTensorRight := + VonNeumannAlgebra.mem_generated_of_mem ⟨B, rfl⟩ + +/-- The commutant of `B(H₁) ⊗̄ 1` is the commutant of the range of `amplifyLeft` (bicommutant +collapse). This reduces the tensor commutation theorem `vnTensorLeft.commutant = vnTensorRight` +to the identity `(range amplifyLeft)' = 1 ⊗̄ B(H₂)`. -/ +theorem vnTensorLeft_commutant_eq_commutantSet : + (vnTensorLeft (H₁ := H₁) (H₂ := H₂)).commutant + = VonNeumannAlgebra.commutantSet (Set.range (amplifyLeft (H₂ := H₂))) := + VonNeumannAlgebra.commutant_generated _ + +/-- The commutant of `1 ⊗̄ B(H₂)` is the commutant of the range of `amplifyRight`. -/ +theorem vnTensorRight_commutant_eq_commutantSet : + (vnTensorRight (H₁ := H₁) (H₂ := H₂)).commutant + = VonNeumannAlgebra.commutantSet (Set.range (amplifyRight (H₁ := H₁))) := + VonNeumannAlgebra.commutant_generated _ + +/-! ### The tensor commutation theorem + +The commutant of `B(H₁) ⊗̄ 1` is exactly `1 ⊗̄ B(H₂)` — von Neumann's commutation theorem for the +special case of a full factor on the first leg. The hard inclusion +`(B(H₁)⊗̄1)' ⊆ 1⊗̄B(H₂)` is the slice argument: an operator `T` commuting with every `A ⊗̂ 1` +must be of the form `1 ⊗̂ S`, where `S = ι_e* ∘ T ∘ ι_e` for a fixed unit vector `e ∈ H₁` and +`ι_e : H₂ → H₁ ⊗̂ H₂`, `y ↦ e ⊗ y`. The reduction to a pure-tensor computation uses the rank-one +operators `|f⟩⟨e|` on `H₁`. -/ + +/-- The bounded inclusion `H₂ → H₁ ⊗̂ H₂`, `z ↦ f ⊗ z`, for a fixed `f ∈ H₁`. Its operator norm +is `‖f‖` (`‖tmulRightL f z‖ = ‖f‖ * ‖z‖`), so it is an isometry exactly when `‖f‖ = 1`. -/ +noncomputable def tmulRightL (f : H₁) : H₂ →L[ℂ] HilbertTensor H₁ H₂ := + UniformSpace.Completion.toComplL.comp + (LinearMap.mkContinuous (TensorProduct.mk ℂ H₁ H₂ f) ‖f‖ fun z => by + rw [TensorProduct.mk_apply, TensorProduct.norm_tmul]) + +@[simp] theorem tmulRightL_apply (f : H₁) (z : H₂) : tmulRightL f z = tmul f z := rfl + +/-- The left and right amplifications commute: `(A ⊗̂ 1)(1 ⊗̂ B) = A ⊗̂ B = (1 ⊗̂ B)(A ⊗̂ 1)`. -/ +theorem amplifyLeft_comp_amplifyRight (A : H₁ →L[ℂ] H₁) (B : H₂ →L[ℂ] H₂) : + (amplifyLeft (H₂ := H₂) A).comp (amplifyRight (H₁ := H₁) B) + = (amplifyRight B).comp (amplifyLeft A) := by + refine ContinuousLinearMap.ext fun w => ?_ + refine UniformSpace.Completion.induction_on w + (isClosed_eq (by fun_prop) (by fun_prop)) (fun a => ?_) + induction a using TensorProduct.induction_on with + | zero => simp only [UniformSpace.Completion.coe_zero, map_zero] + | tmul f y => + change amplifyLeft A (amplifyRight B (tmul f y)) = amplifyRight B (amplifyLeft A (tmul f y)) + rw [amplifyRight_tmul, amplifyLeft_tmul, amplifyLeft_tmul, amplifyRight_tmul] + | add p q hp hq => rw [UniformSpace.Completion.coe_add, map_add, map_add, hp, hq] + +section CompleteRight + +variable [CompleteSpace H₂] + +/-- The adjoint of the inclusion `ι_e` acts on pure tensors as the `e`-slice +`g ⊗ z ↦ ⟪e, g⟫ • z`. -/ +theorem adjoint_tmulRightL_tmul (e g : H₁) (z : H₂) : + ContinuousLinearMap.adjoint (tmulRightL (H₂ := H₂) e) (tmul g z) = (inner ℂ e g) • z := by + refine ext_inner_right ℂ fun y => ?_ + rw [ContinuousLinearMap.adjoint_inner_left, tmulRightL_apply, inner_tmul, inner_smul_left, + inner_conj_symm] + +/-- The amplification of a rank-one operator `|f⟩⟨e|` factors through the `e`-slice and the +inclusion `ι_f`: `(|f⟩⟨e|) ⊗̂ 1 = ι_f ∘ ι_e*`. This is the algebraic heart of the slice +argument. -/ +theorem amplifyLeft_rankOne_eq (e f : H₁) : + amplifyLeft (H₂ := H₂) (InnerProductSpace.rankOne ℂ f e) + = (tmulRightL f).comp (ContinuousLinearMap.adjoint (tmulRightL e)) := by + refine ContinuousLinearMap.ext fun w => ?_ + refine UniformSpace.Completion.induction_on w + (isClosed_eq (by fun_prop) (by fun_prop)) (fun a => ?_) + induction a using TensorProduct.induction_on with + | zero => simp only [UniformSpace.Completion.coe_zero, map_zero] + | tmul g z => + change amplifyLeft _ (tmul g z) + = (tmulRightL f).comp (ContinuousLinearMap.adjoint (tmulRightL e)) (tmul g z) + rw [amplifyLeft_tmul, ContinuousLinearMap.comp_apply, adjoint_tmulRightL_tmul, + tmulRightL_apply, InnerProductSpace.rankOne_apply, + tmul_smul_left, smul_tmul_right] + | add p q hp hq => rw [UniformSpace.Completion.coe_add, map_add, map_add, hp, hq] + +/-- **Slice lemma (dense form).** If `T` commutes with the rank-one amplifications +`(|f⟩⟨e|) ⊗̂ 1` for `f` ranging over a set `D` whose span is dense in `H₁` (and a fixed unit vector +`e ∈ H₁`), then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e`, hence `T ∈ 1 ⊗̄ B(H₂)`. The relation +`T (f ⊗̂ y) = f ⊗̂ (S y)` is first established for `f ∈ D` and then extended to all `f` by density, +working at the level of the bounded inclusions `ι_y : f ↦ f ⊗̂ y`. -/ +theorem mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) + (hD : Dense (Submodule.span ℂ D : Set H₁)) + (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) + (hT : ∀ f ∈ D, T.comp (amplifyLeft (InnerProductSpace.rankOne ℂ f e)) + = (amplifyLeft (InnerProductSpace.rankOne ℂ f e)).comp T) : + T ∈ vnTensorRight := by + set S := (ContinuousLinearMap.adjoint (tmulRightL e)).comp (T.comp (tmulRightL e)) with hS + have hee : inner ℂ e e = (1 : ℂ) := by rw [inner_self_eq_norm_sq_to_K, he]; norm_num + have key : ∀ f ∈ D, ∀ y : H₂, T (tmul f y) = tmul f (S y) := by + intro f hf y + have e1 : amplifyLeft (H₂ := H₂) (InnerProductSpace.rankOne ℂ f e) (tmul e y) = tmul f y := by + rw [amplifyLeft_tmul, InnerProductSpace.rankOne_apply, hee, one_smul] + calc T (tmul f y) + = T (amplifyLeft (InnerProductSpace.rankOne ℂ f e) (tmul e y)) := by rw [e1] + _ = amplifyLeft (InnerProductSpace.rankOne ℂ f e) (T (tmul e y)) := by + rw [← ContinuousLinearMap.comp_apply, hT f hf, ContinuousLinearMap.comp_apply] + _ = (tmulRightL f).comp (ContinuousLinearMap.adjoint (tmulRightL e)) (T (tmul e y)) := by + rw [amplifyLeft_rankOne_eq] + _ = tmul f (S y) := by + rw [ContinuousLinearMap.comp_apply, tmulRightL_apply, hS] + simp only [ContinuousLinearMap.comp_apply, tmulRightL_apply] + have key_all : ∀ (f : H₁) (y : H₂), T (tmul f y) = tmul f (S y) := by + intro f y + have hcl : T.comp (tmulLeftL y) = (amplifyRight S).comp (tmulLeftL y) := by + refine ContinuousLinearMap.ext_on hD (fun g hg => ?_) + rw [ContinuousLinearMap.comp_apply, ContinuousLinearMap.comp_apply, tmulLeftL_apply, + amplifyRight_tmul, key g hg y] + have h := congrArg (fun L : H₁ →L[ℂ] HilbertTensor H₁ H₂ => L f) hcl + simpa only [ContinuousLinearMap.comp_apply, tmulLeftL_apply, amplifyRight_tmul] using h + have hTS : T = amplifyRight S := by + refine ContinuousLinearMap.ext fun w => ?_ + refine UniformSpace.Completion.induction_on w + (isClosed_eq T.continuous (amplifyRight S).continuous) (fun a => ?_) + induction a using TensorProduct.induction_on with + | zero => simp only [UniformSpace.Completion.coe_zero, map_zero] + | tmul f y => + change T (tmul f y) = amplifyRight S (tmul f y) + rw [key_all, amplifyRight_tmul] + | add p q hp hq => rw [UniformSpace.Completion.coe_add, map_add, map_add, hp, hq] + rw [hTS] + exact amplifyRight_mem_vnTensorRight S + +/-- **Slice lemma (hard inclusion of the commutation theorem).** If `T` commutes with every left +amplification `A ⊗̂ 1`, then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e` (any unit vector `e ∈ H₁`), +hence `T ∈ 1 ⊗̄ B(H₂)`. -/ +theorem mem_vnTensorRight_of_commutes (e : H₁) (he : ‖e‖ = 1) + (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) + (hT : ∀ A : H₁ →L[ℂ] H₁, T.comp (amplifyLeft A) = (amplifyLeft A).comp T) : + T ∈ vnTensorRight := + mem_vnTensorRight_of_commutes_dense e he Set.univ + (by rw [Submodule.span_univ, Submodule.top_coe]; exact dense_univ) T + (fun f _ => hT (InnerProductSpace.rankOne ℂ f e)) + +end CompleteRight + +/-- **Tensor commutation theorem.** The commutant of the von Neumann factor `B(H₁) ⊗̄ 1` is exactly +`1 ⊗̄ B(H₂)`. This is von Neumann's commutation theorem `(M ⊗ 1)' = M' ⊗ B(H₂)` for `M = B(H₁)` +(whose commutant `M'` is `ℂ`), and it is the analytic core of the split-property tensor +decomposition: combined with `vnTensorLeft_commutant_eq_commutantSet` and a unit vector in `H₁`, +it identifies `A₁ ⊆ B(H₁)⊗̄1` with `A₂ ⊆ 1⊗̄B(H₂)` for commuting `A₁, A₂`. -/ +theorem vnTensorLeft_commutant [CompleteSpace H₁] [CompleteSpace H₂] [Nontrivial H₁] : + (vnTensorLeft (H₁ := H₁) (H₂ := H₂)).commutant = vnTensorRight := by + rw [vnTensorLeft_commutant_eq_commutantSet] + refine le_antisymm ?_ ?_ + · -- hard inclusion: every `T` commuting with `B(H₁)⊗̄1` lies in `1⊗̄B(H₂)` + obtain ⟨x, hx⟩ := exists_ne (0 : H₁) + have he : ‖(‖x‖⁻¹ : ℂ) • x‖ = 1 := by + rw [norm_smul, norm_inv, Complex.norm_real, norm_norm, + inv_mul_cancel₀ (norm_ne_zero_iff.mpr hx)] + intro T hT + refine mem_vnTensorRight_of_commutes _ he T fun A => ?_ + have hc := (VonNeumannAlgebra.mem_commutantSet_iff.mp hT (amplifyLeft A) ⟨A, rfl⟩).1 + rw [← ContinuousLinearMap.mul_def, ← ContinuousLinearMap.mul_def] + exact hc.symm + · -- easy inclusion: `1⊗̄B(H₂)` commutes with `B(H₁)⊗̄1` + change VonNeumannAlgebra.generated (Set.range (amplifyRight (H₁ := H₁))) + ≤ VonNeumannAlgebra.commutantSet (Set.range (amplifyLeft (H₂ := H₂))) + refine VonNeumannAlgebra.generated_le ?_ + rintro g ⟨B, rfl⟩ + rw [SetLike.mem_coe, VonNeumannAlgebra.mem_commutantSet_iff] + rintro h ⟨A, rfl⟩ + refine ⟨?_, ?_⟩ + · rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] + exact amplifyLeft_comp_amplifyRight A B + · rw [amplifyLeft_star, ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] + exact amplifyLeft_comp_amplifyRight (star A) B + +end HilbertTensor diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean new file mode 100644 index 0000000..a610883 --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean @@ -0,0 +1,144 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor + +/-! +# Central projections in a von Neumann algebra + +A **central projection** of `N` is a projection lying in the centre `N ∩ N'`. This file records +the basic facts, in particular that in a *factor* the only central projections are the trivial +ones `0` and `1` — the projection-level expression of the triviality of the centre, and the seed +of "central support `= 1`" used in the comparison theory. + +## Main definitions + +* `VonNeumannAlgebra.IsCentralProjection N e` — `e` is a projection in `N ∩ N'`. + +## Main results + +* `VonNeumannAlgebra.IsFactor.central_projection_eq` — in a factor every central projection is + `0` or `1`. +* `VonNeumannAlgebra.isStarProjection_mem_commutant_iff` — a star projection lies in the commutant + `N'` exactly when its range is invariant under every element of `N` (the projection–reducing + subspace bridge used to build central supports). +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- A **central projection** of `N`: a star projection lying in both `N` and its commutant +(equivalently, in the centre `N ∩ N'`). -/ +def IsCentralProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := + IsStarProjection e ∧ e ∈ N ∧ e ∈ N.commutant + +/-- `0` is a central projection. -/ +theorem isCentralProjection_zero (N : VonNeumannAlgebra H) : IsCentralProjection N 0 := + ⟨IsStarProjection.zero _, zero_mem _, zero_mem _⟩ + +/-- `1` is a central projection. -/ +theorem isCentralProjection_one (N : VonNeumannAlgebra H) : IsCentralProjection N 1 := + ⟨IsStarProjection.one _, one_mem _, one_mem _⟩ + +/-- In a factor, every central projection is trivial: it is `0` or `1`. This is the +projection-level form of the triviality of the centre. -/ +theorem IsFactor.central_projection_eq [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsCentralProjection N e) : + e = 0 ∨ e = 1 := by + obtain ⟨c, hc⟩ := hN e he.2.1 he.2.2 + have hidem : e * e = e := he.1.isIdempotentElem + rw [hc] at hidem + have hcc : (c * c) • (1 : H →L[ℂ] H) = c • 1 := by + rw [← hidem, smul_mul_smul_comm, mul_one] + have hc2 : c * c = c := smul_left_injective ℂ one_ne_zero hcc + have h0 : c * (c - 1) = 0 := by rw [mul_sub, mul_one, hc2, sub_self] + rcases mul_eq_zero.mp h0 with h | h + · exact Or.inl (by rw [hc, h, zero_smul]) + · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) + +/-- A star projection lies in the commutant `N'` exactly when its range is invariant under every +element of `N`. This is the bridge between reducing subspaces and (eventually central) +projections: it follows from the double-commutant characterisation +`VonNeumannAlgebra.IsStarProjection.mem_iff` together with `commutant_commutant`. -/ +theorem isStarProjection_mem_commutant_iff {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsStarProjection e) : + e ∈ N.commutant ↔ ∀ y ∈ N, (e.range) ∈ Module.End.invtSubmodule (y : Module.End ℂ H) := by + rw [IsStarProjection.mem_iff he N.commutant, commutant_commutant] + +/-- **Central support (factor case).** In a factor, a nonzero operator `q` meets the +"`N`-orbit" of any nonzero `e ∈ N`: there is `a ∈ N` with `q a e ≠ 0`. The statement needs no +projection hypothesis on `e` or `q`, only `e ∈ N`, `e ≠ 0` and `q ≠ 0`. The proof takes the +orthogonal projection `P` onto the closed `N`-invariant subspace generated by `e H`; `P` reduces +both `N` and `N'`, so it is central, hence `0` or `1`; since `P` acts as the identity on `e H` +(so `P ≠ 0`, as `e ≠ 0`), `P = 1`, so the generated subspace is the whole space and `q` cannot +annihilate it. This is the geometric input of the comparison theorem. -/ +theorem IsFactor.exists_mul_ne [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) + {e q : H →L[ℂ] H} (heN : e ∈ N) (he0 : e ≠ 0) (hq0 : q ≠ 0) : ∃ a ∈ N, q * a * e ≠ 0 := by + by_contra hcon + have hcon' : ∀ a ∈ N, q * a * e = 0 := fun a haN => by + by_contra h; exact hcon ⟨a, haN, h⟩ + set S : Set H := {y | ∃ a ∈ N, ∃ x, (a : H →L[ℂ] H) (e x) = y} with hS + set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM + set P : H →L[ℂ] H := M.starProjection with hP + have hPproj : IsStarProjection P := isStarProjection_starProjection + have hSsub : S ⊆ M := Submodule.subset_span.trans (Submodule.le_topologicalClosure _) + have hSmem : ∀ (a : H →L[ℂ] H), a ∈ N → ∀ x, (a : H →L[ℂ] H) (e x) ∈ M := + fun a haN x => hSsub ⟨a, haN, x, rfl⟩ + have hinv : ∀ (y : H →L[ℂ] H), (∀ s ∈ S, y s ∈ M) → + P.range ∈ Module.End.invtSubmodule (y : Module.End ℂ H) := by + intro y hyS + have hcomapclosed : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by + rw [Submodule.comap_coe] + exact ((Submodule.span ℂ S).isClosed_topologicalClosure).preimage y.continuous + have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by + apply Submodule.topologicalClosure_minimal (Submodule.span ℂ S) _ hcomapclosed + rw [Submodule.span_le] + intro s hs + simp only [Submodule.comap_coe, Set.mem_preimage, SetLike.mem_coe] + exact hyS s hs + rw [hP, Submodule.range_starProjection]; exact hle + have hPcomm : P ∈ N.commutant := by + rw [isStarProjection_mem_commutant_iff hPproj] + intro y hyN + refine hinv y ?_ + rintro s ⟨a, haN, x, rfl⟩ + rw [show y ((a : H →L[ℂ] H) (e x)) = (y * a) (e x) from rfl] + exact hSmem (y * a) (mul_mem hyN haN) x + have hPN : P ∈ N := by + rw [IsStarProjection.mem_iff hPproj N] + intro y hyN' + refine hinv y ?_ + rintro s ⟨a, haN, x, rfl⟩ + have hay : a * y = y * a := mem_commutant_iff.mp hyN' a haN + have hey : e * y = y * e := mem_commutant_iff.mp hyN' e heN + have heq : y ((a : H →L[ℂ] H) (e x)) = (a : H →L[ℂ] H) (e (y x)) := by + rw [show y ((a : H →L[ℂ] H) (e x)) = (y * a) (e x) from rfl, ← hay] + rw [show (a * y) (e x) = (a : H →L[ℂ] H) (y (e x)) from rfl] + rw [show y (e x) = (y * e) x from rfl, ← hey]; rfl + rw [heq]; exact hSmem a haN (y x) + have hPcentral : IsCentralProjection N P := ⟨hPproj, hPN, hPcomm⟩ + have hP1 : P = 1 := by + rcases hN.central_projection_eq hPcentral with h0 | h1 + · exact absurd (by + ext x + have hpx : P (e x) = e x := by + rw [hP, Submodule.starProjection_eq_self_iff]; exact hSmem 1 (one_mem _) x + rw [h0] at hpx; simpa using hpx.symm : e = 0) he0 + · exact h1 + have hMtop : M = ⊤ := by + have hMr : M = P.range := (Submodule.range_starProjection M).symm + rw [hMr, hP1]; exact Submodule.eq_top_iff'.2 fun y => ⟨y, rfl⟩ + have hqM : M ≤ LinearMap.ker (q : H →ₗ[ℂ] H) := by + apply Submodule.topologicalClosure_minimal (Submodule.span ℂ S) _ q.isClosed_ker + rw [Submodule.span_le] + rintro s ⟨a, haN, x, rfl⟩ + simp only [SetLike.mem_coe, LinearMap.mem_ker, ContinuousLinearMap.coe_coe] + rw [show q ((a : H →L[ℂ] H) (e x)) = (q * a * e) x from rfl, hcon' a haN]; rfl + apply hq0 + ext x + have hx : x ∈ LinearMap.ker (q : H →ₗ[ℂ] H) := hqM (hMtop ▸ Submodule.mem_top) + simpa using hx + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean new file mode 100644 index 0000000..d5192ad --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean @@ -0,0 +1,229 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.CentralProjection + +/-! +# Comparison of projections in a von Neumann algebra + +Building on `Factor.lean`, this file develops the basic calculus underlying Murray–von Neumann +comparison theory: the source/range identities of partial isometries, the symmetry of the +subprojection relation, and the subordination relation `MvNSub N p q` ("`p` is equivalent to a +subprojection of `q`"). + +The full comparison theorem (any two projections in a factor are comparable) requires central +supports and polar decomposition; it is developed in subsequent steps. + +## Main definitions + +* `VonNeumannAlgebra.MvNSub N p q` — `p ≼[N] q`: `p` is Murray–von Neumann equivalent to a + subprojection of `q`. + +## Main results + +* `MvNEquiv.isStarProjection_left` / `isStarProjection_right` — the endpoints of an equivalence + are star projections. +* `isStarProjection_subproj_comm` — the subprojection relation `e * f = f` is left/right symmetric + for projections. +* `IsPartialIsometry.range_mul_self` / `mul_source` — the range and source projections act as + one-sided identities. +* `MvNEquiv.exists_subproj_equiv` — an equivalence `q ∼[N] r'` transports a subprojection + `q' ≤ q` to a subprojection of `r'` equivalent to `q'`. +* `MvNSub.refl` / `MvNSub.trans` — subordination is a preorder on projections. +* `mvNSub_of_posCorner` — the scaling step of the comparison theorem: a positive scalar corner + `(q a e)⋆(q a e) = c • e`, `c > 0`, yields `e ≼[N] q`. + +## Notation + +The subordination symbol lives in the opt-in `VonNeumannAlgebra` scope (alongside `∼[N]` from +`Factor.lean`); activate it with `open scoped VonNeumannAlgebra`. + +| Symbol | Expansion | How to activate | +|---|---|---| +| `p ≼[N] q` | `VonNeumannAlgebra.MvNSub N p q` | `open scoped VonNeumannAlgebra` | +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- The source projection of a Murray–von Neumann equivalence is a star projection. -/ +theorem MvNEquiv.isStarProjection_left {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) : IsStarProjection p := by + obtain ⟨v, _, hpi, hvp, _⟩ := h; exact hvp ▸ hpi.isStarProjection_star_mul_self + +/-- The range projection of a Murray–von Neumann equivalence is a star projection. -/ +theorem MvNEquiv.isStarProjection_right {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) : IsStarProjection q := by + obtain ⟨v, _, hpi, _, hvq⟩ := h; exact hvq ▸ hpi.isStarProjection_mul_star_self + +/-- For projections, the subprojection relation `e * f = f` is left/right symmetric. -/ +theorem isStarProjection_subproj_comm {R : Type*} [Ring R] [StarRing R] {e f : R} + (he : IsStarProjection e) (hf : IsStarProjection f) (h : e * f = f) : f * e = f := by + have := congrArg star h + rwa [star_mul, he.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this + +/-- The range projection of a partial isometry acts as a left identity. -/ +theorem IsPartialIsometry.range_mul_self {R : Type*} [Monoid R] [StarMul R] {v : R} + (h : IsPartialIsometry v) : (v * star v) * v = v := h + +/-- The source projection of a partial isometry acts as a right identity. -/ +theorem IsPartialIsometry.mul_source {R : Type*} [Monoid R] [StarMul R] {v : R} + (h : IsPartialIsometry v) : v * (star v * v) = v := by rw [← mul_assoc]; exact h + +/-- `p ≼ q` in `N`: `p` is Murray–von Neumann equivalent to a subprojection of `q`. -/ +def MvNSub (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := + ∃ q' : H →L[ℂ] H, q' ∈ N ∧ q * q' = q' ∧ p ∼[N] q' + +/-- `p ≼[N] q` denotes the subordination relation `MvNSub N p q`: `p` is Murray–von Neumann +equivalent to a subprojection of `q` inside `N`. -/ +scoped notation:50 p:51 " ≼[" N "] " q:51 => MvNSub N p q + +/-- Subordination is reflexive on projections of `N`. -/ +theorem MvNSub.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + (hp : IsStarProjection p) (hpN : p ∈ N) : p ≼[N] p := + ⟨p, hpN, hp.isIdempotentElem, MvNEquiv.refl hp hpN⟩ + +/-- An equivalence `q ∼[N] r'` transports a subprojection `q' ≤ q` to a subprojection of `r'` that +is Murray–von Neumann equivalent to `q'`. -/ +theorem MvNEquiv.exists_subproj_equiv {N : VonNeumannAlgebra H} {q r' q' : H →L[ℂ] H} + (hqr : q ∼[N] r') (hq' : IsStarProjection q') (hq'N : q' ∈ N) (hsub : q * q' = q') : + ∃ r'' : H →L[ℂ] H, IsStarProjection r'' ∧ r'' ∈ N ∧ r' * r'' = r'' ∧ q' ∼[N] r'' := by + obtain ⟨w, hwN, hwpi, hwq, hwr⟩ := hqr + refine ⟨w * q' * star w, ⟨?_, ?_⟩, mul_mem (mul_mem hwN hq'N) (star_mem hwN), ?_, ?_⟩ + · change (w * q' * star w) * (w * q' * star w) = w * q' * star w + simp only [mul_assoc] + rw [← mul_assoc (star w) w (q' * star w), hwq, ← mul_assoc q q' (star w), hsub, + ← mul_assoc q' q' (star w), hq'.isIdempotentElem] + · change star (w * q' * star w) = w * q' * star w + rw [star_mul, star_mul, star_star, hq'.isSelfAdjoint.star_eq, mul_assoc] + · rw [← hwr] + simp only [mul_assoc] + rw [← mul_assoc (star w) w (q' * star w), hwq, ← mul_assoc q q' (star w), hsub] + · refine ⟨w * q', mul_mem hwN hq'N, ?_, ?_, ?_⟩ + · change (w * q') * star (w * q') * (w * q') = w * q' + rw [star_mul, hq'.isSelfAdjoint.star_eq] + simp only [mul_assoc] + rw [← mul_assoc (star w) w q', hwq, hsub, hq'.isIdempotentElem, hq'.isIdempotentElem] + · change star (w * q') * (w * q') = q' + rw [star_mul, hq'.isSelfAdjoint.star_eq, mul_assoc, ← mul_assoc (star w) w q', hwq, hsub, + hq'.isIdempotentElem] + · change (w * q') * star (w * q') = w * q' * star w + rw [star_mul, hq'.isSelfAdjoint.star_eq] + simp only [mul_assoc] + rw [← mul_assoc q' q' (star w), hq'.isIdempotentElem] + +/-- Subordination is transitive: `≼` is a preorder on the projections of `N`. -/ +theorem MvNSub.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} + (hpq : p ≼[N] q) (hqr : q ≼[N] r) : p ≼[N] r := by + obtain ⟨q', hq'N, hqsub, hpq'⟩ := hpq + obtain ⟨r', hr'N, hrsub, hqr'⟩ := hqr + obtain ⟨r'', _, hr''N, hr'sub, hq'r''⟩ := + hqr'.exists_subproj_equiv hpq'.isStarProjection_right hq'N hqsub + refine ⟨r'', hr''N, ?_, hpq'.trans hq'r''⟩ + calc r * r'' = r * (r' * r'') := by rw [hr'sub] + _ = (r * r') * r'' := by rw [mul_assoc] + _ = r' * r'' := by rw [hrsub] + _ = r'' := hr'sub + +/-- **Scaling step of the comparison theorem.** If the positive corner element +`(q a e)⋆ (q a e)` equals a positive scalar multiple `c • e` of `e` (with `c > 0`), then `e` is +subordinate to `q`: the normalised element `(√c)⁻¹ • (q a e)` is a partial isometry with source +`e` and range a subprojection of `q`. The hypotheses isolate the two analytic inputs of the +comparison theorem — the corner being scalar (minimality) and its positivity. -/ +theorem mvNSub_of_posCorner {N : VonNeumannAlgebra H} {e q a : H →L[ℂ] H} + (he : IsStarProjection e) (hq : IsStarProjection q) + (heN : e ∈ N) (hqN : q ∈ N) (haN : a ∈ N) + {c : ℝ} (hc : 0 < c) + (hcorner : star (q * a * e) * (q * a * e) = (c : ℂ) • e) : + e ≼[N] q := by + set γ : ℂ := ((Real.sqrt c)⁻¹ : ℂ) with hγ + set v : H →L[ℂ] H := γ • (q * a * e) with hv + have hvN : v ∈ N := smul_mem γ (mul_mem (mul_mem hqN haN) heN) + have hsrc : star v * v = e := by + rw [hv, star_smul, smul_mul_smul_comm, hcorner, smul_smul] + have hstar : star γ = γ := by rw [hγ, star_inv₀, ← starRingEnd_apply, Complex.conj_ofReal] + rw [hstar, hγ, ← mul_inv, ← Complex.ofReal_mul, Real.mul_self_sqrt hc.le, + inv_mul_cancel₀ (by exact_mod_cast hc.ne'), one_smul] + have hve : v * e = v := by + rw [hv, smul_mul_assoc, mul_assoc (q * a) e e, he.isIdempotentElem] + have hvpi : IsPartialIsometry v := by + unfold IsPartialIsometry + rw [mul_assoc, hsrc, hve] + refine ⟨v * star v, mul_mem hvN (star_mem hvN), ?_, ⟨v, hvN, hvpi, hsrc, rfl⟩⟩ + have hqv : q * v = v := by + rw [hv, mul_smul_comm, ← mul_assoc, ← mul_assoc, hq.isIdempotentElem] + rw [← mul_assoc, hqv] + +/-- **Positivity of the corner scalar.** For a minimal projection `e` and `a ∈ N` with +`q a e ≠ 0`, the corner element `(q a e)⋆ (q a e) = e (a⋆ q a) e` equals a *strictly positive +real* scalar multiple of `e`. (Reality comes from self-adjointness; strict positivity from +evaluating on a nonzero vector of `e H` on which `q a e` does not vanish.) -/ +theorem IsMinimalProjection.posCorner {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) + (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : + ∃ c : ℝ, 0 < c ∧ star (q * a * e) * (q * a * e) = (c : ℂ) • e := by + set x := q * a * e with hx + have hxx : star x * x = e * (star a * q * a) * e := by + rw [hx, star_mul, star_mul, he.1.isSelfAdjoint.star_eq, hq.isSelfAdjoint.star_eq] + rw [mul_assoc, mul_assoc, mul_assoc, ← mul_assoc q q, hq.isIdempotentElem] + simp only [mul_assoc] + obtain ⟨c', hc'⟩ := he.2.2.2 (star a * q * a) (mul_mem (mul_mem (star_mem haN) hqN) haN) + rw [← hxx] at hc' + have hconj : (starRingEnd ℂ) c' = c' := by + have hsa : star (star x * x) = star x * x := by rw [star_mul, star_star] + rw [hc', star_smul, he.1.isSelfAdjoint.star_eq] at hsa + rw [starRingEnd_apply]; exact smul_left_injective ℂ he.2.2.1 hsa + have hxe : x * e = x := by rw [hx, mul_assoc, he.1.isIdempotentElem] + obtain ⟨η, hη⟩ : ∃ η, x η ≠ 0 := by + by_contra h + exact hne (by ext η; exact not_not.mp (not_exists.mp h η)) + set ξ := e η with hξ + have hxξ : x ξ ≠ 0 := by + rw [hξ, ← ContinuousLinearMap.comp_apply, ← ContinuousLinearMap.mul_def, hxe]; exact hη + have heξ : e ξ = ξ := by + rw [hξ, ← ContinuousLinearMap.comp_apply, ← ContinuousLinearMap.mul_def, he.1.isIdempotentElem] + have hξne : ξ ≠ 0 := fun h => hxξ (by rw [h, map_zero]) + have hinner : ‖x ξ‖ ^ 2 = c'.re * ‖ξ‖ ^ 2 := by + have e1 : inner ℂ ((star x * x) ξ) ξ = inner ℂ (x ξ) (x ξ) := by + rw [ContinuousLinearMap.mul_apply, ContinuousLinearMap.star_eq_adjoint, + ContinuousLinearMap.adjoint_inner_left] + have e2 : inner ℂ ((star x * x) ξ) ξ = (starRingEnd ℂ) c' * inner ℂ ξ ξ := by + rw [hc', ContinuousLinearMap.smul_apply, heξ, inner_smul_left] + have e3 : inner ℂ (x ξ) (x ξ) = (starRingEnd ℂ) c' * inner ℂ ξ ξ := e1.symm.trans e2 + have hre := congrArg RCLike.re e3 + rw [inner_self_eq_norm_sq, inner_self_eq_norm_sq_to_K] at hre + simp only [RCLike.mul_re, RCLike.mul_im, RCLike.conj_re, RCLike.conj_im, RCLike.ofReal_re, + RCLike.ofReal_im, pow_two, mul_zero, zero_mul, add_zero, sub_zero] at hre + rw [show RCLike.re c' = c'.re from rfl] at hre + nlinarith [hre] + have hξpos : 0 < ‖ξ‖ ^ 2 := pow_pos (norm_pos_iff.mpr hξne) 2 + have hxξpos : 0 < ‖x ξ‖ ^ 2 := pow_pos (norm_pos_iff.mpr hxξ) 2 + have hcre : c' = (c'.re : ℂ) := (Complex.conj_eq_iff_re.mp hconj).symm + refine ⟨c'.re, by nlinarith [hinner, hξpos, hxξpos], ?_⟩ + rw [hc']; exact congrArg (· • e) hcre + +/-- A minimal projection is subordinate to any projection it "meets": if some `a ∈ N` has +`q a e ≠ 0`, then `e ≼ q`. Combined with central supports (which guarantee `q a e ≠ 0` for every +nonzero `q` in a factor) this yields the comparison theorem `minimal e ≼ q`. -/ +theorem IsMinimalProjection.mvNSub_of_ne {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) + (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : e ≼[N] q := by + obtain ⟨c, hcpos, hcorner⟩ := he.posCorner hq hqN haN hne + exact mvNSub_of_posCorner he.1 hq he.2.1 hqN haN hcpos hcorner + +/-- **Comparison theorem (minimal projection case).** In a factor, a minimal projection `e` is +Murray–von Neumann subordinate to *every* nonzero projection `q`: `e ≼ q`. This combines the +scaling lemma (via `mvNSub_of_ne`) with the central-support input +(`IsFactor.exists_mul_ne`, which supplies an `a ∈ N` with `q a e ≠ 0`). It is the form of +comparison needed to show a maximal orthogonal family of minimal projections exhausts the +identity. -/ +theorem IsMinimalProjection.mvNSub_of_isFactor [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) + {q : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (hq0 : q ≠ 0) : + e ≼[N] q := by + obtain ⟨a, haN, hane⟩ := hN.exists_mul_ne he.2.1 he.2.2.1 hq0 + exact he.mvNSub_of_ne hq hqN haN hane + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean new file mode 100644 index 0000000..a8e830f --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean @@ -0,0 +1,173 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison +public import Mathlib.Analysis.InnerProductSpace.Projection.Basic + +/-! +# Towards the type I factor structure theorem: a covering family of minimal projections + +For a type I factor `N` with minimal projection `e`, this file produces (by Zorn's lemma and the +comparison theorem `IsMinimalProjection.mvNSub_of_isFactor`) a family of mutually orthogonal +projections, each Murray–von Neumann equivalent to `e`, whose ranges span densely — the +projection-theoretic backbone `Σ eᵢ = 1` of the structure theorem `N ≅ B(H₁) ⊗̄ 1`. + +The spatial identification (Hilbert sum and `U • N = B(H₁) ⊗̄ 1`) is a further step. + +The dense span is expressed as +`(Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤`, i.e. the closed linear +span of the union of the ranges is the whole space; this is the operator-friendly form of +`⨆ᵢ ranges = 1` and matches the central-support construction `IsFactor.exists_mul_ne`. + +## Main definitions + +* `VonNeumannAlgebra.OrthEquivFam N e F` — `F` is a set of pairwise-orthogonal nonzero projections + in `N`, each Murray–von Neumann equivalent to `e`. + +## Main results + +* `VonNeumannAlgebra.IsFactor.exists_orthEquivFam_top` — in a factor, there is a maximal such + family whose ranges have dense span. +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- The range projection of a Murray–von Neumann equivalence with nonzero source is nonzero. -/ +theorem MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) (hp : p ≠ 0) : q ≠ 0 := by + obtain ⟨v, _, hvpi, hvp, hvq⟩ := h + intro hq0 + apply hp + have hv0 : v = 0 := by + have hpi : v * star v * v = v := hvpi + rw [hvq, hq0, zero_mul] at hpi + exact hpi.symm + rw [← hvp, hv0]; simp + +/-- A family of pairwise-orthogonal nonzero projections in `N`, each Murray–von Neumann equivalent +to `e`. -/ +def OrthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ℂ] H)) : Prop := + (∀ p ∈ F, IsStarProjection p ∧ p ∈ N ∧ p ≠ 0 ∧ e ∼[N] p) ∧ + F.Pairwise (fun p q => p * q = 0) + +/-- By Zorn's lemma, there is a maximal orthogonal family of `e`-equivalent projections. -/ +theorem exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : + ∃ F, OrthEquivFam N e F ∧ ∀ G, OrthEquivFam N e G → F ⊆ G → G ⊆ F := by + obtain ⟨F, hFmax⟩ := zorn_subset {F | OrthEquivFam N e F} (by + intro c hcsub hchain + refine ⟨⋃₀ c, ⟨?_, ?_⟩, fun s hs => Set.subset_sUnion_of_mem hs⟩ + · rintro p ⟨s, hsc, hps⟩; exact (hcsub hsc).1 p hps + · rintro p ⟨s, hsc, hps⟩ q ⟨t, htc, hqt⟩ hpq + rcases hchain.total hsc htc with h | h + · exact (hcsub htc).2 (h hps) hqt hpq + · exact (hcsub hsc).2 hps (h hqt) hpq) + exact ⟨F, hFmax.1, fun G hG hFG => hFmax.2 hG hFG⟩ + +/-- The orthogonal projection onto the closed span of the ranges of an `OrthEquivFam` lies in `N`, +because that subspace is invariant under the commutant `N'`: for `y ∈ N'` and `f ∈ F ⊆ N`, +`y (f x) = (y f) x = (f y) x = f (y x)` lies in the range of `f`. -/ +theorem OrthEquivFam.starProjection_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) : + (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure.starProjection ∈ N := by + set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS + set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM + set p : H →L[ℂ] H := M.starProjection with hp + have hpproj : IsStarProjection p := isStarProjection_starProjection + rw [IsStarProjection.mem_iff hpproj N] + intro y hyN' + rw [hp, Submodule.range_starProjection] + have hcl : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by + rw [Submodule.comap_coe] + exact ((Submodule.span ℂ S).isClosed_topologicalClosure).preimage y.continuous + have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by + refine Submodule.topologicalClosure_minimal (Submodule.span ℂ S) ?_ hcl + rw [Submodule.span_le] + rintro s ⟨f, hf, x, rfl⟩ + simp only [Submodule.comap_coe, Set.mem_preimage, SetLike.mem_coe, ContinuousLinearMap.coe_coe] + have hfy : f * y = y * f := mem_commutant_iff.mp hyN' f (hF.1 f hf).2.1 + rw [show y (f x) = (y * f) x from rfl, ← hfy] + exact Submodule.le_topologicalClosure _ (Submodule.subset_span ⟨f, hf, y x, rfl⟩) + exact hle + +/-- **Covering family of minimal projections (factor case).** In a factor, there is a family `F` +of pairwise-orthogonal nonzero projections in `N`, each equivalent to the minimal projection `e`, +whose ranges span densely: the closed linear span of the union of their ranges is `⊤`. This is the +`Σ eᵢ = 1` input of the type I structure theorem. + +The proof takes a *maximal* such family `F` (Zorn) and lets `p` be the orthogonal projection onto +the closed span `M` of the ranges; `p ∈ N`. If `M ≠ ⊤` then `r = 1 - p` is a nonzero projection in +`N`, so by the comparison theorem some nonzero `q' ≼ r` is equivalent to `e`; `q'` is orthogonal to +every `f ∈ F`, contradicting maximality. -/ +theorem IsFactor.exists_orthEquivFam_top [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : + ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ + (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ := by + obtain ⟨F, hF, hFmax⟩ := exists_maximal_orthEquivFam N e + refine ⟨F, hF, ?_⟩ + set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS + set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM + set p : H →L[ℂ] H := M.starProjection with hp + have hpproj : IsStarProjection p := isStarProjection_starProjection + have hpN : p ∈ N := hF.starProjection_mem + have hpf : ∀ f ∈ F, p * f = f := by + intro f hf + ext x + simp only [ContinuousLinearMap.mul_apply, hp] + rw [Submodule.starProjection_eq_self_iff] + exact Submodule.le_topologicalClosure _ (Submodule.subset_span ⟨f, hf, x, rfl⟩) + by_contra hMtop + set r : H →L[ℂ] H := 1 - p with hr + have hrproj : IsStarProjection r := by + refine ⟨?_, ?_⟩ + · change (1 - p) * (1 - p) = 1 - p + rw [mul_sub, sub_mul, sub_mul, one_mul, one_mul, mul_one, hpproj.isIdempotentElem, + sub_self, sub_zero] + · change star (1 - p) = 1 - p + rw [star_sub, star_one, hpproj.isSelfAdjoint.star_eq] + have hrN : r ∈ N := by rw [hr]; exact sub_mem (one_mem _) hpN + have hr0 : r ≠ 0 := by + intro h + apply hMtop + have hp1 : p = 1 := by rw [hr, sub_eq_zero] at h; exact h.symm + have hMrange : M = p.range := (Submodule.range_starProjection M).symm + rw [hMrange, hp1] + exact Submodule.eq_top_iff'.2 fun y => ⟨y, rfl⟩ + obtain ⟨q', hq'N, hrq', heq'⟩ := he.mvNSub_of_isFactor hN hrproj hrN hr0 + have hq'proj : IsStarProjection q' := heq'.isStarProjection_right + have hq'0 : q' ≠ 0 := heq'.ne_zero he.2.2.1 + have hpq' : p * q' = 0 := by + have h := hrq' + rw [hr, sub_mul, one_mul, sub_eq_self] at h + exact h + have horth : ∀ f ∈ F, q' * f = 0 ∧ f * q' = 0 := by + intro f hf + have hq'p : q' * p = 0 := by + have h := congrArg star hpq' + rwa [star_mul, hq'proj.isSelfAdjoint.star_eq, hpproj.isSelfAdjoint.star_eq, star_zero] at h + have h1 : q' * f = 0 := by + calc q' * f = q' * (p * f) := by rw [hpf f hf] + _ = (q' * p) * f := by rw [mul_assoc] + _ = 0 := by rw [hq'p, zero_mul] + refine ⟨h1, ?_⟩ + have h := congrArg star h1 + rwa [star_mul, (hF.1 f hf).1.isSelfAdjoint.star_eq, hq'proj.isSelfAdjoint.star_eq, + star_zero] at h + have hq'notF : q' ∉ F := fun hq'F => + hq'0 (by have := (horth q' hq'F).1; rwa [hq'proj.isIdempotentElem] at this) + have hbigger : OrthEquivFam N e (insert q' F) := by + refine ⟨?_, ?_⟩ + · rintro x (rfl | hx) + · exact ⟨hq'proj, hq'N, hq'0, heq'⟩ + · exact hF.1 x hx + · rintro x (rfl | hx) z (rfl | hz) hxz + · exact absurd rfl hxz + · exact (horth z hz).1 + · exact (horth x hx).2 + · exact hF.2 hx hz hxz + have hsub := hFmax (insert q' F) hbigger (Set.subset_insert _ _) + exact hq'notF (hsub (Set.mem_insert _ _)) + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean new file mode 100644 index 0000000..59d85fc --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean @@ -0,0 +1,140 @@ +module + +public import Mathlib.Analysis.VonNeumannAlgebra.Basic +public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry + +/-! +# Factors, minimal projections and Murray–von Neumann equivalence + +This file sets up the basic vocabulary of the comparison theory of projections in a von Neumann +algebra, the foundation of the type classification (and, downstream, of the type I factor +structure theorem). + +## Main definitions + +* `VonNeumannAlgebra.IsFactor N` — `N` has trivial centre: every element of `N ∩ N'` is a scalar. +* `VonNeumannAlgebra.IsMinimalProjection N e` — `e` is a nonzero star projection in `N` with + trivial corner `e N e = ℂ e`. This implies the order-theoretic minimality (no proper nonzero + subprojection in `N`, expressed algebraically as: any projection `f ∈ N` with `e * f = f`, i.e. + the Loewner relation `f ≤ e`, is `0` or `e`), recorded as + `IsMinimalProjection.no_proper_subprojection`. +* `VonNeumannAlgebra.MvNEquiv N p q` — `p` and `q` are Murray–von Neumann equivalent inside `N`: + there is a partial isometry `v ∈ N` with source `v⋆v = p` and range `vv⋆ = q`. Written `p ∼[N] q`. + +## Main results + +* `VonNeumannAlgebra.MvNEquiv.refl` / `symm` / `trans` — Murray–von Neumann equivalence is an + equivalence relation on the projections of `N`. + +## Notation + +The equivalence relation symbol of the operator-algebra literature lives in the opt-in +`VonNeumannAlgebra` scope; activate it with `open scoped VonNeumannAlgebra`. + +| Symbol | Expansion | How to activate | +|---|---|---| +| `p ∼[N] q` | `VonNeumannAlgebra.MvNEquiv N p q` | `open scoped VonNeumannAlgebra` | +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- A von Neumann algebra is closed under scalar multiplication. -/ +theorem smul_mem {N : VonNeumannAlgebra H} (c : ℂ) {x : H →L[ℂ] H} (hx : x ∈ N) : c • x ∈ N := by + rw [Algebra.smul_def] + exact mul_mem (algebraMap_mem N.toStarSubalgebra c) hx + +/-- A von Neumann algebra `N` is a **factor** when its centre is trivial: every operator lying in +both `N` and its commutant is a scalar multiple of the identity. -/ +def IsFactor (N : VonNeumannAlgebra H) : Prop := + ∀ x : H →L[ℂ] H, x ∈ N → x ∈ N.commutant → ∃ c : ℂ, x = c • 1 + +/-- A **minimal projection** of `N`: a nonzero star projection `e ∈ N` whose corner is trivial, +`e N e = ℂ e`. This is the conventional operator-algebraic definition (Takesaki, Kadison–Ringrose); +it implies minimality in the order sense (no proper nonzero subprojection), recorded as +`IsMinimalProjection.no_proper_subprojection`. The corner formulation is the one that +supports comparison theory without invoking Borel functional calculus. -/ +def IsMinimalProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := + IsStarProjection e ∧ e ∈ N ∧ e ≠ 0 ∧ ∀ a ∈ N, ∃ c : ℂ, e * a * e = c • e + +/-- A minimal projection has no proper nonzero subprojection in `N`: if a projection `f ∈ N` +satisfies `f ≤ e` (the Loewner order on projections, equivalently the range inclusion +`ran f ⊆ ran e`, written algebraically as `e * f = f`), then `f = 0` or `f = e`. This recovers the +order-theoretic form of minimality from the corner definition `e N e = ℂ e`. -/ +theorem IsMinimalProjection.no_proper_subprojection {N : VonNeumannAlgebra H} + {e : H →L[ℂ] H} (he : IsMinimalProjection N e) + {f : H →L[ℂ] H} (hf : IsStarProjection f) (hfN : f ∈ N) (hsub : e * f = f) : + f = 0 ∨ f = e := by + have hfe : f * e = f := by + have := congrArg star hsub + rwa [star_mul, he.1.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this + have hefe : e * f * e = f := by rw [hsub, hfe] + obtain ⟨c, hc⟩ := he.2.2.2 f hfN + rw [hefe] at hc + have hidem : f * f = f := hf.isIdempotentElem + rw [hc] at hidem + have h2 : (c • e) * (c • e) = (c * c) • (e : H →L[ℂ] H) := by + rw [smul_mul_smul_comm, he.1.isIdempotentElem] + have hcc : (c * c) • (e : H →L[ℂ] H) = c • e := by rw [← h2, hidem] + have hc2 : c * c = c := smul_left_injective ℂ he.2.2.1 hcc + have h0 : c * (c - 1) = 0 := by rw [mul_sub, mul_one, hc2, sub_self] + rcases mul_eq_zero.mp h0 with h | h + · exact Or.inl (by rw [hc, h, zero_smul]) + · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) + +/-- A **type I factor**: a factor possessing a minimal projection. This is the mathematically +conventional, intrinsic definition; the spatial decomposition `N ≅ B(H₁) ⊗̄ 1` is then a theorem, +not part of the definition. -/ +def IsTypeIFactor (N : VonNeumannAlgebra H) : Prop := + IsFactor N ∧ ∃ e : H →L[ℂ] H, IsMinimalProjection N e + +/-- **Murray–von Neumann equivalence** of projections inside `N`: there is a partial isometry +`v ∈ N` with source projection `v⋆v = p` and range projection `vv⋆ = q`. -/ +def MvNEquiv (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := + ∃ v : H →L[ℂ] H, v ∈ N ∧ IsPartialIsometry v ∧ star v * v = p ∧ v * star v = q + +/-- `p ∼[N] q` denotes Murray–von Neumann equivalence `MvNEquiv N p q` of projections inside `N`. -/ +scoped notation:50 p:51 " ∼[" N "] " q:51 => MvNEquiv N p q + +/-- Murray–von Neumann equivalence is reflexive on projections of `N`. -/ +theorem MvNEquiv.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + (hp : IsStarProjection p) (hpN : p ∈ N) : p ∼[N] p := + ⟨p, hpN, hp.isPartialIsometry, by rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq], + by rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq]⟩ + +/-- Murray–von Neumann equivalence is symmetric. -/ +theorem MvNEquiv.symm {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) : q ∼[N] p := by + obtain ⟨v, hv, hpi, hvp, hvq⟩ := h + exact ⟨star v, star_mem hv, IsPartialIsometry.star hpi, by rw [star_star, hvq], + by rw [star_star, hvp]⟩ + +/-- Murray–von Neumann equivalence is transitive. -/ +theorem MvNEquiv.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} + (hpq : p ∼[N] q) (hqr : q ∼[N] r) : p ∼[N] r := by + obtain ⟨v, hv, hvpi, hvp, hvq⟩ := hpq + obtain ⟨w, hw, hwpi, hwq, hwr⟩ := hqr + have hq : IsStarProjection q := hvq ▸ hvpi.isStarProjection_mul_star_self + refine ⟨w * v, mul_mem hw hv, ?_, ?_, ?_⟩ + · unfold IsPartialIsometry + calc w * v * star (w * v) * (w * v) + = w * (v * star v) * (star w * w) * v := by simp only [star_mul, mul_assoc] + _ = w * q * q * v := by rw [hvq, hwq] + _ = w * q * v := by rw [mul_assoc w q q, hq.isIdempotentElem] + _ = w * (star w * w) * v := by rw [hwq] + _ = w * v := by rw [← mul_assoc w (star w) w, hwpi] + · calc star (w * v) * (w * v) = star v * (star w * w) * v := by simp only [star_mul, mul_assoc] + _ = star v * (v * star v) * v := by rw [hwq, hvq] + _ = (star v * v) * (star v * v) := by simp only [mul_assoc] + _ = star v * v := hvpi.isStarProjection_star_mul_self.isIdempotentElem + _ = p := hvp + · calc (w * v) * star (w * v) = w * (v * star v) * star w := by simp only [star_mul, mul_assoc] + _ = w * (star w * w) * star w := by rw [hvq, ← hwq] + _ = (w * star w) * (w * star w) := by simp only [mul_assoc] + _ = w * star w := hwpi.isStarProjection_mul_star_self.isIdempotentElem + _ = r := hwr + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean new file mode 100644 index 0000000..93b7ffa --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean @@ -0,0 +1,247 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.MatrixUnits +public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition +public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import Mathlib.Algebra.Star.Subalgebra + +/-! +# Matrix units generate the type I factor + +For a type I factor `N ⊆ B(H)` with minimal projection `e` and a covering orthogonal family `F` of +`e`-equivalent projections (`OrthEquivFam`, produced by `IsFactor.exists_orthEquivFam_top`), the +system of matrix units `e_{pq} = v_p v_q⋆` generates `N` as a von Neumann algebra: + +> `VonNeumannAlgebra.generated S = N`, where `S = { e_{pq} | p q : F }`. + +This is the von-Neumann-algebraic (double-commutant) reformulation of the strong-operator +reconstruction `a = Σ_{pq} c_{pq}(a) e_{pq}` of `MatrixUnits.lean`. The reformulation avoids any +strong/weak-operator infinite-sum API (which Mathlib lacks) by working through the commutant: the +inclusion `S'' ⊆ N` is monotonicity, and the content `N ⊆ S''` is the statement that every operator +commuting with all matrix units commutes with all of `N`. + +The proof of that content (`commutes_of_mem_centralizer`) is genuinely analytic: it inserts the +resolution of the identity `Σ_r p_r = 1` (here `p_r = e_{rr} = v_r v_r⋆`) as a `HasSum`, and uses +that each `↑p · a · ↑r` is a *scalar* multiple of the matrix unit `e_{pr}` (multiplicity one, +`exists_matrixEntry`), hence commutes with `b`. The sum over the possibly-infinite index set `F` is +handled throughout by `HasSum`/`HasSum.mapL`/`HasSum.unique`; no operator-level infinite series is +formed. + +## Main results + +* `VonNeumannAlgebra.OrthEquivFam.hasSum_resolutionOfIdentity` — the resolution of the identity + `HasSum (fun i : F => (↑i) y) y`, the analytic core. +* `VonNeumannAlgebra.OrthEquivFam.commutes_of_mem_centralizer` — an operator commuting with every + matrix unit commutes with every element of `N`. +* `VonNeumannAlgebra.OrthEquivFam.generated_matrixUnits_eq` — **the matrix units generate `N`**: + `generated S = N`. +* `VonNeumannAlgebra.OrthEquivFam.mem_sotClosure_adjoin` — the literal SOT-reconstruction corollary: + every `a ∈ N` lies in the SOT-closure of the `*`-subalgebra generated by the matrix units. +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +open StrongOperatorTopology + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] +variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} + +/-- The set of matrix units is contained in `N`. -/ +theorem OrthEquivFam.matrixUnit_subset (hF : OrthEquivFam N e F) : + Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) ⊆ (N : Set (H →L[ℂ] H)) := by + rintro x ⟨pq, rfl⟩ + exact hF.matrixUnit_mem pq.1 pq.2 + +/-- **Resolution of the identity.** For a covering orthogonal family, the projections `↑i` sum to +the identity in the strong operator sense: `HasSum (fun i : F => (↑i) y) y` for every `y`. This is +the analytic heart of the generation theorem; it is extracted from the internal Hilbert-sum +decomposition `H ≅ ℓ²(F; eᵢH)` by recognising the `i`-th Hilbert-sum coordinate of `y` as the +orthogonal projection `(↑i) y`. -/ +theorem OrthEquivFam.hasSum_resolutionOfIdentity (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) (y : H) : + HasSum (fun i : F => (i : H →L[ℂ] H) y) y := by + have hHS := hF.isHilbertSum htop + have hdecomp : HasSum + (fun i : F => (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) i)) y := by + have h := hHS.hasSum_linearIsometryEquiv_symm (hHS.linearIsometryEquiv y) + rwa [LinearIsometryEquiv.symm_apply_apply] at h + have hWmem : ∀ j : F, + (LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) j) + ∈ LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H) := fun j => Submodule.coe_mem _ + have key : ∀ i : F, (i : H →L[ℂ] H) y + = (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i) := by + intro i + have happ := hdecomp.mapL (i : H →L[ℂ] H) + have hii : (i : H →L[ℂ] H) + ((LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i)) + = (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) i) := + (hF.1 i.1 i.2).1.apply_eq_self_of_mem_range (hWmem i) + have hsingle : HasSum + (fun j : F => (i : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j))) + ((i : H →L[ℂ] H) + ((LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) i))) := + hasSum_single i (fun j hj => by + have hjfix : (j : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j)) + = (LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j) := + (hF.1 j.1 j.2).1.apply_eq_self_of_mem_range (hWmem j) + have hij0 : (i : H →L[ℂ] H) * (j : H →L[ℂ] H) = 0 := + hF.2 i.2 j.2 (fun h => hj (Subtype.ext h).symm) + calc (i : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j)) + = (i : H →L[ℂ] H) ((j : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j))) := by rw [hjfix] + _ = ((i : H →L[ℂ] H) * (j : H →L[ℂ] H)) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j)) := rfl + _ = 0 := by rw [hij0]; rfl) + exact (happ.unique hsingle).trans hii + simpa only [key] using hdecomp + +/-- **The content of the generation theorem.** Any operator `b` commuting with every matrix unit +commutes with every `a ∈ N`. Equivalently `Set.centralizer S ⊆ Set.centralizer N`, which is the +nontrivial inclusion `N ⊆ S''`. + +The proof tests `a * b = b * a` against arbitrary inner products. Inserting the resolution of the +identity `Σ_r p_r = 1` between and around `a`, the commutator reduces to the family of operators +`↑p · a · ↑r`, each of which equals a *scalar* multiple of the matrix unit `e_{pr}` +(`exists_matrixEntry`) and therefore commutes with `b`. -/ +theorem OrthEquivFam.commutes_of_mem_centralizer (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + {a : H →L[ℂ] H} (ha : a ∈ N) {b : H →L[ℂ] H} + (hb : b ∈ Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2))) : + a * b = b * a := by + have hbcomm : ∀ p q : F, hF.matrixUnit p q * b = b * hF.matrixUnit p q := + fun p q => (Set.mem_centralizer_iff.mp hb) _ ⟨(p, q), rfl⟩ + -- `↑p · a · ↑r` is a scalar multiple of `e_{pr}`, hence commutes with `b`. + have hcomm_T : ∀ p r : F, ((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) * b + = b * ((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) := by + intro p r + obtain ⟨c, hc⟩ := hF.exists_matrixEntry he p r ha + have hT : (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) = c • hF.matrixUnit p r := by + rw [← hF.pisom_range p, ← hF.pisom_range r] + calc hF.pisom p * star (hF.pisom p) * a * (hF.pisom r * star (hF.pisom r)) + = hF.pisom p * (star (hF.pisom p) * a * hF.pisom r) * star (hF.pisom r) := by + simp only [mul_assoc] + _ = hF.pisom p * (c • e) * star (hF.pisom r) := by rw [hc] + _ = c • (hF.pisom p * e * star (hF.pisom r)) := by rw [mul_smul_comm, smul_mul_assoc] + _ = c • (hF.pisom p * star (hF.pisom r)) := by rw [hF.pisom_mul_source p] + _ = c • hF.matrixUnit p r := rfl + rw [hT, smul_mul_assoc, hbcomm p r, mul_smul_comm] + -- Test `a * b = b * a` against inner products. + apply ContinuousLinearMap.ext + intro y + apply ext_inner_left ℂ + intro x + -- For each `r`, the `r`-summands agree (insert `Σ_p p_p` to the left of `a`). + have step : ∀ r : F, inner ℂ x ((a * (r : H →L[ℂ] H) * b) y) + = inner ℂ x ((b * a * (r : H →L[ℂ] H)) y) := by + intro r + have hLp : HasSum + (fun p : F => inner ℂ x (((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b) y)) + (inner ℂ x ((a * (r : H →L[ℂ] H) * b) y)) := by + have h := (hF.hasSum_resolutionOfIdentity htop ((a * (r : H →L[ℂ] H) * b) y)).mapL (innerSL ℂ x) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + have hRp : HasSum + (fun p : F => inner ℂ x ((b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) y)) + (inner ℂ x ((b * a * (r : H →L[ℂ] H)) y)) := by + have h := (((hF.hasSum_resolutionOfIdentity htop ((a * (r : H →L[ℂ] H)) y)).mapL b).mapL (innerSL ℂ x)) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + have hfun : (fun p : F => inner ℂ x (((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b) y)) + = (fun p : F => inner ℂ x ((b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) y)) := by + funext p + have hkey : (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b + = b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) := by + rw [hcomm_T p r, ← mul_assoc, ← mul_assoc] + rw [hkey] + rw [hfun] at hLp + exact hLp.unique hRp + have hL : HasSum (fun r : F => inner ℂ x ((a * (r : H →L[ℂ] H) * b) y)) + (inner ℂ x ((a * b) y)) := by + have h := ((hF.hasSum_resolutionOfIdentity htop (b y)).mapL a).mapL (innerSL ℂ x) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + have hR : HasSum (fun r : F => inner ℂ x ((b * a * (r : H →L[ℂ] H)) y)) + (inner ℂ x ((b * a) y)) := by + have h := ((hF.hasSum_resolutionOfIdentity htop y).mapL (b * a)).mapL (innerSL ℂ x) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + rw [funext step] at hL + exact hL.unique hR + +/-- The centralizer of the matrix units is contained in the commutant of `N`. -/ +theorem OrthEquivFam.centralizer_subset_commutant (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) + ⊆ Set.centralizer (N : Set (H →L[ℂ] H)) := by + intro b hb + rw [Set.mem_centralizer_iff] + intro a ha + exact hF.commutes_of_mem_centralizer he htop ha hb + +/-- **Matrix units generate the type I factor.** The von Neumann algebra generated by the system of +matrix units `e_{pq} = v_p v_q⋆` is `N`. This is the von-Neumann-algebraic form of the structure +theorem `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ +theorem OrthEquivFam.generated_matrixUnits_eq (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + VonNeumannAlgebra.generated (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) = N := by + set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef + apply le_antisymm + · exact VonNeumannAlgebra.generated_le hF.matrixUnit_subset + · intro a ha + rw [← SetLike.mem_coe] + change a ∈ ((VonNeumannAlgebra.commutantSet S).commutant : Set (H →L[ℂ] H)) + rw [VonNeumannAlgebra.coe_commutant, VonNeumannAlgebra.coe_commutantSet] + have hsub : (S ∪ star S).centralizer ⊆ (N : Set (H →L[ℂ] H)).centralizer := + (Set.centralizer_subset Set.subset_union_left).trans (hF.centralizer_subset_commutant he htop) + have h2 : ((N : Set (H →L[ℂ] H)).centralizer).centralizer + ⊆ ((S ∪ star S).centralizer).centralizer := Set.centralizer_subset hsub + exact h2 (Set.subset_centralizer_centralizer (SetLike.mem_coe.mpr ha)) + +/-- **SOT reconstruction (corollary).** Every `a ∈ N` lies in the strong-operator closure of the +`*`-subalgebra generated by the matrix units. This is the literal `a = Σ_{pq} c_{pq}(a) e_{pq}` +content of the structure theorem, in closure form, obtained from the generation theorem and the SOT +double commutant theorem. -/ +theorem OrthEquivFam.mem_sotClosure_adjoin (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + {a : H →L[ℂ] H} (ha : a ∈ N) : + (⟨a⟩ : ContinuousLinearMapSOT H) ∈ closure (Set.toSOT + (StarAlgebra.adjoin ℂ (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) : + Set (H →L[ℂ] H))) := by + set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef + apply SOTClosedSubalgebra.mem_sotClosure_of_mem_doubleCommutant (StarAlgebra.adjoin ℂ S) a + have hunion : S ∪ star S ⊆ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := by + refine Set.union_subset (StarAlgebra.subset_adjoin ℂ S) ?_ + intro y hy + rw [Set.mem_star] at hy + have hya : star y ∈ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := + StarAlgebra.subset_adjoin ℂ S hy + have := star_mem (s := StarAlgebra.adjoin ℂ S) hya + rwa [star_star] at this + have hgen : (VonNeumannAlgebra.generated S : Set (H →L[ℂ] H)) + = Set.centralizer (Set.centralizer (S ∪ star S)) := by + change ((VonNeumannAlgebra.commutantSet S).commutant : Set (H →L[ℂ] H)) = _ + rw [VonNeumannAlgebra.coe_commutant, VonNeumannAlgebra.coe_commutantSet] + have hmono : Set.centralizer (Set.centralizer (S ∪ star S)) + ⊆ Set.centralizer (Set.centralizer (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H))) := + Set.centralizer_subset (Set.centralizer_subset hunion) + apply hmono + have hmem : a ∈ (VonNeumannAlgebra.generated S : Set (H →L[ℂ] H)) := by + rw [hF.generated_matrixUnits_eq he htop]; exact SetLike.mem_coe.mpr ha + rwa [hgen] at hmem + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean new file mode 100644 index 0000000..fd96b56 --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean @@ -0,0 +1,158 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily + +/-! +# Matrix units of a type I factor and the multiplicity-one property + +For a covering orthogonal family `F` of projections each Murray–von Neumann equivalent to the +minimal projection `e` (produced by `IsFactor.exists_orthEquivFam_top`; the members are minimal as +a consequence, though `OrthEquivFam` only records that each is a nonzero star projection in `N` +equivalent to `e`), this file builds the **system of matrix units** `e_{pq} = v_p v_q⋆` from the +equivalence partial isometries `v_p : e ≅ p`, and proves the +defining matrix-unit relations. It then establishes the **multiplicity-one** property: for every +`a ∈ N`, the matrix entry `v_p⋆ a v_q` is a *scalar* multiple of `e` (a direct consequence of the +corner condition `e N e = ℂ e` defining a minimal projection). + +Together these say that `N` is, algebraically, the `*`-algebra of `F × F` matrices over `ℂ` — the +algebraic heart of the structure theorem `N ≅ B(ℓ²(F)) ⊗̄ 1`. The remaining (analytic) step is the +strong-operator convergence of `a = Σ_{pq} c_{pq}(a) e_{pq}` and the identification with +`vnTensorLeft`. + +## Main definitions + +* `VonNeumannAlgebra.OrthEquivFam.pisom` — a choice of equivalence partial isometry `v_p : e ≅ p`. +* `VonNeumannAlgebra.OrthEquivFam.matrixUnit` — the matrix unit `e_{pq} = v_p v_q⋆`. + +## Main results + +* `matrixUnit_mul_of_eq` / `matrixUnit_mul_of_ne` — the matrix-unit multiplication law + `e_{pq} e_{rs} = δ_{qr} e_{ps}`. +* `OrthEquivFam.exists_matrixEntry` — multiplicity one: `∃ c, v_p⋆ a v_q = c • e` for `a ∈ N`. +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] +variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} + +/-- A choice of partial isometry `v_p` implementing the Murray–von Neumann equivalence `e ∼[N] p`, +oriented with source projection `v_p⋆ v_p = e` (`pisom_source`) and range projection +`v_p v_p⋆ = p` (`pisom_range`). -/ +noncomputable def OrthEquivFam.pisom (hF : OrthEquivFam N e F) (p : F) : H →L[ℂ] H := + (hF.1 p.1 p.2).2.2.2.choose + +theorem OrthEquivFam.pisom_mem (hF : OrthEquivFam N e F) (p : F) : hF.pisom p ∈ N := + (hF.1 p.1 p.2).2.2.2.choose_spec.1 + +theorem OrthEquivFam.pisom_isPI (hF : OrthEquivFam N e F) (p : F) : + IsPartialIsometry (hF.pisom p) := + (hF.1 p.1 p.2).2.2.2.choose_spec.2.1 + +theorem OrthEquivFam.pisom_source (hF : OrthEquivFam N e F) (p : F) : + star (hF.pisom p) * hF.pisom p = e := + (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.1 + +theorem OrthEquivFam.pisom_range (hF : OrthEquivFam N e F) (p : F) : + hF.pisom p * star (hF.pisom p) = (p : H →L[ℂ] H) := + (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.2 + +/-- `v_p e = v_p`: the source projection acts as a right unit on `v_p`. -/ +theorem OrthEquivFam.pisom_mul_source (hF : OrthEquivFam N e F) (p : F) : + hF.pisom p * e = hF.pisom p := by + have h : hF.pisom p * (star (hF.pisom p) * hF.pisom p) = hF.pisom p := by + rw [← mul_assoc]; exact hF.pisom_isPI p + rwa [hF.pisom_source p] at h + +/-- `e v_p⋆ = v_p⋆`: the source projection acts as a left unit on `v_p⋆`. -/ +theorem OrthEquivFam.e_mul_star_pisom (hF : OrthEquivFam N e F) (p : F) : + e * star (hF.pisom p) = star (hF.pisom p) := by + have h : star (hF.pisom p) * hF.pisom p * star (hF.pisom p) = star (hF.pisom p) := by + have h' : star (hF.pisom p) * star (star (hF.pisom p)) * star (hF.pisom p) + = star (hF.pisom p) := IsPartialIsometry.star (hF.pisom_isPI p) + rwa [star_star] at h' + rwa [hF.pisom_source p] at h + +/-- For distinct family members the partial isometries are orthogonal: `v_q⋆ v_r = 0`. -/ +theorem OrthEquivFam.star_pisom_mul_pisom_of_ne (hF : OrthEquivFam N e F) {q r : F} + (hqr : q ≠ r) : star (hF.pisom q) * hF.pisom r = 0 := by + have hq : (q : H →L[ℂ] H) * hF.pisom q = hF.pisom q := by + have h : hF.pisom q * star (hF.pisom q) * hF.pisom q = hF.pisom q := hF.pisom_isPI q + rwa [hF.pisom_range q] at h + have hr : (r : H →L[ℂ] H) * hF.pisom r = hF.pisom r := by + have h : hF.pisom r * star (hF.pisom r) * hF.pisom r = hF.pisom r := hF.pisom_isPI r + rwa [hF.pisom_range r] at h + have hsq : star (hF.pisom q) * (q : H →L[ℂ] H) = star (hF.pisom q) := by + have := congrArg star hq + rwa [star_mul, (hF.1 q.1 q.2).1.isSelfAdjoint.star_eq] at this + have h0 : (q : H →L[ℂ] H) * r = 0 := hF.2 q.2 r.2 (fun h => hqr (Subtype.ext h)) + calc star (hF.pisom q) * hF.pisom r + = (star (hF.pisom q) * (q : H →L[ℂ] H)) * ((r : H →L[ℂ] H) * hF.pisom r) := by + rw [hsq, hr] + _ = star (hF.pisom q) * ((q : H →L[ℂ] H) * r) * hF.pisom r := by simp only [mul_assoc] + _ = 0 := by rw [h0, mul_zero, zero_mul] + +/-- The **matrix unit** `e_{pq} = v_p v_q⋆`. -/ +noncomputable def OrthEquivFam.matrixUnit (hF : OrthEquivFam N e F) (p q : F) : H →L[ℂ] H := + hF.pisom p * star (hF.pisom q) + +/-- Definitional unfolding of the matrix unit: `e_{pq} = v_p v_q⋆`. -/ +theorem OrthEquivFam.matrixUnit_def (hF : OrthEquivFam N e F) (p q : F) : + hF.matrixUnit p q = hF.pisom p * star (hF.pisom q) := rfl + +/-- Matrix units lie in `N`. -/ +theorem OrthEquivFam.matrixUnit_mem (hF : OrthEquivFam N e F) (p q : F) : + hF.matrixUnit p q ∈ N := + mul_mem (hF.pisom_mem p) (star_mem (hF.pisom_mem q)) + +/-- The diagonal matrix unit is the projection: `e_{pp} = p`. -/ +theorem OrthEquivFam.matrixUnit_self (hF : OrthEquivFam N e F) (p : F) : + hF.matrixUnit p p = (p : H →L[ℂ] H) := hF.pisom_range p + +/-- Matrix units are adjoint-symmetric: `e_{pq}⋆ = e_{qp}`. -/ +theorem OrthEquivFam.star_matrixUnit (hF : OrthEquivFam N e F) (p q : F) : + star (hF.matrixUnit p q) = hF.matrixUnit q p := by + rw [matrixUnit_def, matrixUnit_def, star_mul, star_star] + +/-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, diagonal case `q = r`: +`e_{pq} e_{qs} = e_{ps}`. -/ +theorem OrthEquivFam.matrixUnit_mul_of_eq (hF : OrthEquivFam N e F) (p q s : F) : + hF.matrixUnit p q * hF.matrixUnit q s = hF.matrixUnit p s := by + rw [matrixUnit_def, matrixUnit_def, matrixUnit_def] + calc hF.pisom p * star (hF.pisom q) * (hF.pisom q * star (hF.pisom s)) + = hF.pisom p * (star (hF.pisom q) * hF.pisom q) * star (hF.pisom s) := by + simp only [mul_assoc] + _ = hF.pisom p * e * star (hF.pisom s) := by rw [hF.pisom_source q] + _ = hF.pisom p * star (hF.pisom s) := by rw [hF.pisom_mul_source p] + +/-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, off-diagonal case `q ≠ r`: +`e_{pq} e_{rs} = 0`. -/ +theorem OrthEquivFam.matrixUnit_mul_of_ne (hF : OrthEquivFam N e F) (p s : F) {q r : F} + (hqr : q ≠ r) : hF.matrixUnit p q * hF.matrixUnit r s = 0 := by + rw [matrixUnit_def, matrixUnit_def] + calc hF.pisom p * star (hF.pisom q) * (hF.pisom r * star (hF.pisom s)) + = hF.pisom p * (star (hF.pisom q) * hF.pisom r) * star (hF.pisom s) := by + simp only [mul_assoc] + _ = 0 := by rw [hF.star_pisom_mul_pisom_of_ne hqr, mul_zero, zero_mul] + +/-- **Multiplicity one.** For a minimal projection `e` and any `a ∈ N`, the matrix entry +`v_p⋆ a v_q` is a scalar multiple of `e`. This is the corner condition `e N e = ℂ e` transported +along the equivalences, and is the algebraic content of `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ +theorem OrthEquivFam.exists_matrixEntry (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) (p q : F) {a : H →L[ℂ] H} (ha : a ∈ N) : + ∃ c : ℂ, star (hF.pisom p) * a * hF.pisom q = c • e := by + have hbN : star (hF.pisom p) * a * hF.pisom q ∈ N := + mul_mem (mul_mem (star_mem (hF.pisom_mem p)) ha) (hF.pisom_mem q) + obtain ⟨c, hc⟩ := he.2.2.2 _ hbN + refine ⟨c, ?_⟩ + have key : e * (star (hF.pisom p) * a * hF.pisom q) * e + = star (hF.pisom p) * a * hF.pisom q := by + calc e * (star (hF.pisom p) * a * hF.pisom q) * e + = (e * star (hF.pisom p)) * a * (hF.pisom q * e) := by simp only [mul_assoc] + _ = star (hF.pisom p) * a * hF.pisom q := by + rw [hF.e_mul_star_pisom p, hF.pisom_mul_source q] + rw [← key, hc] + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean new file mode 100644 index 0000000..d4d6b94 --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean @@ -0,0 +1,317 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion +public import Mathlib.Analysis.InnerProductSpace.Adjoint +public import Mathlib.Analysis.InnerProductSpace.l2Space + +/-! +# Spatial decomposition: partial-isometry-induced isometries between projection ranges + +This file begins the spatial half of the type I factor structure theorem. A partial isometry `v` +with source projection `p = v⋆v` and range projection `q = vv⋆` restricts to a linear isometric +equivalence between the closed subspaces `range p` and `range q`. For a family of projections +each Murray–von Neumann equivalent to a fixed minimal projection `e`, these isometries identify +every summand `range eᵢ` with the multiplicity space `range e`, the first step in building the +spatial isomorphism `H ≅ ℓ²(I) ⊗̂ (eH)`. + +## Main results + +* `IsPartialIsometry.sourceRangeEquiv` — the isometric equivalence `range (v⋆v) ≃ₗᵢ range (vv⋆)` + induced by a partial isometry `v`. +* `IsFactor.exists_tensor_decomposition` — the `ℓ²`-sum form `H ≅ ℓ²(F; eH)` of the spatial + decomposition of a type I factor. +* `IsFactor.exists_tmul_decomposition` — the literal tensor form `H ≅ ℓ²(F) ⊗̂ (eH)`, obtained by + composing with the tensor bridge `HilbertTensor.lpTensorEquiv`. +-/ + +@[expose] public section + +open scoped ENNReal + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +section LpCongr + +variable {α : Type*} {𝕜 : Type*} [RCLike 𝕜] {G G' : α → Type*} + [∀ i, NormedAddCommGroup (G i)] [∀ i, NormedSpace 𝕜 (G i)] + [∀ i, NormedAddCommGroup (G' i)] [∀ i, NormedSpace 𝕜 (G' i)] + +/-- A family of isometries preserves `Memℓp`: norms are pointwise unchanged. -/ +theorem memℓp_congr_linearIsometryEquiv (e : ∀ i, G i ≃ₗᵢ[𝕜] G' i) {f : ∀ i, G i} + (hf : Memℓp f 2) : Memℓp (fun i => e i (f i)) 2 := by + apply Memℓp.of_norm + have hnorm : (fun i => ‖e i (f i)‖) = fun i => ‖f i‖ := funext fun i => (e i).norm_map (f i) + rw [hnorm] + exact hf.norm + +/-- A family of linear isometric equivalences `G i ≃ₗᵢ G' i` induces a linear isometric +equivalence between the `ℓ²` sums `lp G 2 ≃ₗᵢ lp G' 2`, applied componentwise. -/ +noncomputable def lpCongr (e : ∀ i, G i ≃ₗᵢ[𝕜] G' i) : lp G 2 ≃ₗᵢ[𝕜] lp G' 2 where + toFun f := ⟨fun i => e i (f i), memℓp_congr_linearIsometryEquiv e (lp.memℓp f)⟩ + invFun g := ⟨fun i => (e i).symm (g i), memℓp_congr_linearIsometryEquiv (fun i => (e i).symm) + (lp.memℓp g)⟩ + left_inv f := by + refine Subtype.ext (funext fun i => ?_) + change (e i).symm (e i (f i)) = f i + rw [LinearIsometryEquiv.symm_apply_apply] + right_inv g := by + refine Subtype.ext (funext fun i => ?_) + change e i ((e i).symm (g i)) = g i + rw [LinearIsometryEquiv.apply_symm_apply] + map_add' x y := by + refine Subtype.ext (funext fun i => ?_) + change e i ((x + y) i) = e i (x i) + e i (y i) + rw [lp.coeFn_add, Pi.add_apply, map_add] + map_smul' c f := by + refine Subtype.ext (funext fun i => ?_) + change e i ((c • f) i) = c • e i (f i) + rw [lp.coeFn_smul, Pi.smul_apply, map_smul] + norm_map' f := by + have hp : (0 : ℝ) < (2 : ℝ≥0∞).toReal := by norm_num + rw [lp.norm_eq_tsum_rpow hp, lp.norm_eq_tsum_rpow hp] + congr 1 + refine tsum_congr fun i => ?_ + congr 1 + exact (e i).norm_map (f i) + +end LpCongr + +namespace IsPartialIsometry + +/-- For `x` in the source subspace (`p x = x` where `p = v⋆v`), the map preserves the norm: +`‖v x‖ = ‖x‖`. -/ +theorem norm_apply {v : H →L[ℂ] H} {p : H →L[ℂ] H} + (hsource : star v * v = p) {x : H} (hx : (p : H →L[ℂ] H) x = x) : ‖v x‖ = ‖x‖ := by + have hinner : (inner ℂ (v x) (v x) : ℂ) = inner ℂ x x := by + rw [← ContinuousLinearMap.adjoint_inner_right, ← ContinuousLinearMap.star_eq_adjoint, + ← ContinuousLinearMap.mul_apply, hsource, hx] + have h2 : ‖v x‖ ^ 2 = ‖x‖ ^ 2 := by + rw [← inner_self_eq_norm_sq (𝕜 := ℂ), ← inner_self_eq_norm_sq (𝕜 := ℂ)] + exact congrArg RCLike.re hinner + have h3 := congrArg Real.sqrt h2 + rwa [Real.sqrt_sq (norm_nonneg _), Real.sqrt_sq (norm_nonneg _)] at h3 + +/-- The image of any vector under a partial isometry lands in the range subspace: if `q = v v⋆` +then `q (v x) = v x`. -/ +theorem apply_mem_range {v : H →L[ℂ] H} (hv : IsPartialIsometry v) {q : H →L[ℂ] H} + (hrange : v * star v = q) (x : H) : (q : H →L[ℂ] H) (v x) = v x := by + rw [← ContinuousLinearMap.mul_apply, ← hrange, hv] + +/-- A partial isometry `v` with source projection `star v * v = p` and range projection +`v * star v = q` restricts to a linear isometric equivalence from the source subspace +`range p` onto the range subspace `range q`. -/ +noncomputable def sourceRangeEquiv {v : H →L[ℂ] H} (hv : IsPartialIsometry v) + {p q : H →L[ℂ] H} (hsource : star v * v = p) (hrange : v * star v = q) : + LinearMap.range (p : H →ₗ[ℂ] H) ≃ₗᵢ[ℂ] LinearMap.range (q : H →ₗ[ℂ] H) := by + have hpidem : (p : H →L[ℂ] H) * p = p := by + have := hv.isStarProjection_star_mul_self.isIdempotentElem + rwa [hsource] at this + have hqidem : (q : H →L[ℂ] H) * q = q := by + have := hv.isStarProjection_mul_star_self.isIdempotentElem + rwa [hrange] at this + have hsvpi : star v * v * star v = star v := by + have h : star v * star (star v) * star v = star v := IsPartialIsometry.star hv + rwa [star_star] at h + have hfix : ∀ {x : H}, x ∈ LinearMap.range (p : H →ₗ[ℂ] H) → (p : H →L[ℂ] H) x = x := by + rintro x ⟨z, rfl⟩ + rw [ContinuousLinearMap.coe_coe, ← ContinuousLinearMap.mul_apply, hpidem] + refine LinearIsometryEquiv.ofSurjective + { toFun := fun ξ => ⟨v ξ.1, ⟨v ξ.1, by + rw [ContinuousLinearMap.coe_coe]; exact hv.apply_mem_range hrange ξ.1⟩⟩ + map_add' := fun a b => by apply Subtype.ext; simp + map_smul' := fun c a => by apply Subtype.ext; simp + norm_map' := fun ξ => norm_apply hsource (hfix ξ.2) } ?_ + rintro ⟨η, hη⟩ + have hqfix : (q : H →L[ℂ] H) η = η := by + obtain ⟨z, hz⟩ := hη + rw [← hz, ContinuousLinearMap.coe_coe, ← ContinuousLinearMap.mul_apply, hqidem] + have hmem : star v η ∈ LinearMap.range (p : H →ₗ[ℂ] H) := by + refine ⟨star v η, ?_⟩ + rw [ContinuousLinearMap.coe_coe, show (p : H →L[ℂ] H) (star v η) = (p * star v) η from rfl, + ← hsource, hsvpi] + refine ⟨⟨star v η, hmem⟩, Subtype.ext ?_⟩ + change v (star v η) = η + rw [← ContinuousLinearMap.mul_apply, hrange, hqfix] + +end IsPartialIsometry + +/-- A vector in the range of a star projection is fixed by it: `p x = x`. -/ +theorem IsStarProjection.apply_eq_self_of_mem_range {p : H →L[ℂ] H} (hp : IsStarProjection p) + {x : H} (hx : x ∈ LinearMap.range (p : H →ₗ[ℂ] H)) : (p : H →L[ℂ] H) x = x := by + obtain ⟨z, rfl⟩ := hx + rw [ContinuousLinearMap.coe_coe, ← ContinuousLinearMap.mul_apply, hp.isIdempotentElem] + +/-- The range of a star projection is closed: it equals the kernel of `1 - p`. -/ +theorem IsStarProjection.isClosed_range {p : H →L[ℂ] H} (hp : IsStarProjection p) : + IsClosed (LinearMap.range (p : H →ₗ[ℂ] H) : Set H) := by + have hker : LinearMap.range (p : H →ₗ[ℂ] H) + = LinearMap.ker ((1 - p : H →L[ℂ] H) : H →ₗ[ℂ] H) := by + ext x + simp only [LinearMap.mem_range, LinearMap.mem_ker, ContinuousLinearMap.coe_coe, + ContinuousLinearMap.sub_apply, ContinuousLinearMap.one_apply, sub_eq_zero] + constructor + · rintro ⟨z, rfl⟩ + rw [← ContinuousLinearMap.mul_apply, hp.isIdempotentElem] + · intro hx + exact ⟨x, hx.symm⟩ + rw [hker] + exact (1 - p).isClosed_ker + +/-- The range of a star projection, as a closed subspace, is complete. -/ +theorem IsStarProjection.completeSpace_range {p : H →L[ℂ] H} (hp : IsStarProjection p) : + CompleteSpace (LinearMap.range (p : H →ₗ[ℂ] H)) := + completeSpace_coe_iff_isComplete.mpr hp.isClosed_range.isComplete + +/-- The inverse of the partial-isometry-induced equivalence acts as `v⋆`: for `η` in the range +subspace, `(sourceRangeEquiv v).symm η = v⋆ η`. -/ +theorem IsPartialIsometry.coe_sourceRangeEquiv_symm {v : H →L[ℂ] H} (hv : IsPartialIsometry v) + {p q : H →L[ℂ] H} (hsource : star v * v = p) (hrange : v * star v = q) + (η : LinearMap.range (q : H →ₗ[ℂ] H)) : + ((hv.sourceRangeEquiv hsource hrange).symm η : H) = star v (η : H) := by + have hsvpi : star v * v * star v = star v := by + have h : star v * star (star v) * star v = star v := IsPartialIsometry.star hv + rwa [star_star] at h + have hq : IsStarProjection q := by rw [← hrange]; exact hv.isStarProjection_mul_star_self + have hqfix : (q : H →L[ℂ] H) (η : H) = (η : H) := hq.apply_eq_self_of_mem_range η.2 + have hmem : star v (η : H) ∈ LinearMap.range (p : H →ₗ[ℂ] H) := + ⟨star v (η : H), by + rw [ContinuousLinearMap.coe_coe, ← hsource, ← ContinuousLinearMap.mul_apply, hsvpi]⟩ + have hG : (hv.sourceRangeEquiv hsource hrange) ⟨star v (η : H), hmem⟩ = η := by + apply Subtype.ext + change v (star v (η : H)) = (η : H) + rw [← ContinuousLinearMap.mul_apply, hrange, hqfix] + have hsymm : (hv.sourceRangeEquiv hsource hrange).symm η = ⟨star v (η : H), hmem⟩ := + (hv.sourceRangeEquiv hsource hrange).injective (by + rw [LinearIsometryEquiv.apply_symm_apply]; exact hG.symm) + rw [hsymm] + +namespace VonNeumannAlgebra + +/-- A covering orthogonal family of star projections (each in `OrthEquivFam`) realises `H` as the +internal Hilbert sum of the ranges. -/ +theorem OrthEquivFam.isHilbertSum {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + IsHilbertSum ℂ (fun i : F => LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) + (fun i => (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ) := by + haveI : ∀ i : F, CompleteSpace (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) := + fun i => (hF.1 i.1 i.2).1.completeSpace_range + refine IsHilbertSum.mkInternal _ ?_ ?_ + · rintro ⟨pi, hpi⟩ ⟨pj, hpj⟩ hij ⟨v, hv⟩ ⟨w, hw⟩ + have hne : pi ≠ pj := fun h => hij (Subtype.ext h) + have h0 : (pi : H →L[ℂ] H) * pj = 0 := hF.2 hpi hpj hne + have hvf : (pi : H →L[ℂ] H) v = v := (hF.1 pi hpi).1.apply_eq_self_of_mem_range hv + have hwf : (pj : H →L[ℂ] H) w = w := (hF.1 pj hpj).1.apply_eq_self_of_mem_range hw + have e1 : (inner ℂ v w : ℂ) = inner ℂ ((pi : H →L[ℂ] H) v) ((pj : H →L[ℂ] H) w) := by + rw [hvf, hwf] + change (inner ℂ v w : ℂ) = 0 + rw [e1, ← ContinuousLinearMap.adjoint_inner_right, ← ContinuousLinearMap.star_eq_adjoint, + (hF.1 pi hpi).1.isSelfAdjoint.star_eq, + show (pi : H →L[ℂ] H) ((pj : H →L[ℂ] H) w) = ((pi : H →L[ℂ] H) * pj) w from rfl, h0] + simp + · rw [← htop] + refine Submodule.topologicalClosure_mono (Submodule.span_le.mpr ?_) + rintro y ⟨f, hf, x, rfl⟩ + exact Submodule.mem_iSup_of_mem ⟨f, hf⟩ ⟨x, rfl⟩ + +/-- **Spatial Hilbert-sum isomorphism.** A covering orthogonal family of `e`-equivalent +projections gives a linear isometric equivalence of `H` with the `ℓ²` sum of the ranges. -/ +noncomputable def OrthEquivFam.hilbertSumEquiv {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + H ≃ₗᵢ[ℂ] lp (fun i : F => LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) 2 := + (hF.isHilbertSum htop).linearIsometryEquiv + +/-- **Tensor-product decomposition of the Hilbert space.** A covering orthogonal family of +projections each Murray–von Neumann equivalent to `e` identifies `H` isometrically with +`ℓ²(F; eH)` — the `ℓ²` sum, indexed by `F`, of copies of the fibre `range e` (which is the +*multiplicity space* when `e` is minimal, as in `exists_tensor_decomposition`; minimality is not +assumed in this lemma). This is the spatial content of the type I factor structure theorem: +`H ≅ ℓ²(F) ⊗̂ (eH)`. The equivalence +is built from the Hilbert-sum decomposition `H ≅ ⊕ᵢ range eᵢ` and the partial-isometry-induced +isometries `range eᵢ ≅ range e`. -/ +noncomputable def OrthEquivFam.multiplicityEquiv {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + H ≃ₗᵢ[ℂ] lp (fun _ : F => LinearMap.range (e : H →ₗ[ℂ] H)) 2 := + (hF.hilbertSumEquiv htop).trans (lpCongr (fun i => + (IsPartialIsometry.sourceRangeEquiv + (hF.1 i.1 i.2).2.2.2.choose_spec.2.1 + (hF.1 i.1 i.2).2.2.2.choose_spec.2.2.1 + (hF.1 i.1 i.2).2.2.2.choose_spec.2.2.2).symm)) + +/-- The `i`-th Hilbert-sum coordinate of `y`, embedded back into `H`, is the orthogonal projection +`(↑i) y`. This identifies the abstract Hilbert-sum decomposition with the explicit family of range +projections. -/ +theorem OrthEquivFam.coe_hilbertSumEquiv_apply {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + (y : H) (i : F) : + ((hF.hilbertSumEquiv htop y i : LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) : H) + = (i : H →L[ℂ] H) y := by + have hHS := hF.isHilbertSum htop + have hdecomp : HasSum + (fun j : F => (LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j)) y := by + have h := hHS.hasSum_linearIsometryEquiv_symm (hHS.linearIsometryEquiv y) + rwa [LinearIsometryEquiv.symm_apply_apply] at h + have happ := hdecomp.mapL (i : H →L[ℂ] H) + have hii : (i : H →L[ℂ] H) + ((LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i)) + = (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i) := + (hF.1 i.1 i.2).1.apply_eq_self_of_mem_range (Submodule.coe_mem _) + have hsingle : HasSum + (fun j : F => (i : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) j))) + ((i : H →L[ℂ] H) + ((LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i))) := + hasSum_single i (fun j hj => by + have hjfix : (j : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) j)) + = (LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j) := + (hF.1 j.1 j.2).1.apply_eq_self_of_mem_range (Submodule.coe_mem _) + have hij0 : (i : H →L[ℂ] H) * (j : H →L[ℂ] H) = 0 := + hF.2 i.2 j.2 (fun h => hj (Subtype.ext h).symm) + calc (i : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) j)) + = (i : H →L[ℂ] H) ((j : H →L[ℂ] H) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j))) := by rw [hjfix] + _ = ((i : H →L[ℂ] H) * (j : H →L[ℂ] H)) + ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ + ((hHS.linearIsometryEquiv y) j)) := rfl + _ = 0 := by rw [hij0]; rfl) + exact ((happ.unique hsingle).trans hii).symm + +/-- The minimal projection `e` of a type I factor is the multiplicity space: a type I factor with +minimal projection `e` acts on a Hilbert space isometric to the `ℓ²` sum `ℓ²(F; eH)` of copies of +`eH = range e`, indexed by a maximal orthogonal family `F` of minimal projections equivalent to +`e`. Composing with the tensor bridge turns this `ℓ²` sum into the literal tensor product +`H ≅ ℓ²(F) ⊗̂ eH`; see `exists_tmul_decomposition`. -/ +theorem IsFactor.exists_tensor_decomposition [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : + ∃ (F : Set (H →L[ℂ] H)), + Nonempty (H ≃ₗᵢ[ℂ] lp (fun _ : F => LinearMap.range (e : H →ₗ[ℂ] H)) 2) := by + obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he + exact ⟨F, ⟨hF.multiplicityEquiv htop⟩⟩ + +/-- **Tensor-product decomposition (literal form).** A type I factor `N ⊆ B(H)` with minimal +projection `e` acts on a Hilbert space isometric to the completed Hilbert tensor product +`ℓ²(F) ⊗̂ (eH)`, where `F` is a maximal orthogonal family of minimal projections equivalent to `e` +and `eH = range e` is the multiplicity space. This is the literal `H ≅ ℓ²(F) ⊗̂ eH` form of the +type I structure theorem, obtained from `exists_tensor_decomposition` by composing with the tensor +bridge `HilbertTensor.lpTensorEquiv`. -/ +theorem IsFactor.exists_tmul_decomposition [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : + ∃ (F : Set (H →L[ℂ] H)), + Nonempty (H ≃ₗᵢ[ℂ] + HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))) := by + obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he + haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range + haveI : DecidableEq (↥F) := Classical.decEq _ + exact ⟨F, ⟨(hF.multiplicityEquiv htop).trans + (HilbertTensor.lpTensorEquiv (ι := F) (K := LinearMap.range (e : H →ₗ[ℂ] H)))⟩⟩ + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean new file mode 100644 index 0000000..59f9eb4 --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean @@ -0,0 +1,388 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.GeneratedByMatrixUnits +public import QuantumSystem.Algebra.Star.TensorProduct + +/-! +# Spatial identification of a type I factor with `B(H₁) ⊗̄ 1` + +This file completes the spatial structure theorem for a type I factor `N ⊆ B(H)` with minimal +projection `e`: there is a linear isometric equivalence `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` under which `N` +becomes exactly the tensor factor `B(ℓ²(F)) ⊗̄ 1` and `N'` becomes the right factor `1 ⊗̄ B(eH)`. + +The identification glues the generation theorem `N = ⟨matrix units⟩''` (`GeneratedByMatrixUnits`) +to the tensor commutation theorem (`Algebra.Star.TensorProduct`) through the spatial isomorphism +`U = multiplicityEquiv ∘ lpTensorEquiv`. The key computation is that `U` carries the matrix unit +`e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨δ_q| ⊗̂ 1`, where `δ_p = lp.single 2 p 1` is the +`p`-th standard basis vector of `ℓ²(F)`. + +## Main results + +* `VonNeumannAlgebra.OrthEquivFam.coe_multiplicityEquiv_apply` — the explicit `i`-th coordinate of + `U y`: `(multiplicityEquiv y) i = v_i⋆ y`. +* `VonNeumannAlgebra.OrthEquivFam.hasSum_tmul_spatialEquiv` — the resulting expansion + `U y = ∑ᵢ δᵢ ⊗̂ (v_i⋆ y)`. +* `VonNeumannAlgebra.OrthEquivFam.conjStarAlgEquiv_matrixUnit` — `U e_{pq} U⋆ = |δ_p⟩⟨δ_q| ⊗̂ 1`. +* `VonNeumannAlgebra.OrthEquivFam.conj_spatialEquiv_eq_vnTensorLeft` — the identification + `U N U⋆ = B(ℓ²(F)) ⊗̄ 1`, with commutant companion `conj_spatialEquiv_commutant_eq_vnTensorRight`. +* `VonNeumannAlgebra.IsFactor.exists_spatial_tensorDecomposition` — the existence headline. +* `VonNeumannAlgebra.IsFactor.exists_split_tensorDecomposition` — the split tensor decomposition: + for an intermediate type I factor `A₁ ≤ N ≤ A₂'`, the same `U` sends `A₁` into `B(ℓ²(F)) ⊗̄ 1` + and `A₂` into `1 ⊗̄ B(eH)`. +-/ + +@[expose] public section + +open scoped TensorProduct + +namespace VonNeumannAlgebra + +open HilbertTensor + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] +variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} + +/-- The `i`-th standard basis vector `δ_i = lp.single 2 i 1` of `ℓ²(F) = lp (fun _ : F => ℂ) 2`. +This is a thin wrapper whose only purpose is to pin the index family `fun _ : F => ℂ`, so that the +basis vectors are unambiguous in scalar positions (such as inner products). -/ +noncomputable def lpDelta [DecidableEq F] (i : F) : lp (fun _ : F => ℂ) 2 := + lp.single (E := fun _ : F => ℂ) 2 i (1 : ℂ) + +/-- `δ i` abbreviates the standard basis vector `lpDelta i` of `ℓ²(F)`, matching the `δ_i` of the +informal text. (A Dirac bra-ket `|x⟩⟨y|` notation for the rank-one operator is deliberately not +introduced here: a leading `|` token collides with the set-builder `{y | … }` used in the `htop` +hypotheses throughout this file.) -/ +local notation "δ" => lpDelta + +omit [CompleteSpace H] in +theorem lpDelta_apply [DecidableEq F] (i : F) : + lpDelta i = lp.single (E := fun _ : F => ℂ) 2 i (1 : ℂ) := rfl + +omit [CompleteSpace H] in +/-- The basis vectors `δ_i` are unit vectors. -/ +theorem lpDelta_norm [DecidableEq F] (i : F) : ‖lpDelta i‖ = 1 := by + rw [lpDelta_apply, lp.norm_single (by norm_num), norm_one] + +omit [CompleteSpace H] in +/-- The standard basis vectors `δ_i` span a dense subspace of `ℓ²(F)`. -/ +theorem dense_span_lpDelta [DecidableEq F] : + Dense (Submodule.span ℂ (Set.range (lpDelta : F → lp (fun _ : F => ℂ) 2)) : + Set (lp (fun _ : F => ℂ) 2)) := by + intro g + have hsum : HasSum (fun i : F => lp.single (E := fun _ : F => ℂ) 2 i (g i)) g := + lp.hasSum_single (by norm_num) g + refine mem_closure_of_tendsto hsum (Filter.Eventually.of_forall (fun s => ?_)) + refine Submodule.sum_mem _ (fun i _ => ?_) + rw [show lp.single (E := fun _ : F => ℂ) 2 i (g i) = (g i) • lpDelta i by + rw [lpDelta_apply, ← lp.single_smul, smul_eq_mul, mul_one]] + exact Submodule.smul_mem _ _ (Submodule.subset_span ⟨i, rfl⟩) + +/-- **Explicit multiplicity coordinate.** Under the spatial decomposition the `i`-th coordinate of +`y` in `ℓ²(F; eH)` is `v_i⋆ y`, where `v_i` is the equivalence partial isometry `e ≅ i`. -/ +theorem OrthEquivFam.coe_multiplicityEquiv_apply (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + (y : H) (i : F) : + ((hF.multiplicityEquiv htop y i : LinearMap.range (e : H →ₗ[ℂ] H)) : H) + = star (hF.pisom i) y := by + have hop : star (hF.pisom i) * (i : H →L[ℂ] H) = star (hF.pisom i) := by + rw [← hF.pisom_range i, ← mul_assoc, hF.pisom_source i, hF.e_mul_star_pisom i] + have h1 : ((hF.multiplicityEquiv htop y i : LinearMap.range (e : H →ₗ[ℂ] H)) : H) + = star (hF.pisom i) + ((hF.hilbertSumEquiv htop y i : LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) : H) := + (hF.pisom_isPI i).coe_sourceRangeEquiv_symm (hF.pisom_source i) (hF.pisom_range i) _ + rw [h1, hF.coe_hilbertSumEquiv_apply htop y i, ← ContinuousLinearMap.mul_apply, hop] + +/-- **The spatial isomorphism.** A covering orthogonal family of `e`-equivalent projections gives a +linear isometric equivalence `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` of `H` with the completed Hilbert tensor +product, identifying `H` with `ℓ²(F) ⊗̂ (eH)` via `multiplicityEquiv` and the tensor bridge. This is +the isomorphism implementing the type I structure theorem `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ +noncomputable def OrthEquivFam.spatialEquiv (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] : + H ≃ₗᵢ[ℂ] HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H)) := + (hF.multiplicityEquiv htop).trans (lpTensorEquiv (ι := F) (K := LinearMap.range (e : H →ₗ[ℂ] H))) + +/-- **Spatial expansion of `U`.** The spatial isomorphism `U = multiplicityEquiv ∘ lpTensorEquiv` +expands a vector as `U y = ∑ᵢ δᵢ ⊗̂ (i-th multiplicity coordinate of y)`. -/ +theorem OrthEquivFam.hasSum_tmul_spatialEquiv (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (y : H) : + HasSum (fun i : F => tmul (δ i) (hF.multiplicityEquiv htop y i)) + (hF.spatialEquiv htop y) := by + have h := (lp.hasSum_single (E := fun _ : F => LinearMap.range (e : H →ₗ[ℂ] H)) (p := 2) + (by norm_num) (hF.multiplicityEquiv htop y)).mapL + (lpTensorEquiv (ι := F) + (K := LinearMap.range (e : H →ₗ[ℂ] H))).toLinearIsometry.toContinuousLinearMap + simpa only [OrthEquivFam.spatialEquiv, lpDelta, LinearIsometryEquiv.coe_toLinearIsometry, + LinearIsometry.coe_toContinuousLinearMap, lpTensorEquiv_single, + LinearIsometryEquiv.trans_apply] using h + +attribute [local irreducible] OrthEquivFam.spatialEquiv OrthEquivFam.multiplicityEquiv + +/-- The `p`-th coordinate of `U (e_{pq} y)` collapses to the single term `δ_p ⊗̂ (v_q⋆ y)`: every +other coordinate vanishes because `v_i⋆ e_{pq} = 0` for `i ≠ p`. -/ +theorem OrthEquivFam.spatialEquiv_matrixUnit_apply (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) (y : H) : + hF.spatialEquiv htop (hF.matrixUnit p q y) + = tmul (δ p) (hF.multiplicityEquiv htop (hF.matrixUnit p q y) p) := by + refine (hF.hasSum_tmul_spatialEquiv htop (hF.matrixUnit p q y)).unique ?_ + refine hasSum_single p (fun i hi => ?_) + have hcoe : ((hF.multiplicityEquiv htop (hF.matrixUnit p q y) i : + LinearMap.range (e : H →ₗ[ℂ] H)) : H) = 0 := by + rw [hF.coe_multiplicityEquiv_apply htop] + have h0 : star (hF.pisom i) * hF.matrixUnit p q = 0 := by + rw [OrthEquivFam.matrixUnit_def, ← mul_assoc, + hF.star_pisom_mul_pisom_of_ne hi, zero_mul] + rw [← ContinuousLinearMap.mul_apply, h0, ContinuousLinearMap.zero_apply] + rw [show hF.multiplicityEquiv htop (hF.matrixUnit p q y) i = 0 from + Subtype.ext (by rw [hcoe]; rfl), ← tmulRightL_apply, map_zero] + +/-- The surviving coordinates agree: `v_p⋆ (e_{pq} y) = v_q⋆ y`. -/ +theorem OrthEquivFam.multiplicityEquiv_matrixUnit_coord (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + (p q : F) (y : H) : + hF.multiplicityEquiv htop (hF.matrixUnit p q y) p = hF.multiplicityEquiv htop y q := by + apply Subtype.ext + rw [hF.coe_multiplicityEquiv_apply htop, hF.coe_multiplicityEquiv_apply htop] + have hpp : star (hF.pisom p) * hF.matrixUnit p q = star (hF.pisom q) := by + rw [OrthEquivFam.matrixUnit_def, ← mul_assoc, hF.pisom_source p, hF.e_mul_star_pisom q] + rw [← ContinuousLinearMap.mul_apply, hpp] + +/-- The amplified rank-one operator on `U y` collapses to the single term `δ_p ⊗̂ (v_q⋆ y)`: the +rank-one operator picks out the `q`-th coordinate. -/ +theorem OrthEquivFam.amplifyLeft_rankOne_spatialEquiv (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) (y : H) : + amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) (hF.spatialEquiv htop y) + = tmul (δ p) (hF.multiplicityEquiv htop y q) := by + have key : ∀ i : F, amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) + (tmul (δ i) (hF.multiplicityEquiv htop y i)) + = (inner ℂ (δ q) (δ i) : ℂ) • tmul (δ p) (hF.multiplicityEquiv htop y i) := + fun i => by rw [amplifyLeft_tmul, InnerProductSpace.rankOne_apply, tmul_smul_left] + have hqq : (inner ℂ (δ q) (δ q) : ℂ) = 1 := by + rw [lpDelta_apply, lp.inner_single_left, lp.coeFn_single, Pi.single_eq_same, + RCLike.inner_apply, map_one, mul_one] + have hz : ∀ i : F, i ≠ q → amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) + (tmul (δ i) (hF.multiplicityEquiv htop y i)) = 0 := by + intro i hi + have hzero : (inner ℂ (δ q) (δ i) : ℂ) = 0 := by + rw [lpDelta_apply, lpDelta_apply, lp.inner_single_left, lp.coeFn_single, + Pi.single_eq_of_ne (Ne.symm hi), inner_zero_right] + rw [key i, hzero, zero_smul] + have hval : amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) + (tmul (δ q) (hF.multiplicityEquiv htop y q)) + = tmul (δ p) (hF.multiplicityEquiv htop y q) := by + rw [key q, hqq, one_smul] + exact (((hF.hasSum_tmul_spatialEquiv htop y).mapL + (amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)))).unique + (hasSum_single q hz)).trans hval + +/-- **Intertwining relation.** The spatial isomorphism intertwines the matrix unit `e_{pq}` with +the amplified rank-one operator: `U (e_{pq} y) = (|δ_p⟩⟨δ_q| ⊗̂ 1) (U y)`. -/ +theorem OrthEquivFam.spatialEquiv_intertwine (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) (y : H) : + hF.spatialEquiv htop (hF.matrixUnit p q y) + = amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) (hF.spatialEquiv htop y) := + (hF.spatialEquiv_matrixUnit_apply htop p q y).trans + ((congrArg (tmul (δ p)) (hF.multiplicityEquiv_matrixUnit_coord htop p q y)).trans + (hF.amplifyLeft_rankOne_spatialEquiv htop p q y).symm) + +/-- **Matrix unit identifies with an amplified rank-one operator.** Under the spatial isomorphism +`U`, the matrix unit `e_{pq}` is carried to the amplification of the rank-one operator +`|δ_p⟩⟨δ_q|` on `ℓ²(F)`: `U e_{pq} U⋆ = |δ_p⟩⟨δ_q| ⊗̂ 1`. This is the algebraic heart of the +identification `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ +theorem OrthEquivFam.conjStarAlgEquiv_matrixUnit (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) : + (hF.spatialEquiv htop).conjStarAlgEquiv (hF.matrixUnit p q) + = amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) := by + refine ContinuousLinearMap.ext fun w => ?_ + rw [LinearIsometryEquiv.conjStarAlgEquiv_apply_apply] + exact (hF.spatialEquiv_intertwine htop p q ((hF.spatialEquiv htop).symm w)).trans + (congrArg (amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q))) + (LinearIsometryEquiv.apply_symm_apply (hF.spatialEquiv htop) w)) + +omit [CompleteSpace H] in +/-- **The amplified basis rank-one operators generate `B(ℓ²(F)) ⊗̄ 1`.** The von Neumann algebra +generated by `{|δ_p⟩⟨δ_q| ⊗̂ 1 : p q : F}` is the tensor factor `vnTensorLeft = B(ℓ²(F)) ⊗̄ 1`. The +proof computes the commutant: an operator commuting with all the amplified rank-one operators lies +in `1 ⊗̄ B(eH)` (the dense slice lemma, using that `{δ_p}` spans densely), and conversely +`1 ⊗̄ B(eH)` commutes with them; so the commutant is `vnTensorRight`, whose commutant is +`vnTensorLeft`. -/ +theorem generated_amplifyLeft_rankOne_eq [Nonempty F] [DecidableEq F] + [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] : + VonNeumannAlgebra.generated (Set.range (fun pq : F × F => + amplifyLeft (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)) + (InnerProductSpace.rankOne ℂ (δ pq.1) (δ pq.2)))) + = vnTensorLeft := by + set T := Set.range (fun pq : F × F => amplifyLeft (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)) + (InnerProductSpace.rankOne ℂ (δ pq.1) (δ pq.2))) with hTdef + have hcomm : VonNeumannAlgebra.commutantSet T = vnTensorRight := by + refine le_antisymm (fun x hx => ?_) ?_ + · refine mem_vnTensorRight_of_commutes_dense (δ (Classical.arbitrary F)) + (lpDelta_norm _) (Set.range lpDelta) dense_span_lpDelta x (fun f hf => ?_) + obtain ⟨p, rfl⟩ := hf + have hg : amplifyLeft (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)) + (InnerProductSpace.rankOne ℂ (δ p) (δ (Classical.arbitrary F))) ∈ T := + ⟨(p, Classical.arbitrary F), rfl⟩ + have hcx := (VonNeumannAlgebra.mem_commutantSet_iff.mp hx _ hg).1 + exact hcx.symm + · refine VonNeumannAlgebra.generated_le ?_ + rintro g ⟨B, rfl⟩ + rw [SetLike.mem_coe, VonNeumannAlgebra.mem_commutantSet_iff] + rintro h ⟨pq, rfl⟩ + refine ⟨amplifyLeft_comp_amplifyRight + (InnerProductSpace.rankOne ℂ (δ pq.1) (δ pq.2)) B, ?_⟩ + rw [amplifyLeft_star] + exact amplifyLeft_comp_amplifyRight + (star (InnerProductSpace.rankOne ℂ (δ pq.1) (δ pq.2))) B + haveI : Nontrivial (lp (fun _ : F => ℂ) 2) := + ⟨lpDelta (Classical.arbitrary F), 0, by + rw [← norm_ne_zero_iff, lpDelta_norm]; norm_num⟩ + have hcc : (vnTensorRight (H₁ := lp (fun _ : F => ℂ) 2) + (H₂ := LinearMap.range (e : H →ₗ[ℂ] H))).commutant = vnTensorLeft := + (congrArg VonNeumannAlgebra.commutant + (vnTensorLeft_commutant (H₁ := lp (fun _ : F => ℂ) 2) + (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)))).symm.trans + (VonNeumannAlgebra.commutant_commutant _) + exact (congrArg VonNeumannAlgebra.commutant hcomm).trans hcc + +/-- **Type I factor structure theorem (explicit identification).** Under the spatial isomorphism +`U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)`, the type I factor `N` is carried exactly onto the tensor factor +`B(ℓ²(F)) ⊗̄ 1`: `U N U⋆ = B(ℓ²(F)) ⊗̄ 1`. This glues the matrix-unit generation theorem +`N = ⟨e_{pq}⟩''` to the identification `U e_{pq} U⋆ = |δ_p⟩⟨δ_q| ⊗̂ 1` through the fact that the +spatial conjugation commutes with the generated-algebra construction. -/ +theorem OrthEquivFam.conj_spatialEquiv_eq_vnTensorLeft (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] : + VonNeumannAlgebra.conj (hF.spatialEquiv htop) N = vnTensorLeft := by + have himg : ⇑(hF.spatialEquiv htop).conjStarAlgEquiv '' + (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) + = Set.range (fun pq : F × F => + amplifyLeft (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)) + (InnerProductSpace.rankOne ℂ (δ pq.1) (δ pq.2))) := by + rw [← Set.range_comp] + exact congrArg Set.range (funext fun pq => hF.conjStarAlgEquiv_matrixUnit htop pq.1 pq.2) + calc VonNeumannAlgebra.conj (hF.spatialEquiv htop) N + = VonNeumannAlgebra.conj (hF.spatialEquiv htop) + (VonNeumannAlgebra.generated (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2))) := + congrArg (VonNeumannAlgebra.conj (hF.spatialEquiv htop)) + (hF.generated_matrixUnits_eq he htop).symm + _ = VonNeumannAlgebra.generated (⇑(hF.spatialEquiv htop).conjStarAlgEquiv '' + Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) := + VonNeumannAlgebra.conj_generated _ _ + _ = VonNeumannAlgebra.generated (Set.range (fun pq : F × F => + amplifyLeft (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)) + (InnerProductSpace.rankOne ℂ (δ pq.1) (δ pq.2)))) := + congrArg VonNeumannAlgebra.generated himg + _ = vnTensorLeft := generated_amplifyLeft_rankOne_eq + +/-- **Type I factor structure theorem (commutant).** The same spatial isomorphism carries the +commutant `N'` onto `1 ⊗̄ B(eH)`: `U N' U⋆ = 1 ⊗̄ B(eH)`. This is the companion of +`conj_spatialEquiv_eq_vnTensorLeft`, obtained from it because conjugation commutes with taking +commutants and `(B(ℓ²(F)) ⊗̄ 1)' = 1 ⊗̄ B(eH)`. -/ +theorem OrthEquivFam.conj_spatialEquiv_commutant_eq_vnTensorRight (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] : + VonNeumannAlgebra.conj (hF.spatialEquiv htop) N′ = vnTensorRight := by + haveI : Nontrivial (lp (fun _ : F => ℂ) 2) := + ⟨lpDelta (Classical.arbitrary F), 0, by + rw [← norm_ne_zero_iff, lpDelta_norm]; norm_num⟩ + rw [← VonNeumannAlgebra.conj_commutant, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, + vnTensorLeft_commutant] + +/-- **Split inclusion (left factor).** Any von Neumann subalgebra `A₁ ≤ N` of the type I factor `N` +is carried by the spatial isomorphism into the left tensor factor: `U A₁ U⋆ ≤ B(ℓ²(F)) ⊗̄ 1`. This +is monotonicity of spatial conjugation composed with `U N U⋆ = vnTensorLeft`. -/ +theorem OrthEquivFam.conj_spatialEquiv_le_vnTensorLeft (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] + {A₁ : VonNeumannAlgebra H} (h₁ : A₁ ≤ N) : + VonNeumannAlgebra.conj (hF.spatialEquiv htop) A₁ ≤ vnTensorLeft := + (VonNeumannAlgebra.conj_mono _ h₁).trans_eq (hF.conj_spatialEquiv_eq_vnTensorLeft he htop) + +/-- **Split inclusion (right factor).** Any von Neumann algebra `A₂` whose commutant contains `N` +(equivalently `A₂ ⊆ N'`) is carried by the spatial isomorphism into the right tensor factor: +`U A₂ U⋆ ≤ 1 ⊗̄ B(eH)`. The hypothesis `N ≤ A₂'` is the split-property condition; taking commutants +turns it into `A₂ ≤ N'`, and monotonicity composed with `U N' U⋆ = vnTensorRight` finishes. -/ +theorem OrthEquivFam.conj_spatialEquiv_le_vnTensorRight (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] + {A₂ : VonNeumannAlgebra H} (h₂ : N ≤ A₂′) : + VonNeumannAlgebra.conj (hF.spatialEquiv htop) A₂ ≤ vnTensorRight := by + have hA₂ : A₂ ≤ N′ := by + have h := VonNeumannAlgebra.commutant_le h₂ + rwa [VonNeumannAlgebra.commutant_commutant] at h + exact (VonNeumannAlgebra.conj_mono _ hA₂).trans_eq + (hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop) + +omit [CompleteSpace H] in +/-- A covering orthogonal family of a nonzero Hilbert space is nonempty: its ranges span a dense +subspace, which would be `{0}` were the family empty. -/ +theorem OrthEquivFam.nonempty_of_top [Nontrivial H] {F : Set (H →L[ℂ] H)} + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + Nonempty F := by + rw [← not_isEmpty_iff] + intro hempty + have hset : {y : H | ∃ f ∈ F, ∃ x, f x = y} = (∅ : Set H) := by + ext y + simp only [Set.mem_setOf_eq, Set.mem_empty_iff_false, iff_false] + rintro ⟨f, hf, x, rfl⟩ + exact hempty.false ⟨f, hf⟩ + obtain ⟨z, hz⟩ := exists_ne (0 : H) + have hmem : z ∈ (⊤ : Submodule ℂ H) := Submodule.mem_top + rw [← htop, hset, Submodule.span_empty, ← SetLike.mem_coe, + Submodule.topologicalClosure_coe, Submodule.bot_coe, closure_singleton, + Set.mem_singleton_iff] at hmem + exact hz hmem + +/-- **Type I factor structure theorem (existence form).** A type I factor `N ⊆ B(H)` with minimal +projection `e` (acting on a nonzero Hilbert space) is, up to a spatial isomorphism +`U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)`, exactly the tensor factor `B(ℓ²(F)) ⊗̄ 1`, with commutant `1 ⊗̄ B(eH)`: +conjugation by `U` carries `N` onto `vnTensorLeft` and `N'` onto `vnTensorRight`. This is +Yngvason §5.1 (38)→(39) in its model-independent von-Neumann-algebraic form. -/ +theorem IsFactor.exists_spatial_tensorDecomposition [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : + ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] + HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), + VonNeumannAlgebra.conj U N = vnTensorLeft ∧ + VonNeumannAlgebra.conj U N′ = vnTensorRight := by + obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he + haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range + haveI : DecidableEq F := Classical.decEq _ + haveI : Nonempty F := OrthEquivFam.nonempty_of_top htop + exact ⟨F, hF.spatialEquiv htop, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, + hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop⟩ + +/-- **Split tensor decomposition (Yngvason §5.1 (38)→(39)).** Suppose an intermediate type I factor +`N ⊆ B(H)` with minimal projection `e` is sandwiched between two von Neumann algebras, +`A₁ ≤ N ≤ A₂'` — the *split property* for the pair `(A₁, A₂)`. Then there is a spatial isomorphism +`U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` simultaneously tensor-splitting both algebras: `A₁` lands in the left +factor `B(ℓ²(F)) ⊗̄ 1` and `A₂` lands in the right factor `1 ⊗̄ B(eH)`, with `N` and its commutant +identified exactly. The existence of such an intermediate type I factor `N` is the +model-dependent split-property input; everything downstream of it is proved here. -/ +theorem IsFactor.exists_split_tensorDecomposition [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) + {A₁ A₂ : VonNeumannAlgebra H} (h₁ : A₁ ≤ N) (h₂ : N ≤ A₂′) : + ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] + HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), + VonNeumannAlgebra.conj U N = vnTensorLeft ∧ + VonNeumannAlgebra.conj U N′ = vnTensorRight ∧ + VonNeumannAlgebra.conj U A₁ ≤ vnTensorLeft ∧ + VonNeumannAlgebra.conj U A₂ ≤ vnTensorRight := by + obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he + haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range + haveI : DecidableEq F := Classical.decEq _ + haveI : Nonempty F := OrthEquivFam.nonempty_of_top htop + exact ⟨F, hF.spatialEquiv htop, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, + hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop, + hF.conj_spatialEquiv_le_vnTensorLeft he htop h₁, + hF.conj_spatialEquiv_le_vnTensorRight he htop h₂⟩ + +end VonNeumannAlgebra diff --git a/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean b/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean new file mode 100644 index 0000000..bf46e4f --- /dev/null +++ b/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean @@ -0,0 +1,137 @@ +module + +public import Mathlib.Algebra.Star.StarProjection +public import Mathlib.Analysis.CStarAlgebra.Basic + +/-! +# Partial isometries in a star semigroup + +A **partial isometry** in a semigroup with involution is an element `v` with `v * v⋆ * v = v`. +Its *source projection* `v⋆ * v` and *range projection* `v * v⋆` are then star projections. +Over a C⋆-ring the converse also holds: if *either* `v⋆ * v` or `v * v⋆` is a star projection, +then `v` is a partial isometry, so being a partial isometry is equivalent to each projection +condition. This equivalence is the algebraic backbone of Murray–von Neumann comparison theory +for von Neumann algebras. + +## Main definitions + +* `IsPartialIsometry v` — `v * star v * v = v`. + +## Main results + +* `IsPartialIsometry.isStarProjection_star_mul_self` / `isStarProjection_mul_star_self` — the + source and range projections `v⋆v`, `vv⋆` are star projections. +* `IsPartialIsometry.star` — the adjoint of a partial isometry is a partial isometry. +* `isPartialIsometry_of_isStarProjection_star_mul_self` / + `isPartialIsometry_of_isStarProjection_mul_star_self` — the C⋆-ring converse: a star projection + source or range projection forces `v` to be a partial isometry. +* `isPartialIsometry_iff_isStarProjection_star_mul_self` / + `isPartialIsometry_iff_isStarProjection_mul_star_self` — the resulting equivalences. +-/ + +@[expose] public section + +section Mul + +variable {R : Type*} [Mul R] [Star R] + +/-- An element `v` of a semigroup with involution is a **partial isometry** when `v * v⋆ * v = v`. +For operators on a Hilbert space this is the usual notion: `v` restricts to an isometry on the +orthogonal complement of its kernel. -/ +def IsPartialIsometry (v : R) : Prop := v * star v * v = v + +/-- Every star projection is a partial isometry (with itself as source and range). -/ +theorem IsStarProjection.isPartialIsometry {p : R} (hp : IsStarProjection p) : + IsPartialIsometry p := by + unfold IsPartialIsometry + rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq, hp.isIdempotentElem.eq] + +end Mul + +section Semigroup + +variable {R : Type*} [Semigroup R] [StarMul R] + +namespace IsPartialIsometry + +/-- The source projection `v⋆ * v` of a partial isometry is a star projection. -/ +theorem isStarProjection_star_mul_self {v : R} (h : IsPartialIsometry v) : + IsStarProjection (star v * v) := + ⟨by calc (star v * v) * (star v * v) = star v * (v * star v * v) := by simp only [mul_assoc] + _ = star v * v := by rw [h], + IsSelfAdjoint.star_mul_self v⟩ + +/-- The range projection `v * v⋆` of a partial isometry is a star projection. -/ +theorem isStarProjection_mul_star_self {v : R} (h : IsPartialIsometry v) : + IsStarProjection (v * star v) := + ⟨by calc (v * star v) * (v * star v) = (v * star v * v) * star v := by simp only [mul_assoc] + _ = v * star v := by rw [h], + IsSelfAdjoint.mul_star_self v⟩ + +end IsPartialIsometry + +/-- The adjoint of a partial isometry is a partial isometry. -/ +protected theorem IsPartialIsometry.star {v : R} (h : IsPartialIsometry v) : + IsPartialIsometry (star v) := by + unfold IsPartialIsometry at * + rw [star_star] + calc Star.star v * v * Star.star v = Star.star (v * Star.star v * v) := by + rw [star_mul, star_mul, star_star, mul_assoc] + _ = Star.star v := by rw [h] + +end Semigroup + +section CStarRing + +variable {R : Type*} [NonUnitalNormedRing R] [StarRing R] [CStarRing R] + +/-- The C⋆-ring converse to `IsPartialIsometry.isStarProjection_star_mul_self`: if the source +projection `v⋆ * v` is a star projection, then `v` is a partial isometry. With `a := v - v v⋆ v` +the idempotence of `v⋆ * v` gives `a⋆ * a = 0`, and the C⋆-identity `‖a‖² = ‖a⋆ a‖` forces +`a = 0`. -/ +theorem isPartialIsometry_of_isStarProjection_star_mul_self {v : R} + (h : IsStarProjection (star v * v)) : IsPartialIsometry v := by + have hidem : star v * v * (star v * v) = star v * v := h.isIdempotentElem.eq + have hstar : star (v * star v * v) = star v * v * star v := by + rw [star_mul, star_mul, star_star, mul_assoc] + have key : star (v - v * star v * v) * (v - v * star v * v) = 0 := by + rw [star_sub, hstar] + have expand : (star v - star v * v * star v) * (v - v * star v * v) = + star v * v - star v * v * (star v * v) - star v * v * (star v * v) + + star v * v * (star v * v) * (star v * v) := by + simp only [mul_sub, sub_mul, mul_assoc] + abel + rw [expand] + simp only [hidem] + abel + have hnorm : ‖v - v * star v * v‖ = 0 := by + have hmul := CStarRing.norm_star_mul_self (x := v - v * star v * v) + rw [key, norm_zero] at hmul + exact mul_self_eq_zero.mp hmul.symm + have hzero : v - v * star v * v = 0 := norm_eq_zero.mp hnorm + exact (sub_eq_zero.mp hzero).symm + +/-- The C⋆-ring converse to `IsPartialIsometry.isStarProjection_mul_star_self`: if the range +projection `v * v⋆` is a star projection, then `v` is a partial isometry. This is the source +statement applied to `v⋆`. -/ +theorem isPartialIsometry_of_isStarProjection_mul_star_self {v : R} + (h : IsStarProjection (v * star v)) : IsPartialIsometry v := by + have h' : IsStarProjection (star (star v) * star v) := by rwa [star_star] + have hv := IsPartialIsometry.star (isPartialIsometry_of_isStarProjection_star_mul_self h') + rwa [star_star] at hv + +/-- In a C⋆-ring, `v` is a partial isometry iff its source projection `v⋆ * v` is a star +projection. -/ +theorem isPartialIsometry_iff_isStarProjection_star_mul_self {v : R} : + IsPartialIsometry v ↔ IsStarProjection (star v * v) := + ⟨IsPartialIsometry.isStarProjection_star_mul_self, + isPartialIsometry_of_isStarProjection_star_mul_self⟩ + +/-- In a C⋆-ring, `v` is a partial isometry iff its range projection `v * v⋆` is a star +projection. -/ +theorem isPartialIsometry_iff_isStarProjection_mul_star_self {v : R} : + IsPartialIsometry v ↔ IsStarProjection (v * star v) := + ⟨IsPartialIsometry.isStarProjection_mul_star_self, + isPartialIsometry_of_isStarProjection_mul_star_self⟩ + +end CStarRing diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean new file mode 100644 index 0000000..cc4bd1f --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean @@ -0,0 +1,712 @@ +module + +public import Mathlib.Analysis.InnerProductSpace.Completion +public import Mathlib.Analysis.InnerProductSpace.TensorProduct +public import Mathlib.Analysis.InnerProductSpace.l2Space + +/-! +# The completed Hilbert-space tensor product and operator amplification + +For complex inner product spaces `H₁` and `H₂`, Mathlib equips the *algebraic* tensor product +`H₁ ⊗[ℂ] H₂` with an inner product (`TensorProduct.instInnerProductSpace`), with +`⟪a ⊗ₜ b, c ⊗ₜ d⟫ = ⟪a, c⟫ * ⟪b, d⟫`, but it is left incomplete (an explicit `TODO` in +`Mathlib/Analysis/InnerProductSpace/TensorProduct.lean`). This file packages its completion + +`HilbertTensor H₁ H₂ := UniformSpace.Completion (H₁ ⊗[ℂ] H₂)`, + +which inherits an `InnerProductSpace ℂ` structure from +`UniformSpace.Completion.innerProductSpace` and is complete, hence a genuine complex Hilbert +space — the object physicists write `H₁ ⊗ H₂` for Hilbert spaces. + +It then constructs the **amplifications** of bounded operators, + +`amplifyLeft : B(H₁) → B(HilbertTensor H₁ H₂)`, `A ↦ A ⊗̂ 1`, +`amplifyRight : B(H₂) → B(HilbertTensor H₁ H₂)`, `B ↦ 1 ⊗̂ B`, + +obtained by extending the bounded operator `A ⊗ 1` (resp. `1 ⊗ B`) from the dense algebraic +tensor product to the completion. The key analytic input is the cross-norm bound +`‖(A ⊗ 1) z‖ ≤ ‖A‖ * ‖z‖`, proved by writing `z` along an orthonormal family of the second +factor. + +## Notation + +The textbook symbols `⊗̂` (completed tensor) and `⊗ₕ` (pure tensor) live in the opt-in +`HilbertTensor` scope; activate them with `open scoped HilbertTensor`. + +| Symbol | Expansion | How to activate | +|---|---|---| +| `H₁ ⊗̂ H₂` | `HilbertTensor H₁ H₂` | `open scoped HilbertTensor` | +| `x ⊗ₕ y` | `HilbertTensor.tmul x y` | `open scoped HilbertTensor` | + +## Main definitions + +* `HilbertTensor H₁ H₂` — the completed Hilbert-space tensor product. +* `HilbertTensor.tmul x y` — the pure tensor `x ⊗ y` viewed in the completion. +* `HilbertTensor.amplifyLeft A`, `HilbertTensor.amplifyRight B` — the amplified operators. +* `HilbertTensor.amplifyLeftₐ`, `HilbertTensor.amplifyRightₐ` — the amplifications bundled as + unital `⋆`-algebra homomorphisms (on genuine Hilbert spaces). + +## Main results + +* `HilbertTensor.inner_tmul` — the inner product on pure tensors factorises. +* `HilbertTensor.add_tmul` / `tmul_add` / `tmul_smul_left` / `smul_tmul_right` — `tmul` is + bilinear. +* `TensorProduct.norm_map_left_le` / `norm_map_right_le` — the cross-norm bounds on the + algebraic tensor product. +* `HilbertTensor.amplifyLeft_tmul` / `amplifyRight_tmul` — the action on pure tensors. +* `HilbertTensor.amplifyLeft_one` / `amplifyLeft_mul` / `amplifyLeft_add` / `amplifyLeft_smul` + (and the right analogues) — the amplifications are unital `ℂ`-algebra homomorphisms. +-/ + +@[expose] public section + +open scoped TensorProduct + +variable {H₁ H₂ : Type*} + [NormedAddCommGroup H₁] [InnerProductSpace ℂ H₁] + [NormedAddCommGroup H₂] [InnerProductSpace ℂ H₂] + +/-- The **completed Hilbert-space tensor product** of two complex inner product spaces: the +completion of the algebraic tensor product `H₁ ⊗[ℂ] H₂` with respect to the inner-product norm +`‖x ⊗ₜ y‖ = ‖x‖ * ‖y‖`. As the completion of an inner product space it is again an +`InnerProductSpace ℂ`, and being a completion it is a `CompleteSpace`, so it is a complex +Hilbert space. -/ +abbrev HilbertTensor (H₁ H₂ : Type*) + [NormedAddCommGroup H₁] [InnerProductSpace ℂ H₁] + [NormedAddCommGroup H₂] [InnerProductSpace ℂ H₂] : Type _ := + UniformSpace.Completion (H₁ ⊗[ℂ] H₂) + +namespace HilbertTensor + +/-- A pure tensor `x ⊗ y` regarded as an element of the completed tensor product. -/ +noncomputable def tmul (x : H₁) (y : H₂) : HilbertTensor H₁ H₂ := + ((x ⊗ₜ[ℂ] y : H₁ ⊗[ℂ] H₂) : HilbertTensor H₁ H₂) + +/-- `H₁ ⊗̂ H₂` denotes the completed Hilbert-space tensor product `HilbertTensor H₁ H₂`. The hat +distinguishes it from Mathlib's algebraic tensor product `H₁ ⊗[ℂ] H₂`. -/ +scoped infixr:35 " ⊗̂ " => HilbertTensor + +/-- `x ⊗ₕ y` denotes the pure tensor `HilbertTensor.tmul x y` in the completed tensor product. The +subscript `h` (Hilbert) distinguishes it from Mathlib's algebraic pure tensor `x ⊗ₜ y`. -/ +scoped infixr:100 " ⊗ₕ " => HilbertTensor.tmul + +/-- The inner product of two pure tensors in the completed tensor product factorises as the +product of the inner products of the factors. -/ +@[simp] theorem inner_tmul (x x' : H₁) (y y' : H₂) : + inner ℂ (x ⊗ₕ y) (x' ⊗ₕ y') = inner ℂ x x' * inner ℂ y y' := by + rw [tmul, tmul, UniformSpace.Completion.inner_coe, TensorProduct.inner_tmul] + +/-- The norm of a pure tensor factorises. -/ +@[simp] theorem norm_tmul (x : H₁) (y : H₂) : ‖x ⊗ₕ y‖ = ‖x‖ * ‖y‖ := by + rw [tmul, UniformSpace.Completion.norm_coe, TensorProduct.norm_tmul] + +/-- The pure tensor is additive in its right argument. -/ +theorem tmul_add (x : H₁) (y y' : H₂) : x ⊗ₕ (y + y') = x ⊗ₕ y + x ⊗ₕ y' := by + rw [tmul, tmul, tmul, ← UniformSpace.Completion.coe_add, TensorProduct.tmul_add] + +/-- The pure tensor is additive in its left argument. -/ +theorem add_tmul (x x' : H₁) (y : H₂) : (x + x') ⊗ₕ y = x ⊗ₕ y + x' ⊗ₕ y := by + rw [tmul, tmul, tmul, ← UniformSpace.Completion.coe_add, TensorProduct.add_tmul] + +/-- A scalar in the left argument of a pure tensor factors out. -/ +theorem tmul_smul_left (c : ℂ) (x : H₁) (y : H₂) : (c • x) ⊗ₕ y = c • x ⊗ₕ y := by + rw [tmul, tmul, ← UniformSpace.Completion.coe_smul, TensorProduct.smul_tmul'] + +/-- A scalar in the right argument of a pure tensor factors out. -/ +theorem smul_tmul_right (c : ℂ) (x : H₁) (y : H₂) : x ⊗ₕ (c • y) = c • x ⊗ₕ y := by + rw [tmul, tmul, ← UniformSpace.Completion.coe_smul, TensorProduct.tmul_smul] + +/-- A pure tensor with a zero left argument vanishes. -/ +@[simp] theorem zero_tmul (y : H₂) : (0 : H₁) ⊗ₕ y = 0 := by + rw [tmul, TensorProduct.zero_tmul, UniformSpace.Completion.coe_zero] + +/-- A pure tensor with a zero right argument vanishes. -/ +@[simp] theorem tmul_zero (x : H₁) : x ⊗ₕ (0 : H₂) = 0 := by + rw [tmul, TensorProduct.tmul_zero, UniformSpace.Completion.coe_zero] + +/-- The bounded inclusion `H₁ → H₁ ⊗̂ H₂`, `x ↦ x ⊗ z`, for a fixed `z ∈ H₂`. Its operator norm is +`‖z‖` (`‖tmulLeftL z x‖ = ‖x‖ * ‖z‖`), so it is an isometry exactly when `‖z‖ = 1`. This is the +mirror image of `tmulRightL`, fixing the second factor instead of the first. -/ +noncomputable def tmulLeftL (z : H₂) : H₁ →L[ℂ] HilbertTensor H₁ H₂ := + UniformSpace.Completion.toComplL.comp + (LinearMap.mkContinuous ((TensorProduct.mk ℂ H₁ H₂).flip z) ‖z‖ fun x => by + rw [LinearMap.flip_apply, TensorProduct.mk_apply, TensorProduct.norm_tmul, mul_comm]) + +@[simp] theorem tmulLeftL_apply (z : H₂) (x : H₁) : tmulLeftL z x = tmul x z := by + rw [tmulLeftL, ContinuousLinearMap.comp_apply, LinearMap.mkContinuous_apply, + LinearMap.flip_apply, TensorProduct.mk_apply] + rfl + +end HilbertTensor + +namespace TensorProduct + +/-- Every element of the algebraic tensor product can be written as a finite sum +`∑ ξ i ⊗ₜ e i` where the second factors `e i` form an orthonormal family of `H₂`. This is the +analytic normal form behind the cross-norm bound: choose a finite-dimensional submodule of `H₂` +carrying the element and take an orthonormal basis of it. -/ +theorem exists_orthonormal_rep (z : H₁ ⊗[ℂ] H₂) : + ∃ (n : ℕ) (e : Fin n → H₂) (ξ : Fin n → H₁), + Orthonormal ℂ e ∧ z = ∑ i, ξ i ⊗ₜ[ℂ] e i := by + obtain ⟨N', hN'fin, hz⟩ := + TensorProduct.exists_finite_submodule_right_of_setFinite {z} (Set.finite_singleton z) + obtain ⟨z₀, hz₀⟩ := hz (Set.mem_singleton z) + haveI : FiniteDimensional ℂ N' := hN'fin + let b := stdOrthonormalBasis ℂ N' + set ξ : Fin (Module.finrank ℂ N') → H₁ := + fun i => TensorProduct.equivFinsuppOfBasisRight b.toBasis z₀ i with hξ + have hrep : z₀ = ∑ i, ξ i ⊗ₜ[ℂ] b.toBasis i := by + conv_lhs => rw [← (TensorProduct.equivFinsuppOfBasisRight b.toBasis).symm_apply_apply z₀] + rw [TensorProduct.equivFinsuppOfBasisRight_symm_apply, + Finsupp.sum_fintype _ _ (fun i => by simp)] + refine ⟨Module.finrank ℂ N', fun i => (b i : H₂), ξ, + b.orthonormal.comp_linearIsometry N'.subtypeₗᵢ, ?_⟩ + calc z = (LinearMap.lTensor H₁ N'.subtype) z₀ := hz₀.symm + _ = (LinearMap.lTensor H₁ N'.subtype) (∑ i, ξ i ⊗ₜ[ℂ] b.toBasis i) := by rw [← hrep] + _ = ∑ i, ξ i ⊗ₜ[ℂ] (b i : H₂) := by + rw [map_sum]; simp_rw [LinearMap.lTensor_tmul]; rfl + +/-- **Cross-norm bound (left factor).** On the algebraic Hilbert tensor product, amplifying a +bounded operator `A` on the first factor by the identity does not increase the norm beyond a +factor of `‖A‖`: `‖(A ⊗ 1) z‖ ≤ ‖A‖ * ‖z‖`. -/ +theorem norm_map_left_le (A : H₁ →L[ℂ] H₁) (z : H₁ ⊗[ℂ] H₂) : + ‖TensorProduct.map A.toLinearMap LinearMap.id z‖ ≤ ‖A‖ * ‖z‖ := by + obtain ⟨n, e, ξ, he, rfl⟩ := exists_orthonormal_rep z + classical + have key : ∀ (η : Fin n → H₁), ‖∑ i, η i ⊗ₜ[ℂ] e i‖ ^ 2 = ∑ i, ‖η i‖ ^ 2 := by + intro η + rw [← inner_self_eq_norm_sq (𝕜 := ℂ)] + have h : inner ℂ (∑ i, η i ⊗ₜ[ℂ] e i) (∑ i, η i ⊗ₜ[ℂ] e i) + = ∑ i, inner ℂ (η i) (η i) := by + rw [sum_inner] + simp_rw [inner_sum, TensorProduct.inner_tmul, orthonormal_iff_ite.mp he] + simp [Finset.sum_ite_eq] + rw [h, map_sum] + simp_rw [inner_self_eq_norm_sq (𝕜 := ℂ)] + rw [map_sum] + simp_rw [TensorProduct.map_tmul, LinearMap.id_coe, id_eq, ContinuousLinearMap.coe_coe] + rw [← Real.sqrt_sq (norm_nonneg _), ← Real.sqrt_sq (mul_nonneg (norm_nonneg A) (norm_nonneg _))] + apply Real.sqrt_le_sqrt + rw [mul_pow, key, key, Finset.mul_sum] + apply Finset.sum_le_sum + intro i _ + rw [← mul_pow] + gcongr + exact A.le_opNorm (ξ i) + +/-- The commutation isometry intertwines the two one-sided amplifications on the algebraic +tensor product: swapping the factors turns `1 ⊗ B` into `B ⊗ 1`. -/ +theorem commIsometry_map_id (B : H₂ →L[ℂ] H₂) (z : H₁ ⊗[ℂ] H₂) : + commIsometry ℂ H₁ H₂ (TensorProduct.map LinearMap.id B.toLinearMap z) + = TensorProduct.map B.toLinearMap LinearMap.id (commIsometry ℂ H₁ H₂ z) := by + induction z using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp + | add a b ha hb => simp [map_add, ha, hb] + +/-- **Cross-norm bound (right factor).** `‖(1 ⊗ B) z‖ ≤ ‖B‖ * ‖z‖`, obtained from the left bound +by conjugating with the commutation isometry. -/ +theorem norm_map_right_le (B : H₂ →L[ℂ] H₂) (z : H₁ ⊗[ℂ] H₂) : + ‖TensorProduct.map LinearMap.id B.toLinearMap z‖ ≤ ‖B‖ * ‖z‖ := by + rw [← (commIsometry ℂ H₁ H₂).norm_map (TensorProduct.map LinearMap.id B.toLinearMap z), + commIsometry_map_id, ← (commIsometry ℂ H₁ H₂).norm_map z] + exact norm_map_left_le B _ + +end TensorProduct + +namespace HilbertTensor + +open UniformSpace + +/-- The amplification `A ⊗ 1` as a bounded operator on the *algebraic* tensor product, packaged +from the cross-norm bound `TensorProduct.norm_map_left_le`. -/ +noncomputable def algAmplifyLeft (A : H₁ →L[ℂ] H₁) : (H₁ ⊗[ℂ] H₂) →L[ℂ] (H₁ ⊗[ℂ] H₂) := + LinearMap.mkContinuous (TensorProduct.map A.toLinearMap LinearMap.id) ‖A‖ + (TensorProduct.norm_map_left_le A) + +/-- The amplification `1 ⊗ B` as a bounded operator on the *algebraic* tensor product. -/ +noncomputable def algAmplifyRight (B : H₂ →L[ℂ] H₂) : (H₁ ⊗[ℂ] H₂) →L[ℂ] (H₁ ⊗[ℂ] H₂) := + LinearMap.mkContinuous (TensorProduct.map LinearMap.id B.toLinearMap) ‖B‖ + (TensorProduct.norm_map_right_le B) + +@[simp] theorem algAmplifyLeft_tmul (A : H₁ →L[ℂ] H₁) (x : H₁) (y : H₂) : + algAmplifyLeft (H₂ := H₂) A (x ⊗ₜ[ℂ] y) = (A x) ⊗ₜ[ℂ] y := by + simp [algAmplifyLeft] + +@[simp] theorem algAmplifyRight_tmul (B : H₂ →L[ℂ] H₂) (x : H₁) (y : H₂) : + algAmplifyRight (H₁ := H₁) B (x ⊗ₜ[ℂ] y) = x ⊗ₜ[ℂ] (B y) := by + simp [algAmplifyRight] + +/-- The **left amplification** `A ↦ A ⊗̂ 1` of a bounded operator on the first factor to a bounded +operator on the completed Hilbert tensor product, obtained by extending `algAmplifyLeft A` from +the dense algebraic tensor product to the completion. -/ +noncomputable def amplifyLeft (A : H₁ →L[ℂ] H₁) : + HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂ where + toFun := Completion.map (algAmplifyLeft A) + map_add' x y := by + refine Completion.induction_on₂ x y + (isClosed_eq ((Completion.continuous_map (f := algAmplifyLeft A)).comp continuous_add) + (((Completion.continuous_map (f := algAmplifyLeft A)).comp continuous_fst).add + ((Completion.continuous_map (f := algAmplifyLeft A)).comp continuous_snd))) + (fun a b => ?_) + rw [← Completion.coe_add, Completion.map_coe (algAmplifyLeft A).uniformContinuous, + Completion.map_coe (algAmplifyLeft A).uniformContinuous, + Completion.map_coe (algAmplifyLeft A).uniformContinuous, ← Completion.coe_add, map_add] + map_smul' c x := by + refine Completion.induction_on x + (isClosed_eq + ((Completion.continuous_map (f := algAmplifyLeft A)).comp (continuous_const_smul c)) + ((continuous_const_smul c).comp (Completion.continuous_map (f := algAmplifyLeft A)))) + (fun a => ?_) + rw [← Completion.coe_smul, Completion.map_coe (algAmplifyLeft A).uniformContinuous, + Completion.map_coe (algAmplifyLeft A).uniformContinuous, ← Completion.coe_smul, map_smul] + rfl + cont := Completion.continuous_map + +/-- The **right amplification** `B ↦ 1 ⊗̂ B`. -/ +noncomputable def amplifyRight (B : H₂ →L[ℂ] H₂) : + HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂ where + toFun := Completion.map (algAmplifyRight B) + map_add' x y := by + refine Completion.induction_on₂ x y + (isClosed_eq ((Completion.continuous_map (f := algAmplifyRight B)).comp continuous_add) + (((Completion.continuous_map (f := algAmplifyRight B)).comp continuous_fst).add + ((Completion.continuous_map (f := algAmplifyRight B)).comp continuous_snd))) + (fun a b => ?_) + rw [← Completion.coe_add, Completion.map_coe (algAmplifyRight B).uniformContinuous, + Completion.map_coe (algAmplifyRight B).uniformContinuous, + Completion.map_coe (algAmplifyRight B).uniformContinuous, ← Completion.coe_add, map_add] + map_smul' c x := by + refine Completion.induction_on x + (isClosed_eq + ((Completion.continuous_map (f := algAmplifyRight B)).comp (continuous_const_smul c)) + ((continuous_const_smul c).comp (Completion.continuous_map (f := algAmplifyRight B)))) + (fun a => ?_) + rw [← Completion.coe_smul, Completion.map_coe (algAmplifyRight B).uniformContinuous, + Completion.map_coe (algAmplifyRight B).uniformContinuous, ← Completion.coe_smul, map_smul] + rfl + cont := Completion.continuous_map + +@[simp] theorem amplifyLeft_tmul (A : H₁ →L[ℂ] H₁) (x : H₁) (y : H₂) : + amplifyLeft A (x ⊗ₕ y) = (A x) ⊗ₕ y := by + rw [amplifyLeft, tmul] + change Completion.map (algAmplifyLeft A) _ = _ + rw [Completion.map_coe (algAmplifyLeft A).uniformContinuous, algAmplifyLeft_tmul, tmul] + +@[simp] theorem amplifyRight_tmul (B : H₂ →L[ℂ] H₂) (x : H₁) (y : H₂) : + amplifyRight B (x ⊗ₕ y) = x ⊗ₕ (B y) := by + rw [amplifyRight, tmul] + change Completion.map (algAmplifyRight B) _ = _ + rw [Completion.map_coe (algAmplifyRight B).uniformContinuous, algAmplifyRight_tmul, tmul] + +/-- The defining action of the left amplification on the image of the algebraic tensor product. -/ +@[simp] theorem amplifyLeft_coe (A : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : + amplifyLeft A (a : HilbertTensor H₁ H₂) + = ((algAmplifyLeft A a : H₁ ⊗[ℂ] H₂) : HilbertTensor H₁ H₂) := + Completion.map_coe (algAmplifyLeft A).uniformContinuous a + +/-- The defining action of the right amplification on the image of the algebraic tensor product. -/ +@[simp] theorem amplifyRight_coe (B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : + amplifyRight B (a : HilbertTensor H₁ H₂) + = ((algAmplifyRight B a : H₁ ⊗[ℂ] H₂) : HilbertTensor H₁ H₂) := + Completion.map_coe (algAmplifyRight B).uniformContinuous a + +/-! ### Multiplicativity and unitality + +The amplifications are unital algebra homomorphisms onto their images: they send the identity to +the identity and turn composition in `B(H₁)` (resp. `B(H₂)`) into composition in +`B(HilbertTensor H₁ H₂)`. -/ + +theorem algAmplifyLeft_one_apply (a : H₁ ⊗[ℂ] H₂) : + algAmplifyLeft (H₂ := H₂) (1 : H₁ →L[ℂ] H₁) a = a := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp + | add p q hp hq => simp [map_add, hp, hq] + +theorem algAmplifyLeft_mul_apply (A B : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : + algAmplifyLeft (A * B) a = algAmplifyLeft A (algAmplifyLeft B a) := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp [ContinuousLinearMap.mul_apply] + | add p q hp hq => simp [map_add, hp, hq] + +theorem algAmplifyRight_one_apply (a : H₁ ⊗[ℂ] H₂) : + algAmplifyRight (H₁ := H₁) (1 : H₂ →L[ℂ] H₂) a = a := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp + | add p q hp hq => simp [map_add, hp, hq] + +theorem algAmplifyRight_mul_apply (A B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : + algAmplifyRight (A * B) a = algAmplifyRight A (algAmplifyRight B a) := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp [ContinuousLinearMap.mul_apply] + | add p q hp hq => simp [map_add, hp, hq] + +@[simp] theorem amplifyLeft_one : + amplifyLeft (1 : H₁ →L[ℂ] H₁) = (1 : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyLeft _).continuous (ContinuousLinearMap.continuous 1)) (fun a => ?_) + simp [algAmplifyLeft_one_apply] + +theorem amplifyLeft_mul (A B : H₁ →L[ℂ] H₁) : + amplifyLeft (H₂ := H₂) (A * B) = amplifyLeft A * amplifyLeft B := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyLeft _).continuous + ((amplifyLeft A).continuous.comp (amplifyLeft B).continuous)) (fun a => ?_) + simp [ContinuousLinearMap.mul_apply, algAmplifyLeft_mul_apply] + +@[simp] theorem amplifyRight_one : + amplifyRight (1 : H₂ →L[ℂ] H₂) = (1 : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyRight _).continuous (ContinuousLinearMap.continuous 1)) (fun a => ?_) + simp [algAmplifyRight_one_apply] + +theorem amplifyRight_mul (A B : H₂ →L[ℂ] H₂) : + amplifyRight (H₁ := H₁) (A * B) = amplifyRight A * amplifyRight B := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyRight _).continuous + ((amplifyRight A).continuous.comp (amplifyRight B).continuous)) (fun a => ?_) + simp [ContinuousLinearMap.mul_apply, algAmplifyRight_mul_apply] + +/-! ### Additivity and homogeneity in the amplified operator + +The amplifications `A ↦ A ⊗̂ 1` and `B ↦ 1 ⊗̂ B` are themselves `ℂ`-linear in the operator +being amplified: they preserve `0`, addition, and scalar multiplication. -/ + +theorem algAmplifyLeft_zero_apply (a : H₁ ⊗[ℂ] H₂) : + algAmplifyLeft (H₂ := H₂) (0 : H₁ →L[ℂ] H₁) a = 0 := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp + | add p q hp hq => simp [map_add, hp, hq] + +theorem algAmplifyLeft_add_apply (A B : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : + algAmplifyLeft (A + B) a = algAmplifyLeft A a + algAmplifyLeft B a := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp [ContinuousLinearMap.add_apply, TensorProduct.add_tmul] + | add p q hp hq => simp only [map_add, hp, hq]; abel + +theorem algAmplifyLeft_smul_apply (c : ℂ) (A : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : + algAmplifyLeft (c • A) a = c • algAmplifyLeft A a := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp [ContinuousLinearMap.smul_apply, TensorProduct.smul_tmul'] + | add p q hp hq => simp only [map_add, hp, hq, smul_add] + +theorem algAmplifyRight_zero_apply (a : H₁ ⊗[ℂ] H₂) : + algAmplifyRight (H₁ := H₁) (0 : H₂ →L[ℂ] H₂) a = 0 := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp + | add p q hp hq => simp [map_add, hp, hq] + +theorem algAmplifyRight_add_apply (A B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : + algAmplifyRight (A + B) a = algAmplifyRight A a + algAmplifyRight B a := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp [ContinuousLinearMap.add_apply, TensorProduct.tmul_add] + | add p q hp hq => simp only [map_add, hp, hq]; abel + +theorem algAmplifyRight_smul_apply (c : ℂ) (B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : + algAmplifyRight (c • B) a = c • algAmplifyRight B a := by + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => simp [ContinuousLinearMap.smul_apply, TensorProduct.tmul_smul] + | add p q hp hq => simp only [map_add, hp, hq, smul_add] + +@[simp] theorem amplifyLeft_zero : + amplifyLeft (0 : H₁ →L[ℂ] H₁) = (0 : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyLeft _).continuous (ContinuousLinearMap.continuous 0)) (fun a => ?_) + rw [amplifyLeft_coe, algAmplifyLeft_zero_apply, UniformSpace.Completion.coe_zero, + ContinuousLinearMap.zero_apply] + +theorem amplifyLeft_add (A B : H₁ →L[ℂ] H₁) : + amplifyLeft (H₂ := H₂) (A + B) = amplifyLeft A + amplifyLeft B := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyLeft _).continuous + ((amplifyLeft A).continuous.add (amplifyLeft B).continuous)) (fun a => ?_) + rw [amplifyLeft_coe, algAmplifyLeft_add_apply, UniformSpace.Completion.coe_add, + ContinuousLinearMap.add_apply, amplifyLeft_coe, amplifyLeft_coe] + +theorem amplifyLeft_smul (c : ℂ) (A : H₁ →L[ℂ] H₁) : + amplifyLeft (H₂ := H₂) (c • A) = c • amplifyLeft A := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyLeft _).continuous + ((continuous_const_smul c).comp (amplifyLeft A).continuous)) (fun a => ?_) + rw [amplifyLeft_coe, algAmplifyLeft_smul_apply, UniformSpace.Completion.coe_smul, + ContinuousLinearMap.smul_apply, amplifyLeft_coe] + +@[simp] theorem amplifyRight_zero : + amplifyRight (0 : H₂ →L[ℂ] H₂) = (0 : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyRight _).continuous (ContinuousLinearMap.continuous 0)) (fun a => ?_) + rw [amplifyRight_coe, algAmplifyRight_zero_apply, UniformSpace.Completion.coe_zero, + ContinuousLinearMap.zero_apply] + +theorem amplifyRight_add (A B : H₂ →L[ℂ] H₂) : + amplifyRight (H₁ := H₁) (A + B) = amplifyRight A + amplifyRight B := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyRight _).continuous + ((amplifyRight A).continuous.add (amplifyRight B).continuous)) (fun a => ?_) + rw [amplifyRight_coe, algAmplifyRight_add_apply, UniformSpace.Completion.coe_add, + ContinuousLinearMap.add_apply, amplifyRight_coe, amplifyRight_coe] + +theorem amplifyRight_smul (c : ℂ) (B : H₂ →L[ℂ] H₂) : + amplifyRight (H₁ := H₁) (c • B) = c • amplifyRight B := by + ext z + refine Completion.induction_on z + (isClosed_eq (amplifyRight _).continuous + ((continuous_const_smul c).comp (amplifyRight B).continuous)) (fun a => ?_) + rw [amplifyRight_coe, algAmplifyRight_smul_apply, UniformSpace.Completion.coe_smul, + ContinuousLinearMap.smul_apply, amplifyRight_coe] + +/-! ### Adjoints + +On genuine Hilbert spaces (`CompleteSpace H₁`, `CompleteSpace H₂`) the amplifications are +`*`-homomorphisms: they intertwine the adjoint on `B(H₁)` (resp. `B(H₂)`) with the adjoint on +`B(HilbertTensor H₁ H₂)`, hence preserve the `star` operation. Together with +`amplifyLeft_one`/`amplifyLeft_mul`/`amplifyLeft_add`/`amplifyLeft_smul` this exhibits +`amplifyLeft` and `amplifyRight` as unital `*`-algebra homomorphisms, bundled as +`amplifyLeftₐ` and `amplifyRightₐ`. -/ + +section Adjoint + +variable [CompleteSpace H₁] [CompleteSpace H₂] + +omit [CompleteSpace H₂] in +theorem algAmplifyLeft_inner_adjoint (A : H₁ →L[ℂ] H₁) (a b : H₁ ⊗[ℂ] H₂) : + inner ℂ (algAmplifyLeft (ContinuousLinearMap.adjoint A) a) b + = inner ℂ a (algAmplifyLeft A b) := by + simp only [algAmplifyLeft, LinearMap.mkContinuous_apply] + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => + induction b using TensorProduct.induction_on with + | zero => simp + | tmul x' y' => + simp only [TensorProduct.map_tmul, LinearMap.id_coe, id_eq, ContinuousLinearMap.coe_coe, + TensorProduct.inner_tmul] + rw [ContinuousLinearMap.adjoint_inner_left] + | add p q hp hq => simp only [inner_add_right, map_add, hp, hq] + | add p q hp hq => simp only [inner_add_left, map_add, hp, hq] + +omit [CompleteSpace H₁] in +theorem algAmplifyRight_inner_adjoint (B : H₂ →L[ℂ] H₂) (a b : H₁ ⊗[ℂ] H₂) : + inner ℂ (algAmplifyRight (ContinuousLinearMap.adjoint B) a) b + = inner ℂ a (algAmplifyRight B b) := by + simp only [algAmplifyRight, LinearMap.mkContinuous_apply] + induction a using TensorProduct.induction_on with + | zero => simp + | tmul x y => + induction b using TensorProduct.induction_on with + | zero => simp + | tmul x' y' => + simp only [TensorProduct.map_tmul, LinearMap.id_coe, id_eq, ContinuousLinearMap.coe_coe, + TensorProduct.inner_tmul] + rw [ContinuousLinearMap.adjoint_inner_left] + | add p q hp hq => simp only [inner_add_right, map_add, hp, hq] + | add p q hp hq => simp only [inner_add_left, map_add, hp, hq] + +omit [CompleteSpace H₂] in +/-- The adjoint of the left amplification of `A` is the left amplification of the adjoint of `A`. -/ +theorem amplifyLeft_adjoint (A : H₁ →L[ℂ] H₁) : + ContinuousLinearMap.adjoint (amplifyLeft (H₂ := H₂) A) + = amplifyLeft (ContinuousLinearMap.adjoint A) := by + symm + rw [ContinuousLinearMap.eq_adjoint_iff] + intro u v + refine Completion.induction_on₂ u v (isClosed_eq (by fun_prop) (by fun_prop)) (fun a b => ?_) + rw [amplifyLeft_coe, amplifyLeft_coe, UniformSpace.Completion.inner_coe, + UniformSpace.Completion.inner_coe, algAmplifyLeft_inner_adjoint] + +omit [CompleteSpace H₁] in +/-- The adjoint of the right amplification of `B` is the right amplification of the adjoint of +`B`. -/ +theorem amplifyRight_adjoint (B : H₂ →L[ℂ] H₂) : + ContinuousLinearMap.adjoint (amplifyRight (H₁ := H₁) B) + = amplifyRight (ContinuousLinearMap.adjoint B) := by + symm + rw [ContinuousLinearMap.eq_adjoint_iff] + intro u v + refine Completion.induction_on₂ u v (isClosed_eq (by fun_prop) (by fun_prop)) (fun a b => ?_) + rw [amplifyRight_coe, amplifyRight_coe, UniformSpace.Completion.inner_coe, + UniformSpace.Completion.inner_coe, algAmplifyRight_inner_adjoint] + +omit [CompleteSpace H₂] in +/-- The left amplification preserves the `star` (adjoint) operation. -/ +@[simp] theorem amplifyLeft_star (A : H₁ →L[ℂ] H₁) : + star (amplifyLeft (H₂ := H₂) A) = amplifyLeft (star A) := + amplifyLeft_adjoint A + +omit [CompleteSpace H₁] in +/-- The right amplification preserves the `star` (adjoint) operation. -/ +@[simp] theorem amplifyRight_star (B : H₂ →L[ℂ] H₂) : + star (amplifyRight (H₁ := H₁) B) = amplifyRight (star B) := + amplifyRight_adjoint B + +omit [CompleteSpace H₂] in +/-- The **left amplification** `A ↦ A ⊗̂ 1`, bundled as a unital `⋆`-algebra homomorphism +`B(H₁) →⋆ₐ[ℂ] B(HilbertTensor H₁ H₂)`. This packages `amplifyLeft_one`, `amplifyLeft_mul`, +`amplifyLeft_add`, `amplifyLeft_smul`, and `amplifyLeft_star` into a single morphism. -/ +noncomputable def amplifyLeftₐ : + (H₁ →L[ℂ] H₁) →⋆ₐ[ℂ] (HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) where + toFun := amplifyLeft + map_one' := amplifyLeft_one + map_mul' := amplifyLeft_mul + map_zero' := amplifyLeft_zero + map_add' := amplifyLeft_add + commutes' r := by + rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, amplifyLeft_smul, + amplifyLeft_one] + map_star' A := (amplifyLeft_star A).symm + +omit [CompleteSpace H₂] in +@[simp] theorem amplifyLeftₐ_apply (A : H₁ →L[ℂ] H₁) : + amplifyLeftₐ (H₂ := H₂) A = amplifyLeft A := rfl + +omit [CompleteSpace H₁] in +/-- The **right amplification** `B ↦ 1 ⊗̂ B`, bundled as a unital `⋆`-algebra homomorphism +`B(H₂) →⋆ₐ[ℂ] B(HilbertTensor H₁ H₂)`. -/ +noncomputable def amplifyRightₐ : + (H₂ →L[ℂ] H₂) →⋆ₐ[ℂ] (HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) where + toFun := amplifyRight + map_one' := amplifyRight_one + map_mul' := amplifyRight_mul + map_zero' := amplifyRight_zero + map_add' := amplifyRight_add + commutes' r := by + rw [Algebra.algebraMap_eq_smul_one, Algebra.algebraMap_eq_smul_one, amplifyRight_smul, + amplifyRight_one] + map_star' B := (amplifyRight_star B).symm + +omit [CompleteSpace H₁] in +@[simp] theorem amplifyRightₐ_apply (B : H₂ →L[ℂ] H₂) : + amplifyRightₐ (H₁ := H₁) B = amplifyRight B := rfl + +end Adjoint + +/-! ### The tensor bridge `ℓ²(ι) ⊗̂ K ≃ lp (fun _ : ι => K) 2` + +The completed Hilbert tensor product of `ℓ²(ι) = lp (fun _ : ι => ℂ) 2` with a Hilbert space `K` +is, canonically, the `ℓ²` sum of `ι`-many copies of `K`. The isomorphism sends the pure tensor +`δᵢ ⊗ k` (with `δᵢ = lp.single 2 i 1` the `i`-th standard basis vector of `ℓ²(ι)`) to the single +`lp.single 2 i k`. It is built by exhibiting the inclusions `k ↦ δᵢ ⊗ k` as an orthogonal family +whose total span is dense, i.e. as a Hilbert sum (`IsHilbertSum`). -/ + +section LpTensorBridge + +open scoped ENNReal + +variable {ι : Type*} [DecidableEq ι] + {K : Type*} [NormedAddCommGroup K] [InnerProductSpace ℂ K] + +/-- The isometric inclusion `K → ℓ²(ι) ⊗̂ K`, `k ↦ δᵢ ⊗ k`, where `δᵢ = lp.single 2 i 1` is the +`i`-th standard basis vector of `ℓ²(ι) = lp (fun _ : ι => ℂ) 2`. As `δᵢ` is a unit vector this is a +genuine linear isometry; the family `i ↦ tmulSingleₗᵢ i` exhibits `ℓ²(ι) ⊗̂ K` as the Hilbert sum +of copies of `K`. -/ +noncomputable def tmulSingleₗᵢ (i : ι) : + K →ₗᵢ[ℂ] (lp (fun _ : ι => ℂ) 2) ⊗̂ K where + toFun k := tmul (lp.single 2 i (1 : ℂ)) k + map_add' k k' := tmul_add _ k k' + map_smul' c k := by + rw [RingHom.id_apply, tmul, tmul, TensorProduct.tmul_smul, UniformSpace.Completion.coe_smul] + norm_map' k := by + simp only [LinearMap.coe_mk, AddHom.coe_mk, norm_tmul] + rw [lp.norm_single (p := 2) (by norm_num), norm_one, one_mul] + +@[simp] theorem tmulSingleₗᵢ_apply (i : ι) (k : K) : + tmulSingleₗᵢ i k = tmul (lp.single 2 i (1 : ℂ)) k := by rfl + +/-- Distinct standard basis vectors of `ℓ²(ι)` are orthogonal, so the inclusions `tmulSingleₗᵢ` +form an orthogonal family. -/ +theorem orthogonalFamily_tmulSingleₗᵢ : + OrthogonalFamily ℂ (fun _ : ι => K) (fun i => tmulSingleₗᵢ (K := K) i) := by + intro i j hij k k' + have hδ : inner ℂ (lp.single 2 i (1 : ℂ) : lp (fun _ : ι => ℂ) 2) (lp.single 2 j (1 : ℂ)) = 0 := by + rw [lp.inner_single_left, lp.coeFn_single, Pi.single_eq_of_ne hij, inner_zero_right] + rw [tmulSingleₗᵢ_apply, tmulSingleₗᵢ_apply, inner_tmul, hδ, zero_mul] + +/-- The orthogonal family `tmulSingleₗᵢ` has dense total span, exhibiting `ℓ²(ι) ⊗̂ K` as the +Hilbert sum of `ι`-many copies of `K`. Density is proved by approximating a pure tensor +`a ⊗ k` (`a ∈ ℓ²(ι)`) by the convergent series `∑ᵢ (a i) • (δᵢ ⊗ k)`, each term of which lies in +the range of `tmulSingleₗᵢ i`. -/ +theorem isHilbertSum_tmulSingleₗᵢ [CompleteSpace K] : + IsHilbertSum ℂ (fun _ : ι => K) (fun i => tmulSingleₗᵢ (K := K) i) := by + haveI : ∀ _ : ι, CompleteSpace K := fun _ => inferInstance + refine IsHilbertSum.mk orthogonalFamily_tmulSingleₗᵢ ?_ + set M : Submodule ℂ (HilbertTensor (lp (fun _ : ι => ℂ) 2) K) := + ⨆ i, LinearMap.range (tmulSingleₗᵢ (K := K) i).toLinearMap with hM + have key : ∀ z : (lp (fun _ : ι => ℂ) 2) ⊗[ℂ] K, + ((z : HilbertTensor (lp (fun _ : ι => ℂ) 2) K)) ∈ M.topologicalClosure := by + intro z + induction z using TensorProduct.induction_on with + | zero => + rw [UniformSpace.Completion.coe_zero] + exact (M.topologicalClosure).zero_mem + | add p q hp hq => + rw [UniformSpace.Completion.coe_add] + exact (M.topologicalClosure).add_mem hp hq + | tmul a k => + change tmul a k ∈ M.topologicalClosure + have hsum : HasSum (fun i => tmul (lp.single 2 i (a i)) k) (tmul a k) := by + have h := (lp.hasSum_single (E := fun _ : ι => ℂ) (p := 2) (by norm_num) a).mapL + (tmulLeftL (H₁ := lp (fun _ : ι => ℂ) 2) (H₂ := K) k) + simpa only [tmulLeftL_apply] using h + have hmem : ∀ i, tmul (lp.single 2 i (a i)) k ∈ M := by + intro i + have heq : tmul (lp.single 2 i (a i)) k = (a i) • tmulSingleₗᵢ (K := K) i k := by + rw [tmulSingleₗᵢ_apply, + show (lp.single 2 i (a i) : lp (fun _ : ι => ℂ) 2) + = (a i) • lp.single 2 i (1 : ℂ) by + rw [← lp.single_smul, smul_eq_mul, mul_one], + tmul, tmul, ← TensorProduct.smul_tmul', UniformSpace.Completion.coe_smul] + rw [heq] + exact Submodule.smul_mem _ _ + (Submodule.mem_iSup_of_mem i (LinearMap.mem_range_self _ k)) + have hcl : tmul a k ∈ closure (M : Set (HilbertTensor (lp (fun _ : ι => ℂ) 2) K)) := + mem_closure_of_tendsto hsum + (Filter.Eventually.of_forall fun s => + SetLike.mem_coe.mpr (Submodule.sum_mem _ fun i _ => hmem i)) + rwa [← Submodule.topologicalClosure_coe, SetLike.mem_coe] at hcl + have hsub : Set.range ((↑) : (lp (fun _ : ι => ℂ) 2 ⊗[ℂ] K) → + HilbertTensor (lp (fun _ : ι => ℂ) 2) K) ⊆ (M.topologicalClosure : Set _) := by + rintro _ ⟨z, rfl⟩ + exact key z + rw [top_le_iff] + apply SetLike.coe_injective + rw [Submodule.top_coe] + apply Set.eq_univ_of_univ_subset + rw [← UniformSpace.Completion.denseRange_coe.closure_range] + exact closure_minimal hsub M.isClosed_topologicalClosure + +/-- **Tensor bridge.** The `ℓ²` sum of `ι`-many copies of a Hilbert space `K` is isometrically the +completed Hilbert tensor product `ℓ²(ι) ⊗̂ K`, where `ℓ²(ι) = lp (fun _ : ι => ℂ) 2`. Under the +bijection the single `lp.single 2 i k` corresponds to the pure tensor `δᵢ ⊗ k` +(`lpTensorEquiv_single`). -/ +noncomputable def lpTensorEquiv [CompleteSpace K] : + lp (fun _ : ι => K) 2 ≃ₗᵢ[ℂ] (lp (fun _ : ι => ℂ) 2) ⊗̂ K := + isHilbertSum_tmulSingleₗᵢ.linearIsometryEquiv.symm + +@[simp] theorem lpTensorEquiv_single [CompleteSpace K] (i : ι) (k : K) : + lpTensorEquiv (lp.single 2 i k) = (lp.single 2 i (1 : ℂ)) ⊗ₕ k := by + rw [lpTensorEquiv, + IsHilbertSum.linearIsometryEquiv_symm_apply_single isHilbertSum_tmulSingleₗᵢ, + tmulSingleₗᵢ_apply] + +end LpTensorBridge + +end HilbertTensor diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean new file mode 100644 index 0000000..41bbe5e --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -0,0 +1,188 @@ +module + +public import Mathlib.Analysis.VonNeumannAlgebra.Basic +public import Mathlib.Analysis.InnerProductSpace.Adjoint + +/-! +# The commutant of a set, the generated von Neumann algebra, and unitary conjugation + +Mathlib's `VonNeumannAlgebra.commutant` takes the commutant of a von Neumann algebra. This file +provides the companion constructions that take an *arbitrary* set of bounded operators, together +with the transport of a von Neumann algebra along a linear isometric equivalence: + +* `VonNeumannAlgebra.commutantSet s` — the commutant `s'` of a set `s`, as a von Neumann algebra. + The double-commutant property is automatic (`Set.centralizer_centralizer_centralizer`), and + `StarSubalgebra.centralizer` already symmetrises by `s ∪ star s`, so no self-adjointness + hypothesis is needed. +* `VonNeumannAlgebra.generated s` — the von Neumann algebra `s''` generated by `s`, defined as the + commutant of `commutantSet s`. +* `VonNeumannAlgebra.conj U N` — the spatial conjugate `U N U⋆` of a von Neumann algebra `N` on + `H` by a linear isometric equivalence `U : H ≃ₗᵢ H'`, a von Neumann algebra on `H'`. Conjugation + by the induced `*`-isomorphism `U.conjStarAlgEquiv` commutes with taking commutants + (`conj_commutant`), hence with the generated-algebra construction (`conj_generated`): this is the + statement that a unitary equivalence of representations carries `s''` to `(U s U⋆)''`. + +These let one build `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)` (and any concretely-generated von Neumann +algebra) without unfolding the bicommutant by hand, and transport the generation theorem +`N = ⟨matrix units⟩''` of a type I factor along the spatial isomorphism. + +## Notation + +The prime notation of the operator-algebra literature lives in the opt-in `VonNeumannAlgebra` +scope; activate it with `open scoped VonNeumannAlgebra`. + +| Symbol | Expansion | How to activate | +|---|---|---| +| `M′` | `VonNeumannAlgebra.commutant M` | `open scoped VonNeumannAlgebra` | +| `s″` | `VonNeumannAlgebra.generated s` | `open scoped VonNeumannAlgebra` | +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- The commutant `s'` of an arbitrary set of bounded operators, packaged as a von Neumann +algebra. -/ +noncomputable def commutantSet (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H where + toStarSubalgebra := StarSubalgebra.centralizer ℂ s + centralizer_centralizer' := by simp + +@[simp] theorem coe_commutantSet (s : Set (H →L[ℂ] H)) : + (commutantSet s : Set (H →L[ℂ] H)) = (s ∪ star s).centralizer := + StarSubalgebra.coe_centralizer ℂ s + +theorem mem_commutantSet_iff {s : Set (H →L[ℂ] H)} {z : H →L[ℂ] H} : + z ∈ commutantSet s ↔ ∀ g ∈ s, g * z = z * g ∧ star g * z = z * star g := + StarSubalgebra.mem_centralizer_iff ℂ + +/-- The von Neumann algebra `s''` generated by a set `s` of bounded operators, defined as the +commutant of its commutant. -/ +noncomputable def generated (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H := + (commutantSet s).commutant + +/-- `M′` denotes the commutant `VonNeumannAlgebra.commutant M`, the prime of the operator-algebra +literature. -/ +scoped postfix:max "′" => VonNeumannAlgebra.commutant + +/-- `s″` denotes the von Neumann algebra `VonNeumannAlgebra.generated s` generated by a set `s`, +the double prime `s''` of the operator-algebra literature. -/ +scoped postfix:max "″" => VonNeumannAlgebra.generated + +/-- The commutant of the generated von Neumann algebra `s''` is the commutant `s'`. -/ +@[simp] theorem commutant_generated (s : Set (H →L[ℂ] H)) : + (generated s).commutant = commutantSet s := + VonNeumannAlgebra.commutant_commutant (commutantSet s) + +/-- A set is contained in the von Neumann algebra it generates. -/ +theorem mem_generated_of_mem {s : Set (H →L[ℂ] H)} {x : H →L[ℂ] H} (hx : x ∈ s) : + x ∈ generated s := by + have h1 : x ∈ (commutantSet s : Set (H →L[ℂ] H)).centralizer := by + rw [coe_commutantSet] + exact Set.subset_centralizer_centralizer (Set.mem_union_left _ hx) + rwa [← VonNeumannAlgebra.coe_commutant] at h1 + +/-- Taking the commutant of von Neumann algebras is antitone. Named to match the Mathlib +`centralizer_le` family (`Subalgebra.centralizer_le`, `Subring.centralizer_le`, …). -/ +theorem commutant_le {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : + Q.commutant ≤ P.commutant := by + intro x hx + rw [← SetLike.mem_coe, VonNeumannAlgebra.coe_commutant] at hx ⊢ + exact Set.centralizer_subset (SetLike.coe_subset_coe.2 h) hx + +/-- The von Neumann algebra generated by `s` is the smallest von Neumann algebra containing `s`: +if a von Neumann algebra `M` contains `s`, then it contains `generated s`. -/ +theorem generated_le {s : Set (H →L[ℂ] H)} {M : VonNeumannAlgebra H} + (hsM : s ⊆ (M : Set (H →L[ℂ] H))) : generated s ≤ M := by + have hstar : s ∪ star s ⊆ (M : Set (H →L[ℂ] H)) := by + refine Set.union_subset hsM fun x hx => ?_ + rw [Set.mem_star] at hx + simpa using star_mem (hsM hx) + have h1 : M.commutant ≤ (generated s).commutant := by + rw [commutant_generated] + intro x hx + rw [← SetLike.mem_coe, coe_commutantSet] + rw [← SetLike.mem_coe, VonNeumannAlgebra.coe_commutant] at hx + exact Set.centralizer_subset hstar hx + have h2 := commutant_le h1 + rwa [VonNeumannAlgebra.commutant_commutant, VonNeumannAlgebra.commutant_commutant] at h2 + +/-! ### Unitary conjugation of a von Neumann algebra -/ + +/-- A multiplicative bijection carries the centralizer of a set onto the centralizer of the image: +`φ '' s' = (φ '' s)'`. This is the algebraic core of the fact that a spatial isomorphism commutes +with taking commutants. -/ +theorem image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] + [EquivLike F M₁ M₂] [MulEquivClass F M₁ M₂] (φ : F) (s : Set M₁) : + ⇑φ '' Set.centralizer s = Set.centralizer (⇑φ '' s) := by + ext y + simp only [Set.mem_image, Set.mem_centralizer_iff] + constructor + · rintro ⟨x, hx, rfl⟩ _ ⟨a, ha, rfl⟩ + rw [← map_mul, ← map_mul, hx a ha] + · intro hy + obtain ⟨x, rfl⟩ := EquivLike.surjective φ y + refine ⟨x, fun a ha => ?_, rfl⟩ + have h := hy (φ a) ⟨a, ha, rfl⟩ + apply EquivLike.injective φ + rw [map_mul, map_mul, h] + +variable {H' : Type*} [NormedAddCommGroup H'] [InnerProductSpace ℂ H'] [CompleteSpace H'] + +/-- The **spatial conjugate** `U N U⋆` of a von Neumann algebra `N ⊆ B(H)` by a linear isometric +equivalence `U : H ≃ₗᵢ H'`, as a von Neumann algebra on `H'`. This is the adjoint action `Ad U`, +written `U N U⋆` (and `U • N` in informal notes); since `U` is unitary, `U⋆ = U.symm`. Its carrier +is the image of `N` under the conjugation `*`-isomorphism `U.conjStarAlgEquiv : B(H) ≃⋆ₐ B(H')`; the +double-commutant property is inherited from `N` because conjugation commutes with taking +centralizers. -/ +noncomputable def conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : VonNeumannAlgebra H' where + toStarSubalgebra := + N.toStarSubalgebra.map (U.conjStarAlgEquiv : (H →L[ℂ] H) →⋆ₐ[ℂ] H' →L[ℂ] H') + centralizer_centralizer' := by + have hcoe : ((N.toStarSubalgebra.map + (U.conjStarAlgEquiv : (H →L[ℂ] H) →⋆ₐ[ℂ] H' →L[ℂ] H')).carrier) + = ⇑U.conjStarAlgEquiv '' (N : Set (H →L[ℂ] H)) := + StarSubalgebra.coe_map _ _ + rw [hcoe, ← image_centralizer, ← image_centralizer, N.centralizer_centralizer] + +@[simp] theorem coe_conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : + (conj U N : Set (H' →L[ℂ] H')) = ⇑U.conjStarAlgEquiv '' (N : Set (H →L[ℂ] H)) := + StarSubalgebra.coe_map _ _ + +/-- **Spatial conjugation is monotone.** If `P ≤ Q` then `U P U⋆ ≤ U Q U⋆`: conjugation transports +inclusions, since its carrier is the image of the carrier under `U.conjStarAlgEquiv`. -/ +theorem conj_mono (U : H ≃ₗᵢ[ℂ] H') {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : + conj U P ≤ conj U Q := by + intro x hx + rw [← SetLike.mem_coe, coe_conj] at hx ⊢ + exact Set.image_mono (SetLike.coe_subset_coe.2 h) hx + +/-- **Conjugation commutes with the commutant.** `(U N U⋆)' = U N' U⋆`. -/ +theorem conj_commutant (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : + (conj U N).commutant = conj U N.commutant := by + apply SetLike.coe_injective + rw [VonNeumannAlgebra.coe_commutant, coe_conj, coe_conj, VonNeumannAlgebra.coe_commutant, + image_centralizer] + +/-- **Conjugation commutes with the commutant of a set.** `U s' U⋆ = (U s U⋆)'`. -/ +theorem conj_commutantSet (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : + conj U (commutantSet s) = commutantSet (⇑U.conjStarAlgEquiv '' s) := by + have hstar : ⇑U.conjStarAlgEquiv '' star s = star (⇑U.conjStarAlgEquiv '' s) := by + ext z + simp only [Set.mem_image, Set.mem_star] + constructor + · rintro ⟨w, hw, rfl⟩ + exact ⟨star w, hw, by rw [map_star]⟩ + · rintro ⟨x, hx, hz⟩ + exact ⟨star x, by simpa using hx, by rw [map_star, hz, star_star]⟩ + apply SetLike.coe_injective + rw [coe_conj, coe_commutantSet, coe_commutantSet, image_centralizer, Set.image_union, hstar] + +/-- **Conjugation commutes with the generated von Neumann algebra.** A spatial isomorphism carries +`s''` to `(U s U⋆)''`: `U ⟨s⟩'' U⋆ = ⟨U s U⋆⟩''`. -/ +theorem conj_generated (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : + conj U (generated s) = generated (⇑U.conjStarAlgEquiv '' s) := by + rw [generated, ← conj_commutant, conj_commutantSet, generated] + +end VonNeumannAlgebra From 5b0eb76d16396abd3dbc84b43c1f80467bceeba9 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:13:01 +0000 Subject: [PATCH 044/113] refactor: move image_centralizer to ForMathlib and document symmetrized commutant Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 1 + .../ForMathlib/Algebra/Group/Center.lean | 31 +++++++++++++++ .../Analysis/VonNeumannAlgebra/Commutant.lean | 39 +++++++------------ 3 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 QuantumSystem/ForMathlib/Algebra/Group/Center.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 93c78ed..5bafddd 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -45,6 +45,7 @@ public import QuantumSystem.Analysis.Matrix.Pinching public import QuantumSystem.Analysis.Matrix.PosDef public import QuantumSystem.Channel public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar +public import QuantumSystem.ForMathlib.Algebra.Group.Center public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry public import QuantumSystem.ForMathlib.Analysis.Calculus.Deriv.Sign public import QuantumSystem.ForMathlib.Analysis.Complex.Basic diff --git a/QuantumSystem/ForMathlib/Algebra/Group/Center.lean b/QuantumSystem/ForMathlib/Algebra/Group/Center.lean new file mode 100644 index 0000000..2d8f898 --- /dev/null +++ b/QuantumSystem/ForMathlib/Algebra/Group/Center.lean @@ -0,0 +1,31 @@ +module + +public import Mathlib.Algebra.Group.Center +public import Mathlib.Algebra.Group.Equiv.Defs + +/-! +# Centralizers under multiplicative bijections + +A multiplicative bijection carries the centralizer of a set onto the centralizer of the image. +This is the algebraic core of the fact that a spatial isomorphism of von Neumann algebras +commutes with taking commutants. +-/ + +@[expose] public section + +/-- A multiplicative bijection carries the centralizer of a set onto the centralizer of the image: +`φ '' s' = (φ '' s)'`. -/ +theorem Set.image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] + [EquivLike F M₁ M₂] [MulEquivClass F M₁ M₂] (φ : F) (s : Set M₁) : + ⇑φ '' Set.centralizer s = Set.centralizer (⇑φ '' s) := by + ext y + simp only [Set.mem_image, Set.mem_centralizer_iff] + constructor + · rintro ⟨x, hx, rfl⟩ _ ⟨a, ha, rfl⟩ + rw [← map_mul, ← map_mul, hx a ha] + · intro hy + obtain ⟨x, rfl⟩ := EquivLike.surjective φ y + refine ⟨x, fun a ha => ?_, rfl⟩ + have h := hy (φ a) ⟨a, ha, rfl⟩ + apply EquivLike.injective φ + rw [map_mul, map_mul, h] diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean index 41bbe5e..33830ef 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -2,6 +2,7 @@ module public import Mathlib.Analysis.VonNeumannAlgebra.Basic public import Mathlib.Analysis.InnerProductSpace.Adjoint +public import QuantumSystem.ForMathlib.Algebra.Group.Center /-! # The commutant of a set, the generated von Neumann algebra, and unitary conjugation @@ -34,7 +35,7 @@ scope; activate it with `open scoped VonNeumannAlgebra`. | Symbol | Expansion | How to activate | |---|---|---| | `M′` | `VonNeumannAlgebra.commutant M` | `open scoped VonNeumannAlgebra` | -| `s″` | `VonNeumannAlgebra.generated s` | `open scoped VonNeumannAlgebra` | +| `s″` | `VonNeumannAlgebra.generated s`, i.e. `(s ∪ s⋆)''` | `open scoped VonNeumannAlgebra` | -/ @[expose] public section @@ -43,8 +44,11 @@ namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] -/-- The commutant `s'` of an arbitrary set of bounded operators, packaged as a von Neumann -algebra. -/ +/-- The commutant `(s ∪ s⋆)′` of the *symmetrized* set of an arbitrary set of bounded operators, +packaged as a von Neumann algebra. For star-closed `s` — in particular for every self-adjoint +generating set — this coincides with the commutant `s′` of the operator-algebra literature; for +non-star-closed `s` the literal `s′` is a larger, non-star-closed algebra, and symmetrizing is +what makes the construction land in `VonNeumannAlgebra H`. -/ noncomputable def commutantSet (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H where toStarSubalgebra := StarSubalgebra.centralizer ℂ s centralizer_centralizer' := by simp @@ -66,8 +70,9 @@ noncomputable def generated (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H := literature. -/ scoped postfix:max "′" => VonNeumannAlgebra.commutant -/-- `s″` denotes the von Neumann algebra `VonNeumannAlgebra.generated s` generated by a set `s`, -the double prime `s''` of the operator-algebra literature. -/ +/-- `s″` denotes the von Neumann algebra `VonNeumannAlgebra.generated s` generated by a set `s`. +For star-closed `s` this is the double prime `s''` of the operator-algebra literature; in general +it is `(s ∪ s⋆)''`, the smallest von Neumann algebra containing `s` (see `generated_le`). -/ scoped postfix:max "″" => VonNeumannAlgebra.generated /-- The commutant of the generated von Neumann algebra `s''` is the commutant `s'`. -/ @@ -110,24 +115,6 @@ theorem generated_le {s : Set (H →L[ℂ] H)} {M : VonNeumannAlgebra H} /-! ### Unitary conjugation of a von Neumann algebra -/ -/-- A multiplicative bijection carries the centralizer of a set onto the centralizer of the image: -`φ '' s' = (φ '' s)'`. This is the algebraic core of the fact that a spatial isomorphism commutes -with taking commutants. -/ -theorem image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] - [EquivLike F M₁ M₂] [MulEquivClass F M₁ M₂] (φ : F) (s : Set M₁) : - ⇑φ '' Set.centralizer s = Set.centralizer (⇑φ '' s) := by - ext y - simp only [Set.mem_image, Set.mem_centralizer_iff] - constructor - · rintro ⟨x, hx, rfl⟩ _ ⟨a, ha, rfl⟩ - rw [← map_mul, ← map_mul, hx a ha] - · intro hy - obtain ⟨x, rfl⟩ := EquivLike.surjective φ y - refine ⟨x, fun a ha => ?_, rfl⟩ - have h := hy (φ a) ⟨a, ha, rfl⟩ - apply EquivLike.injective φ - rw [map_mul, map_mul, h] - variable {H' : Type*} [NormedAddCommGroup H'] [InnerProductSpace ℂ H'] [CompleteSpace H'] /-- The **spatial conjugate** `U N U⋆` of a von Neumann algebra `N ⊆ B(H)` by a linear isometric @@ -144,7 +131,7 @@ noncomputable def conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : Von (U.conjStarAlgEquiv : (H →L[ℂ] H) →⋆ₐ[ℂ] H' →L[ℂ] H')).carrier) = ⇑U.conjStarAlgEquiv '' (N : Set (H →L[ℂ] H)) := StarSubalgebra.coe_map _ _ - rw [hcoe, ← image_centralizer, ← image_centralizer, N.centralizer_centralizer] + rw [hcoe, ← Set.image_centralizer, ← Set.image_centralizer, N.centralizer_centralizer] @[simp] theorem coe_conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : (conj U N : Set (H' →L[ℂ] H')) = ⇑U.conjStarAlgEquiv '' (N : Set (H →L[ℂ] H)) := @@ -163,7 +150,7 @@ theorem conj_commutant (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : (conj U N).commutant = conj U N.commutant := by apply SetLike.coe_injective rw [VonNeumannAlgebra.coe_commutant, coe_conj, coe_conj, VonNeumannAlgebra.coe_commutant, - image_centralizer] + Set.image_centralizer] /-- **Conjugation commutes with the commutant of a set.** `U s' U⋆ = (U s U⋆)'`. -/ theorem conj_commutantSet (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : @@ -177,7 +164,7 @@ theorem conj_commutantSet (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : · rintro ⟨x, hx, hz⟩ exact ⟨star x, by simpa using hx, by rw [map_star, hz, star_star]⟩ apply SetLike.coe_injective - rw [coe_conj, coe_commutantSet, coe_commutantSet, image_centralizer, Set.image_union, hstar] + rw [coe_conj, coe_commutantSet, coe_commutantSet, Set.image_centralizer, Set.image_union, hstar] /-- **Conjugation commutes with the generated von Neumann algebra.** A spatial isomorphism carries `s''` to `(U s U⋆)''`: `U ⟨s⟩'' U⋆ = ⟨U s U⋆⟩''`. -/ From 9ba28c97f32594bd1e11bce2a20278403891b833 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:15:14 +0000 Subject: [PATCH 045/113] refactor: derive hasSum_resolutionOfIdentity from coe_hilbertSumEquiv_apply Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- .../GeneratedByMatrixUnits.lean | 58 ++++--------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean index 93b7ffa..b084fb2 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean @@ -57,58 +57,20 @@ theorem OrthEquivFam.matrixUnit_subset (hF : OrthEquivFam N e F) : /-- **Resolution of the identity.** For a covering orthogonal family, the projections `↑i` sum to the identity in the strong operator sense: `HasSum (fun i : F => (↑i) y) y` for every `y`. This is -the analytic heart of the generation theorem; it is extracted from the internal Hilbert-sum -decomposition `H ≅ ℓ²(F; eᵢH)` by recognising the `i`-th Hilbert-sum coordinate of `y` as the -orthogonal projection `(↑i) y`. -/ +the analytic heart of the generation theorem; it is the Hilbert-sum reconstruction of `y` from its +coordinates, with the `i`-th coordinate recognised as the orthogonal projection `(↑i) y` by +`coe_hilbertSumEquiv_apply`. -/ theorem OrthEquivFam.hasSum_resolutionOfIdentity (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) (y : H) : HasSum (fun i : F => (i : H →L[ℂ] H) y) y := by - have hHS := hF.isHilbertSum htop have hdecomp : HasSum - (fun i : F => (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) i)) y := by - have h := hHS.hasSum_linearIsometryEquiv_symm (hHS.linearIsometryEquiv y) - rwa [LinearIsometryEquiv.symm_apply_apply] at h - have hWmem : ∀ j : F, - (LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) j) - ∈ LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H) := fun j => Submodule.coe_mem _ - have key : ∀ i : F, (i : H →L[ℂ] H) y - = (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i) := by - intro i - have happ := hdecomp.mapL (i : H →L[ℂ] H) - have hii : (i : H →L[ℂ] H) - ((LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ ((hHS.linearIsometryEquiv y) i)) - = (LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) i) := - (hF.1 i.1 i.2).1.apply_eq_self_of_mem_range (hWmem i) - have hsingle : HasSum - (fun j : F => (i : H →L[ℂ] H) - ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) j))) - ((i : H →L[ℂ] H) - ((LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) i))) := - hasSum_single i (fun j hj => by - have hjfix : (j : H →L[ℂ] H) - ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) j)) - = (LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) j) := - (hF.1 j.1 j.2).1.apply_eq_self_of_mem_range (hWmem j) - have hij0 : (i : H →L[ℂ] H) * (j : H →L[ℂ] H) = 0 := - hF.2 i.2 j.2 (fun h => hj (Subtype.ext h).symm) - calc (i : H →L[ℂ] H) - ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) j)) - = (i : H →L[ℂ] H) ((j : H →L[ℂ] H) - ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) j))) := by rw [hjfix] - _ = ((i : H →L[ℂ] H) * (j : H →L[ℂ] H)) - ((LinearMap.range ((j : H →L[ℂ] H) : H →ₗ[ℂ] H)).subtypeₗᵢ - ((hHS.linearIsometryEquiv y) j)) := rfl - _ = 0 := by rw [hij0]; rfl) - exact (happ.unique hsingle).trans hii - simpa only [key] using hdecomp + (fun i : F => ((hF.hilbertSumEquiv htop y i : + LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) : H)) y := by + have h := (hF.isHilbertSum htop).hasSum_linearIsometryEquiv_symm (hF.hilbertSumEquiv htop y) + have hy : (hF.isHilbertSum htop).linearIsometryEquiv.symm (hF.hilbertSumEquiv htop y) = y := + (hF.hilbertSumEquiv htop).symm_apply_apply y + rwa [hy] at h + simpa only [hF.coe_hilbertSumEquiv_apply htop y] using hdecomp /-- **The content of the generation theorem.** Any operator `b` commuting with every matrix unit commutes with every `a ∈ N`. Equivalently `Set.centralizer S ⊆ Set.centralizer N`, which is the From 4503fef47d9aecbf4b3e02463ecece44dd55378b Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:18:51 +0000 Subject: [PATCH 046/113] feat: strengthen spatial decomposition existentials to covering families of minimal projections Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- .../VonNeumannAlgebra/CoveringFamily.lean | 32 +++++++++++++++++++ .../SpatialDecomposition.lean | 31 +++++++++++------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean index a8e830f..82440e2 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean @@ -47,12 +47,44 @@ theorem MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} exact hpi.symm rw [← hvp, hv0]; simp +/-- **Minimality transports along Murray–von Neumann equivalence.** If `e` is a minimal projection +and `e ∼[N] p`, then `p` is minimal: with `v⋆v = e` and `vv⋆ = p`, the corner computes as +`p a p = v (e (v⋆ a v) e) v⋆ = c • v e v⋆ = c • p`. -/ +theorem IsMinimalProjection.of_mvNEquiv {N : VonNeumannAlgebra H} {e p : H →L[ℂ] H} + (he : IsMinimalProjection N e) (h : e ∼[N] p) : IsMinimalProjection N p := by + have hpproj : IsStarProjection p := h.isStarProjection_right + have hp0 : p ≠ 0 := h.ne_zero he.2.2.1 + obtain ⟨v, hvN, hvpi, hvp, hvq⟩ := h + have hpN : p ∈ N := by rw [← hvq]; exact mul_mem hvN (star_mem hvN) + have hve : v * e = v := by rw [← hvp]; exact IsPartialIsometry.mul_source hvpi + have hev : e * star v = star v := by + have := congrArg star hve + rwa [star_mul, he.1.isSelfAdjoint.star_eq] at this + refine ⟨hpproj, hpN, hp0, fun a haN => ?_⟩ + obtain ⟨c, hc⟩ := he.2.2.2 (star v * a * v) (mul_mem (mul_mem (star_mem hvN) haN) hvN) + refine ⟨c, ?_⟩ + calc p * a * p + = (v * star v) * a * (v * star v) := by rw [hvq] + _ = (v * e) * (star v * a * v) * (e * star v) := by + rw [hve, hev]; simp only [mul_assoc] + _ = v * (e * (star v * a * v) * e) * star v := by simp only [mul_assoc] + _ = v * (c • e) * star v := by rw [hc] + _ = c • (v * e * star v) := by simp only [mul_smul_comm, smul_mul_assoc] + _ = c • p := by rw [hve, hvq] + /-- A family of pairwise-orthogonal nonzero projections in `N`, each Murray–von Neumann equivalent to `e`. -/ def OrthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ℂ] H)) : Prop := (∀ p ∈ F, IsStarProjection p ∧ p ∈ N ∧ p ≠ 0 ∧ e ∼[N] p) ∧ F.Pairwise (fun p q => p * q = 0) +/-- When `e` is minimal, every member of an `OrthEquivFam` for `e` is itself a minimal +projection, since minimality transports along `∼[N]` (`IsMinimalProjection.of_mvNEquiv`). -/ +theorem OrthEquivFam.isMinimalProjection_of_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) + {p : H →L[ℂ] H} (hp : p ∈ F) : IsMinimalProjection N p := + he.of_mvNEquiv (hF.1 p hp).2.2.2 + /-- By Zorn's lemma, there is a maximal orthogonal family of `e`-equivalent projections. -/ theorem exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : ∃ F, OrthEquivFam N e F ∧ ∀ G, OrthEquivFam N e G → F ⊆ G → G ⊆ F := by diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean index d4d6b94..5dc206e 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean @@ -287,31 +287,38 @@ theorem OrthEquivFam.coe_hilbertSumEquiv_apply {N : VonNeumannAlgebra H} {e : H /-- The minimal projection `e` of a type I factor is the multiplicity space: a type I factor with minimal projection `e` acts on a Hilbert space isometric to the `ℓ²` sum `ℓ²(F; eH)` of copies of -`eH = range e`, indexed by a maximal orthogonal family `F` of minimal projections equivalent to -`e`. Composing with the tensor bridge turns this `ℓ²` sum into the literal tensor product -`H ≅ ℓ²(F) ⊗̂ eH`; see `exists_tmul_decomposition`. -/ +`eH = range e`, indexed by a covering orthogonal family `F` (`OrthEquivFam`, with densely +spanning ranges) of minimal projections equivalent to `e`. Composing with the tensor bridge turns +this `ℓ²` sum into the literal tensor product `H ≅ ℓ²(F) ⊗̂ eH`; see +`exists_tmul_decomposition`. -/ theorem IsFactor.exists_tensor_decomposition [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : - ∃ (F : Set (H →L[ℂ] H)), + ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ + (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ ∧ + (∀ p ∈ F, IsMinimalProjection N p) ∧ Nonempty (H ≃ₗᵢ[ℂ] lp (fun _ : F => LinearMap.range (e : H →ₗ[ℂ] H)) 2) := by obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he - exact ⟨F, ⟨hF.multiplicityEquiv htop⟩⟩ + exact ⟨F, hF, htop, fun p hp => hF.isMinimalProjection_of_mem he hp, + ⟨hF.multiplicityEquiv htop⟩⟩ /-- **Tensor-product decomposition (literal form).** A type I factor `N ⊆ B(H)` with minimal projection `e` acts on a Hilbert space isometric to the completed Hilbert tensor product -`ℓ²(F) ⊗̂ (eH)`, where `F` is a maximal orthogonal family of minimal projections equivalent to `e` -and `eH = range e` is the multiplicity space. This is the literal `H ≅ ℓ²(F) ⊗̂ eH` form of the -type I structure theorem, obtained from `exists_tensor_decomposition` by composing with the tensor -bridge `HilbertTensor.lpTensorEquiv`. -/ +`ℓ²(F) ⊗̂ (eH)`, where `F` is a covering orthogonal family (`OrthEquivFam`, with densely spanning +ranges) of minimal projections equivalent to `e` and `eH = range e` is the multiplicity space. +This is the literal `H ≅ ℓ²(F) ⊗̂ eH` form of the type I structure theorem, obtained from +`exists_tensor_decomposition` by composing with the tensor bridge `HilbertTensor.lpTensorEquiv`. -/ theorem IsFactor.exists_tmul_decomposition [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : - ∃ (F : Set (H →L[ℂ] H)), + ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ + (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ ∧ + (∀ p ∈ F, IsMinimalProjection N p) ∧ Nonempty (H ≃ₗᵢ[ℂ] HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))) := by obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range haveI : DecidableEq (↥F) := Classical.decEq _ - exact ⟨F, ⟨(hF.multiplicityEquiv htop).trans - (HilbertTensor.lpTensorEquiv (ι := F) (K := LinearMap.range (e : H →ₗ[ℂ] H)))⟩⟩ + exact ⟨F, hF, htop, fun p hp => hF.isMinimalProjection_of_mem he hp, + ⟨(hF.multiplicityEquiv htop).trans + (HilbertTensor.lpTensorEquiv (ι := F) (K := LinearMap.range (e : H →ₗ[ℂ] H)))⟩⟩ end VonNeumannAlgebra From ebdb16e28c23d678b0d4cc5b27ebe42916373a13 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:19:57 +0000 Subject: [PATCH 047/113] refactor: move Hilbert tensor factors to VonNeumannAlgebra.TensorFactor Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 2 +- .../TensorFactor.lean} | 0 .../Algebra/VonNeumannAlgebra/TensorIdentification.lean | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename QuantumSystem/Algebra/{Star/TensorProduct.lean => VonNeumannAlgebra/TensorFactor.lean} (100%) diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 5bafddd..df2c20a 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -22,7 +22,6 @@ public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra -public import QuantumSystem.Algebra.Star.TensorProduct public import QuantumSystem.Algebra.VonNeumannAlgebra.CentralProjection public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily @@ -30,6 +29,7 @@ public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor public import QuantumSystem.Algebra.VonNeumannAlgebra.GeneratedByMatrixUnits public import QuantumSystem.Algebra.VonNeumannAlgebra.MatrixUnits public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition +public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification public import QuantumSystem.Analysis.CFC.Diagonal public import QuantumSystem.Analysis.Entropy.KroneckerProduct diff --git a/QuantumSystem/Algebra/Star/TensorProduct.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean similarity index 100% rename from QuantumSystem/Algebra/Star/TensorProduct.lean rename to QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean index 59f9eb4..6471dca 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean @@ -1,7 +1,7 @@ module public import QuantumSystem.Algebra.VonNeumannAlgebra.GeneratedByMatrixUnits -public import QuantumSystem.Algebra.Star.TensorProduct +public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor /-! # Spatial identification of a type I factor with `B(H₁) ⊗̄ 1` @@ -11,7 +11,7 @@ projection `e`: there is a linear isometric equivalence `U : H ≃ₗᵢ ℓ²(F becomes exactly the tensor factor `B(ℓ²(F)) ⊗̄ 1` and `N'` becomes the right factor `1 ⊗̄ B(eH)`. The identification glues the generation theorem `N = ⟨matrix units⟩''` (`GeneratedByMatrixUnits`) -to the tensor commutation theorem (`Algebra.Star.TensorProduct`) through the spatial isomorphism +to the tensor commutation theorem (`Algebra.VonNeumannAlgebra.TensorFactor`) through the spatial isomorphism `U = multiplicityEquiv ∘ lpTensorEquiv`. The key computation is that `U` carries the matrix unit `e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨δ_q| ⊗̂ 1`, where `δ_p = lp.single 2 p 1` is the `p`-th standard basis vector of `ℓ²(F)`. From 08ed8640279b46b1b8895b5ab017300c0f659201 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:27:28 +0000 Subject: [PATCH 048/113] feat: prove the tensor von Neumann algebras are factors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 1 + .../VonNeumannAlgebra/TensorFactor.lean | 128 ++++++++++++++++-- .../TensorIdentification.lean | 10 +- .../Analysis/InnerProductSpace/RankOne.lean | 37 +++++ 4 files changed, 155 insertions(+), 21 deletions(-) create mode 100644 QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index df2c20a..f29258d 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -58,6 +58,7 @@ public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.WeakDual public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.DiagonalAmplification public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.InvariantSubspace +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.RankOne public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.StrongOperatorTopology diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index 2c2fb2f..a1c9e93 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -1,7 +1,9 @@ module +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.RankOne public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor public import Mathlib.Analysis.InnerProductSpace.Adjoint /-! @@ -33,8 +35,10 @@ the first leg): the commutant of `B(H₁)⊗̄1` is exactly `1⊗̄B(H₂)`. * `HilbertTensor.amplifyLeft_comp_amplifyRight` — the two amplifications commute. * `HilbertTensor.mem_vnTensorRight_of_commutes` — the slice lemma: an operator commuting with all `A ⊗̂ 1` is of the form `1 ⊗̂ S`. -* `HilbertTensor.vnTensorLeft_commutant` — the tensor commutation theorem - `(B(H₁)⊗̄1)' = 1⊗̄B(H₂)`. +* `HilbertTensor.vnTensorLeft_commutant` / `vnTensorRight_commutant` — the tensor commutation + theorem `(B(H₁)⊗̄1)' = 1⊗̄B(H₂)` and its bicommutant companion. +* `HilbertTensor.isFactor_vnTensorLeft` / `isFactor_vnTensorRight` — both tensor algebras are + factors: their common centre is trivial. -/ @[expose] public section @@ -48,12 +52,14 @@ variable {H₁ H₂ : Type*} [NormedAddCommGroup H₂] [InnerProductSpace ℂ H₂] /-- The von Neumann factor `B(H₁) ⊗̄ 1` acting on `HilbertTensor H₁ H₂`: the von Neumann algebra -generated by the image of the left amplification `A ↦ A ⊗̂ 1`. -/ +generated by the image of the left amplification `A ↦ A ⊗̂ 1`. Factor-ness is proved in +`isFactor_vnTensorLeft` (for complete legs and nontrivial `H₁`). -/ noncomputable def vnTensorLeft : VonNeumannAlgebra (HilbertTensor H₁ H₂) := VonNeumannAlgebra.generated (Set.range (amplifyLeft (H₂ := H₂))) /-- The von Neumann factor `1 ⊗̄ B(H₂)` acting on `HilbertTensor H₁ H₂`: the von Neumann algebra -generated by the image of the right amplification `B ↦ 1 ⊗̂ B`. -/ +generated by the image of the right amplification `B ↦ 1 ⊗̂ B`. Factor-ness is proved in +`isFactor_vnTensorRight` (for complete legs and nontrivial `H₁`). -/ noncomputable def vnTensorRight : VonNeumannAlgebra (HilbertTensor H₁ H₂) := VonNeumannAlgebra.generated (Set.range (amplifyRight (H₁ := H₁))) @@ -144,17 +150,17 @@ theorem amplifyLeft_rankOne_eq (e f : H₁) : tmul_smul_left, smul_tmul_right] | add p q hp hq => rw [UniformSpace.Completion.coe_add, map_add, map_add, hp, hq] -/-- **Slice lemma (dense form).** If `T` commutes with the rank-one amplifications -`(|f⟩⟨e|) ⊗̂ 1` for `f` ranging over a set `D` whose span is dense in `H₁` (and a fixed unit vector -`e ∈ H₁`), then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e`, hence `T ∈ 1 ⊗̄ B(H₂)`. The relation +/-- **Slice lemma (dense form, explicit representation).** If `T` commutes with the rank-one +amplifications `(|f⟩⟨e|) ⊗̂ 1` for `f` ranging over a set `D` whose span is dense in `H₁` (and a +fixed unit vector `e ∈ H₁`), then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e`. The relation `T (f ⊗̂ y) = f ⊗̂ (S y)` is first established for `f ∈ D` and then extended to all `f` by density, working at the level of the bounded inclusions `ι_y : f ↦ f ⊗̂ y`. -/ -theorem mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) +theorem exists_amplifyRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) (hD : Dense (Submodule.span ℂ D : Set H₁)) (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) (hT : ∀ f ∈ D, T.comp (amplifyLeft (InnerProductSpace.rankOne ℂ f e)) = (amplifyLeft (InnerProductSpace.rankOne ℂ f e)).comp T) : - T ∈ vnTensorRight := by + ∃ S : H₂ →L[ℂ] H₂, T = amplifyRight S := by set S := (ContinuousLinearMap.adjoint (tmulRightL e)).comp (T.comp (tmulRightL e)) with hS have hee : inner ℂ e e = (1 : ℂ) := by rw [inner_self_eq_norm_sq_to_K, he]; norm_num have key : ∀ f ∈ D, ∀ y : H₂, T (tmul f y) = tmul f (S y) := by @@ -188,19 +194,39 @@ theorem mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : S change T (tmul f y) = amplifyRight S (tmul f y) rw [key_all, amplifyRight_tmul] | add p q hp hq => rw [UniformSpace.Completion.coe_add, map_add, map_add, hp, hq] - rw [hTS] + exact ⟨S, hTS⟩ + +/-- **Slice lemma (dense form).** If `T` commutes with the rank-one amplifications +`(|f⟩⟨e|) ⊗̂ 1` for `f` ranging over a set `D` whose span is dense in `H₁` (and a fixed unit +vector `e ∈ H₁`), then `T = 1 ⊗̂ S`, hence `T ∈ 1 ⊗̄ B(H₂)`. -/ +theorem mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) + (hD : Dense (Submodule.span ℂ D : Set H₁)) + (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) + (hT : ∀ f ∈ D, T.comp (amplifyLeft (InnerProductSpace.rankOne ℂ f e)) + = (amplifyLeft (InnerProductSpace.rankOne ℂ f e)).comp T) : + T ∈ vnTensorRight := by + obtain ⟨S, rfl⟩ := exists_amplifyRight_of_commutes_dense e he D hD T hT exact amplifyRight_mem_vnTensorRight S +/-- **Slice lemma (explicit representation).** If `T` commutes with every left amplification +`A ⊗̂ 1`, then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e` (any unit vector `e ∈ H₁`). -/ +theorem exists_amplifyRight_of_commutes (e : H₁) (he : ‖e‖ = 1) + (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) + (hT : ∀ A : H₁ →L[ℂ] H₁, T.comp (amplifyLeft A) = (amplifyLeft A).comp T) : + ∃ S : H₂ →L[ℂ] H₂, T = amplifyRight S := + exists_amplifyRight_of_commutes_dense e he Set.univ + (by rw [Submodule.span_univ, Submodule.top_coe]; exact dense_univ) T + (fun f _ => hT (InnerProductSpace.rankOne ℂ f e)) + /-- **Slice lemma (hard inclusion of the commutation theorem).** If `T` commutes with every left amplification `A ⊗̂ 1`, then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e` (any unit vector `e ∈ H₁`), hence `T ∈ 1 ⊗̄ B(H₂)`. -/ theorem mem_vnTensorRight_of_commutes (e : H₁) (he : ‖e‖ = 1) (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) (hT : ∀ A : H₁ →L[ℂ] H₁, T.comp (amplifyLeft A) = (amplifyLeft A).comp T) : - T ∈ vnTensorRight := - mem_vnTensorRight_of_commutes_dense e he Set.univ - (by rw [Submodule.span_univ, Submodule.top_coe]; exact dense_univ) T - (fun f _ => hT (InnerProductSpace.rankOne ℂ f e)) + T ∈ vnTensorRight := by + obtain ⟨S, rfl⟩ := exists_amplifyRight_of_commutes e he T hT + exact amplifyRight_mem_vnTensorRight S end CompleteRight @@ -236,4 +262,78 @@ theorem vnTensorLeft_commutant [CompleteSpace H₁] [CompleteSpace H₂] [Nontri · rw [amplifyLeft_star, ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] exact amplifyLeft_comp_amplifyRight (star A) B +/-- The commutant of `1 ⊗̄ B(H₂)` is exactly `B(H₁) ⊗̄ 1`: the bicommutant form of the tensor +commutation theorem `vnTensorLeft_commutant`. -/ +theorem vnTensorRight_commutant [CompleteSpace H₁] [CompleteSpace H₂] [Nontrivial H₁] : + (vnTensorRight (H₁ := H₁) (H₂ := H₂)).commutant = vnTensorLeft := by + rw [← vnTensorLeft_commutant, VonNeumannAlgebra.commutant_commutant] + +/-! ### The tensor factors are factors -/ + +/-- The right amplification `B ↦ 1 ⊗̂ B` is injective (for nontrivial `H₁`): evaluating on pure +tensors `f ⊗̂ y` with `f ≠ 0` recovers `B y` up to the norm factor `‖f‖`. -/ +theorem amplifyRight_injective [Nontrivial H₁] : + Function.Injective (amplifyRight (H₁ := H₁) (H₂ := H₂)) := by + intro B₁ B₂ h + obtain ⟨f, hf⟩ := exists_ne (0 : H₁) + ext y + have h1 := congrArg + (fun L : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂ => L (tmul f y)) h + simp only [amplifyRight_tmul] at h1 + have h2 : tmul f (B₁ y - B₂ y) = 0 := by + rw [sub_eq_add_neg, tmul_add, ← neg_one_smul ℂ (B₂ y), smul_tmul_right, h1, neg_one_smul, + add_neg_cancel] + have h3 : ‖f‖ * ‖B₁ y - B₂ y‖ = 0 := by rw [← norm_tmul, h2, norm_zero] + rcases mul_eq_zero.mp h3 with h4 | h4 + · exact absurd (norm_eq_zero.mp h4) hf + · exact sub_eq_zero.mp (norm_eq_zero.mp h4) + +/-- **The centre of the tensor decomposition is trivial.** An operator lying in both +`B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)` is a scalar: by the slice lemma it is `1 ⊗̂ S`, membership in +`B(H₁) ⊗̄ 1 = (1 ⊗̄ B(H₂))'` makes `S` commute with all of `B(H₂)` — in particular with every +rank-one operator — so `S` is scalar. -/ +theorem eq_smul_one_of_mem_vnTensorLeft_of_mem_vnTensorRight + [CompleteSpace H₁] [CompleteSpace H₂] [Nontrivial H₁] + {x : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂} + (hL : x ∈ vnTensorLeft (H₁ := H₁) (H₂ := H₂)) (hR : x ∈ vnTensorRight) : + ∃ c : ℂ, x = c • 1 := by + obtain ⟨u, hu⟩ := exists_ne (0 : H₁) + have he : ‖(‖u‖⁻¹ : ℂ) • u‖ = 1 := by + rw [norm_smul, norm_inv, Complex.norm_real, norm_norm, + inv_mul_cancel₀ (norm_ne_zero_iff.mpr hu)] + have hx' : x ∈ VonNeumannAlgebra.commutantSet (Set.range (amplifyLeft (H₂ := H₂))) := by + rw [← vnTensorLeft_commutant_eq_commutantSet, vnTensorLeft_commutant] + exact hR + obtain ⟨S, rfl⟩ := exists_amplifyRight_of_commutes _ he x fun A => by + have hc := (VonNeumannAlgebra.mem_commutantSet_iff.mp hx' (amplifyLeft A) ⟨A, rfl⟩).1 + rw [← ContinuousLinearMap.mul_def, ← ContinuousLinearMap.mul_def] + exact hc.symm + have hS : ∀ B : H₂ →L[ℂ] H₂, S * B = B * S := by + intro B + have hmem : amplifyRight (H₁ := H₁) S ∈ vnTensorRight.commutant := by + rw [vnTensorRight_commutant]; exact hL + have h1 := VonNeumannAlgebra.mem_commutant_iff.mp hmem (amplifyRight B) + (amplifyRight_mem_vnTensorRight B) + apply amplifyRight_injective (H₁ := H₁) + rw [amplifyRight_mul, amplifyRight_mul] + exact h1.symm + obtain ⟨c, hc⟩ := + ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm (S := S) fun a b => by + rw [← ContinuousLinearMap.mul_def, ← ContinuousLinearMap.mul_def] + exact hS (InnerProductSpace.rankOne ℂ a b) + exact ⟨c, by rw [hc, amplifyRight_smul, amplifyRight_one]⟩ + +/-- **`B(H₁) ⊗̄ 1` is a factor**: its centre is trivial, since by the commutation theorem the +centre is `(B(H₁) ⊗̄ 1) ⊓ (1 ⊗̄ B(H₂))`. -/ +theorem isFactor_vnTensorLeft [CompleteSpace H₁] [CompleteSpace H₂] [Nontrivial H₁] : + VonNeumannAlgebra.IsFactor (vnTensorLeft (H₁ := H₁) (H₂ := H₂)) := fun _ hx hx' => + eq_smul_one_of_mem_vnTensorLeft_of_mem_vnTensorRight hx (by rwa [← vnTensorLeft_commutant]) + +/-- **`1 ⊗̄ B(H₂)` is a factor**: its centre is trivial, since by the commutation theorem the +centre is `(B(H₁) ⊗̄ 1) ⊓ (1 ⊗̄ B(H₂))`. (Nontriviality of `H₁` is what the commutation theorem +consumes; `H₂` may be arbitrary.) -/ +theorem isFactor_vnTensorRight [CompleteSpace H₁] [CompleteSpace H₂] [Nontrivial H₁] : + VonNeumannAlgebra.IsFactor (vnTensorRight (H₁ := H₁) (H₂ := H₂)) := fun _ hx hx' => + eq_smul_one_of_mem_vnTensorLeft_of_mem_vnTensorRight (by rwa [← vnTensorRight_commutant]) hx + end HilbertTensor diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean index 6471dca..faa4bfc 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean @@ -241,13 +241,9 @@ theorem generated_amplifyLeft_rankOne_eq [Nonempty F] [DecidableEq F] haveI : Nontrivial (lp (fun _ : F => ℂ) 2) := ⟨lpDelta (Classical.arbitrary F), 0, by rw [← norm_ne_zero_iff, lpDelta_norm]; norm_num⟩ - have hcc : (vnTensorRight (H₁ := lp (fun _ : F => ℂ) 2) - (H₂ := LinearMap.range (e : H →ₗ[ℂ] H))).commutant = vnTensorLeft := - (congrArg VonNeumannAlgebra.commutant - (vnTensorLeft_commutant (H₁ := lp (fun _ : F => ℂ) 2) - (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)))).symm.trans - (VonNeumannAlgebra.commutant_commutant _) - exact (congrArg VonNeumannAlgebra.commutant hcomm).trans hcc + exact (congrArg VonNeumannAlgebra.commutant hcomm).trans + (vnTensorRight_commutant (H₁ := lp (fun _ : F => ℂ) 2) + (H₂ := LinearMap.range (e : H →ₗ[ℂ] H))) /-- **Type I factor structure theorem (explicit identification).** Under the spatial isomorphism `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)`, the type I factor `N` is carried exactly onto the tensor factor diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean new file mode 100644 index 0000000..909b3c0 --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean @@ -0,0 +1,37 @@ +module + +public import Mathlib.Analysis.InnerProductSpace.LinearMap + +/-! +# Operators commuting with all rank-one operators are scalar + +A continuous linear operator on an inner product space that commutes with every rank-one operator +`|x⟩⟨y|` is a scalar multiple of the identity. This is the elementary computation behind +"the centre of `B(H)` is trivial" and, downstream, behind the factor property of the tensor +von Neumann algebras `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)`. +-/ + +@[expose] public section + +/-- A continuous linear operator commuting with every rank-one operator `|x⟩⟨y|` is a scalar +multiple of the identity: testing the commutation relation on a fixed nonzero vector `y` yields +`⟪y, y⟫ • S x = ⟪y, S y⟫ • x` for *every* `x`, so `S = (⟪y, S y⟫ / ⟪y, y⟫) • 1`. -/ +theorem ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm + {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] {S : H →L[ℂ] H} + (h : ∀ x y : H, S ∘L InnerProductSpace.rankOne ℂ x y + = InnerProductSpace.rankOne ℂ x y ∘L S) : + ∃ c : ℂ, S = c • 1 := by + by_cases hH : ∀ y : H, y = 0 + · refine ⟨0, ContinuousLinearMap.ext fun x => ?_⟩ + rw [hH x] + simp + push Not at hH + obtain ⟨y, hy⟩ := hH + have hyy : (inner ℂ y y : ℂ) ≠ 0 := inner_self_ne_zero.mpr hy + refine ⟨inner ℂ y (S y) / inner ℂ y y, ContinuousLinearMap.ext fun x => ?_⟩ + have h1 := congrArg (fun L : H →L[ℂ] H => L y) (h x y) + simp only [ContinuousLinearMap.comp_apply, InnerProductSpace.rankOne_apply, map_smul] at h1 + rw [ContinuousLinearMap.smul_apply, ContinuousLinearMap.one_apply] + calc S x = (inner ℂ y y)⁻¹ • ((inner ℂ y y : ℂ) • S x) := (inv_smul_smul₀ hyy _).symm + _ = (inner ℂ y y)⁻¹ • (inner ℂ y (S y) • x) := by rw [h1] + _ = (inner ℂ y (S y) / inner ℂ y y) • x := by rw [smul_smul, div_eq_inv_mul] From 4097ef7a502b0cc85a7a4c60719c4a4814fef3e6 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:32:36 +0000 Subject: [PATCH 049/113] feat: add abelian projections and the general type I property Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 1 + .../Algebra/VonNeumannAlgebra/Factor.lean | 19 ++- .../Algebra/VonNeumannAlgebra/TypeI.lean | 113 ++++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index f29258d..b47fb1c 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -31,6 +31,7 @@ public import QuantumSystem.Algebra.VonNeumannAlgebra.MatrixUnits public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification +public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI public import QuantumSystem.Analysis.CFC.Diagonal public import QuantumSystem.Analysis.Entropy.KroneckerProduct public import QuantumSystem.Analysis.Entropy.MutualInformation diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean index 59d85fc..5de4334 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean @@ -85,9 +85,26 @@ theorem IsMinimalProjection.no_proper_subprojection {N : VonNeumannAlgebra H} · exact Or.inl (by rw [hc, h, zero_smul]) · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) +/-- An **abelian projection** of `N`: a star projection `p ∈ N` whose corner `p N p` is +commutative. Minimal projections are abelian (`IsMinimalProjection.isAbelianProjection`); the +general type I property (`IsTypeI`) is phrased through abelian projections. -/ +def IsAbelianProjection (N : VonNeumannAlgebra H) (p : H →L[ℂ] H) : Prop := + IsStarProjection p ∧ p ∈ N ∧ + ∀ a ∈ N, ∀ b ∈ N, (p * a * p) * (p * b * p) = (p * b * p) * (p * a * p) + +/-- A minimal projection is abelian: its corner `e N e = ℂ e` is one-dimensional, hence +commutative. -/ +theorem IsMinimalProjection.isAbelianProjection {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) : IsAbelianProjection N e := by + refine ⟨he.1, he.2.1, fun a haN b hbN => ?_⟩ + obtain ⟨c, hc⟩ := he.2.2.2 a haN + obtain ⟨d, hd⟩ := he.2.2.2 b hbN + rw [hc, hd, smul_mul_smul_comm, smul_mul_smul_comm, mul_comm c d] + /-- A **type I factor**: a factor possessing a minimal projection. This is the mathematically conventional, intrinsic definition; the spatial decomposition `N ≅ B(H₁) ⊗̄ 1` is then a theorem, -not part of the definition. -/ +not part of the definition. The equivalence with the general abelian-projection definition +`IsTypeI` is `isTypeIFactor_iff_isFactor_and_isTypeI`. -/ def IsTypeIFactor (N : VonNeumannAlgebra H) : Prop := IsFactor N ∧ ∃ e : H →L[ℂ] H, IsMinimalProjection N e diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean new file mode 100644 index 0000000..8b670ad --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -0,0 +1,113 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison + +/-! +# Type I von Neumann algebras + +The general **type I** property, phrased as in the literature (Takesaki V.1, Blackadar III.1.5): +every nonzero central projection dominates a nonzero abelian projection. For a *factor* this is +equivalent to the existence of a minimal projection, i.e. to `IsTypeIFactor`; this file proves +the easy direction (minimal ⇒ abelian ⇒ type I) and the order-minimality of abelian projections +in a factor, the first half of the converse. The remaining half (order-minimal ⇒ corner-scalar) +and the assembled equivalence `IsFactor N → (IsTypeI N ↔ ∃ e, IsMinimalProjection N e)` are the +subject of the continuous-functional-calculus development that follows. + +## Main definitions + +* `VonNeumannAlgebra.IsTypeI N` — every nonzero central projection of `N` dominates a nonzero + abelian projection. + +## Main results + +* `VonNeumannAlgebra.IsFactor.isTypeI_of_exists_isMinimalProjection` — a factor with a minimal + projection is type I. +* `VonNeumannAlgebra.IsFactor.subprojection_eq_of_isAbelianProjection` — in a factor, an abelian + projection has no proper nonzero subprojection. +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- **Type I von Neumann algebra**: every nonzero central projection dominates a nonzero abelian +projection. The subprojection relation `p ≤ z` is written algebraically as `z * p = p`, as +everywhere in this development. -/ +def IsTypeI (N : VonNeumannAlgebra H) : Prop := + ∀ z : H →L[ℂ] H, IsCentralProjection N z → z ≠ 0 → + ∃ p : H →L[ℂ] H, IsAbelianProjection N p ∧ p ≠ 0 ∧ z * p = p + +/-- A factor with a minimal projection is type I: the only nonzero central projection of a factor +is `1` (`central_projection_eq`), and it dominates the minimal projection, which is abelian and +nonzero. -/ +theorem IsFactor.isTypeI_of_exists_isMinimalProjection [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) (h : ∃ e : H →L[ℂ] H, IsMinimalProjection N e) : IsTypeI N := by + obtain ⟨e, he⟩ := h + intro z hz hz0 + rcases hN.central_projection_eq hz with h0 | h1 + · exact absurd h0 hz0 + · exact ⟨e, he.isAbelianProjection, he.2.2.1, by rw [h1, one_mul]⟩ + +/-- **In a factor, an abelian projection is order-minimal**: a projection `q ∈ N` with `q ≤ p` +(written `p * q = q`) is `0` or `p`. + +The proof avoids corner-commutant theory and polar decomposition: if `0 ≠ q ≠ p`, then +`r := p - q` is a nonzero projection under `p` orthogonal to `q`, and the central-support lemma +`IsFactor.exists_mul_ne` produces `a ∈ N` with `z := r a q ≠ 0`. Both `z` and `z⋆` are corner +elements of `p`, so they commute by abelianness; but `q z = 0` and `q z⋆ = z⋆` force +`z⋆ z = q (z z⋆) = (q z) z⋆ = 0`, and the C⋆-identity gives `z = 0` — a contradiction. -/ +theorem IsFactor.subprojection_eq_of_isAbelianProjection [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {p : H →L[ℂ] H} (hp : IsAbelianProjection N p) + {q : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (hsub : p * q = q) : + q = 0 ∨ q = p := by + by_cases hq0 : q = 0 + · exact Or.inl hq0 + by_cases hqp : q = p + · exact Or.inr hqp + exfalso + have hqmul : q * p = q := isStarProjection_subproj_comm hp.1 hq hsub + set r : H →L[ℂ] H := p - q with hr + have hpr : p * r = r := by + rw [hr, mul_sub, hp.1.isIdempotentElem, hsub] + have hqr : q * r = 0 := by + rw [hr, mul_sub, hqmul, hq.isIdempotentElem, sub_self] + have hrsa : star r = r := by + rw [hr, star_sub, hp.1.isSelfAdjoint.star_eq, hq.isSelfAdjoint.star_eq] + have hrN : r ∈ N := sub_mem hp.2.1 hqN + have hr0 : r ≠ 0 := fun h0 => hqp (by rw [hr, sub_eq_zero] at h0; exact h0.symm) + obtain ⟨a, haN, hz0⟩ := hN.exists_mul_ne hqN hq0 hr0 + set z : H →L[ℂ] H := r * a * q with hz + have hzN : z ∈ N := mul_mem (mul_mem hrN haN) hqN + have hzcorner : p * z * p = z := by + rw [hz] + calc p * (r * a * q) * p + = (p * r) * a * (q * p) := by simp only [mul_assoc] + _ = r * a * q := by rw [hpr, hqmul] + have hzstar : star z = q * (star a * r) := by + rw [hz, star_mul, star_mul, hrsa, hq.isSelfAdjoint.star_eq] + have hcomm : z * star z = star z * z := by + have hzc : p * star z * p = star z := by + have h2 := congrArg star hzcorner + rw [star_mul, star_mul, hp.1.isSelfAdjoint.star_eq] at h2 + rw [mul_assoc] + exact h2 + have h1 := hp.2.2 z hzN (star z) (star_mem hzN) + rwa [hzcorner, hzc] at h1 + have hqz : q * z = 0 := by + rw [hz, ← mul_assoc, ← mul_assoc, hqr, zero_mul, zero_mul] + have hqstarz : q * star z = star z := by + rw [hzstar, ← mul_assoc, hq.isIdempotentElem] + have hzz0 : star z * z = 0 := by + have h6 : q * (z * star z) = q * (star z * z) := by rw [hcomm] + rw [← mul_assoc, hqz, zero_mul] at h6 + rw [← mul_assoc, hqstarz] at h6 + exact h6.symm + have hznorm : ‖z‖ = 0 := by + have hmul := CStarRing.norm_star_mul_self (x := z) + rw [hzz0, norm_zero] at hmul + exact mul_self_eq_zero.mp hmul.symm + exact hz0 (norm_eq_zero.mp hznorm) + +end VonNeumannAlgebra From 24bd242c196c272604ca10780ad7b8bc191c5e4e Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 10:56:53 +0000 Subject: [PATCH 050/113] feat: prove type I iff minimal projection for factors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- .../Algebra/VonNeumannAlgebra/TypeI.lean | 473 +++++++++++++++++- .../Analysis/VonNeumannAlgebra/Commutant.lean | 8 + 2 files changed, 474 insertions(+), 7 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean index 8b670ad..2e55b51 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -1,29 +1,46 @@ module public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import Mathlib.Analysis.InnerProductSpace.Projection.Basic +public import Mathlib.Analysis.InnerProductSpace.StarOrder +public import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.PosPart.Basic +public import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Range +public import Mathlib.LinearAlgebra.Complex.Module /-! # Type I von Neumann algebras The general **type I** property, phrased as in the literature (Takesaki V.1, Blackadar III.1.5): every nonzero central projection dominates a nonzero abelian projection. For a *factor* this is -equivalent to the existence of a minimal projection, i.e. to `IsTypeIFactor`; this file proves -the easy direction (minimal ⇒ abelian ⇒ type I) and the order-minimality of abelian projections -in a factor, the first half of the converse. The remaining half (order-minimal ⇒ corner-scalar) -and the assembled equivalence `IsFactor N → (IsTypeI N ↔ ∃ e, IsMinimalProjection N e)` are the -subject of the continuous-functional-calculus development that follows. +equivalent to the existence of a minimal projection, i.e. to `IsTypeIFactor`. The equivalence is +proved in full: the easy direction is minimal ⇒ abelian ⇒ type I; the converse first shows that +an abelian projection of a factor is order-minimal (a corner-commutation argument through the +central-support lemma `IsFactor.exists_mul_ne`), then that order-minimality forces the trivial +corner `p N p = ℂ p` — the positive/negative parts of a self-adjoint corner element (non-unital +continuous functional calculus inside the norm-closed corner subalgebra) yield an order +dichotomy, and a Dedekind-cut argument on `{c : ℝ | 0 ≤ x - c • p}` pins each self-adjoint +corner element to a real multiple of `p`. ## Main definitions * `VonNeumannAlgebra.IsTypeI N` — every nonzero central projection of `N` dominates a nonzero abelian projection. +* `VonNeumannAlgebra.cornerNonUnitalStarSubalgebra N hp` — the norm-closed corner `{y ∈ N | p y + = y = y p}`. ## Main results -* `VonNeumannAlgebra.IsFactor.isTypeI_of_exists_isMinimalProjection` — a factor with a minimal - projection is type I. * `VonNeumannAlgebra.IsFactor.subprojection_eq_of_isAbelianProjection` — in a factor, an abelian projection has no proper nonzero subprojection. +* `VonNeumannAlgebra.isMinimalProjection_of_forall_subprojection` — order-minimality implies the + trivial corner. +* `VonNeumannAlgebra.IsFactor.isMinimalProjection_of_isAbelianProjection` — in a factor, a + nonzero abelian projection is minimal. +* `VonNeumannAlgebra.IsFactor.isTypeI_iff_exists_isMinimalProjection` — a factor is type I iff + it has a minimal projection. +* `VonNeumannAlgebra.isTypeIFactor_iff_isFactor_and_isTypeI` — `IsTypeIFactor N ↔ IsFactor N ∧ + IsTypeI N`. -/ @[expose] public section @@ -110,4 +127,446 @@ theorem IsFactor.subprojection_eq_of_isAbelianProjection [Nontrivial H] {N : Von exact mul_self_eq_zero.mp hmul.symm exact hz0 (norm_eq_zero.mp hznorm) +/-! ### The corner subalgebra + +The elements of `N` supported on a star projection `p` on both sides form a norm-closed +non-unital star subalgebra. Norm-closedness is what lets the non-unital continuous functional +calculus (`cfcₙ_mem`) operate inside the corner: the positive and negative parts of a +self-adjoint corner element stay in the corner. -/ + +/-- The **corner** of `N` at a star projection `p`: the elements of `N` supported on `p` on +both sides, as a non-unital star subalgebra of `B(H)`. -/ +def cornerNonUnitalStarSubalgebra (N : VonNeumannAlgebra H) {p : H →L[ℂ] H} + (hp : IsStarProjection p) : NonUnitalStarSubalgebra ℂ (H →L[ℂ] H) where + carrier := {y | y ∈ N ∧ p * y = y ∧ y * p = y} + add_mem' := by + rintro y z ⟨hyN, hpy, hyp⟩ ⟨hzN, hpz, hzp⟩ + exact ⟨add_mem hyN hzN, by rw [mul_add, hpy, hpz], by rw [add_mul, hyp, hzp]⟩ + zero_mem' := ⟨zero_mem _, mul_zero p, zero_mul p⟩ + mul_mem' := by + rintro y z ⟨hyN, hpy, hyp⟩ ⟨hzN, hpz, hzp⟩ + exact ⟨mul_mem hyN hzN, by rw [← mul_assoc, hpy], by rw [mul_assoc, hzp]⟩ + smul_mem' := by + rintro c y ⟨hyN, hpy, hyp⟩ + exact ⟨smul_mem c hyN, by rw [mul_smul_comm, hpy], by rw [smul_mul_assoc, hyp]⟩ + star_mem' := by + rintro y ⟨hyN, hpy, hyp⟩ + refine ⟨star_mem hyN, ?_, ?_⟩ + · have h := congrArg star hyp + rwa [star_mul, hp.isSelfAdjoint.star_eq] at h + · have h := congrArg star hpy + rwa [star_mul, hp.isSelfAdjoint.star_eq] at h + +/-- Membership in the corner subalgebra, unfolded. -/ +theorem mem_cornerNonUnitalStarSubalgebra_iff {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + {hp : IsStarProjection p} {y : H →L[ℂ] H} : + y ∈ cornerNonUnitalStarSubalgebra N hp ↔ y ∈ N ∧ p * y = y ∧ y * p = y := + Iff.rfl + +/-- The corner subalgebra is norm-closed: it is the intersection of the (double-centralizer, +hence closed) carrier of `N` with the closed support conditions `p * y = y` and `y * p = y`. -/ +theorem isClosed_cornerNonUnitalStarSubalgebra (N : VonNeumannAlgebra H) {p : H →L[ℂ] H} + (hp : IsStarProjection p) : + IsClosed ((cornerNonUnitalStarSubalgebra N hp : Set (H →L[ℂ] H))) := by + have hset : (cornerNonUnitalStarSubalgebra N hp : Set (H →L[ℂ] H)) + = (N : Set (H →L[ℂ] H)) ∩ ({y | p * y = y} ∩ {y | y * p = y}) := by + ext y + exact ⟨fun ⟨h1, h2, h3⟩ => ⟨h1, h2, h3⟩, fun ⟨h1, h2, h3⟩ => ⟨h1, h2, h3⟩⟩ + rw [hset] + refine N.isClosed_coe.inter (IsClosed.inter ?_ ?_) + · exact isClosed_eq (continuous_const.mul continuous_id) continuous_id + · exact isClosed_eq (continuous_id.mul continuous_const) continuous_id + +/-- The positive part of a corner element stays in the corner. -/ +theorem posPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + (hp : IsStarProjection p) {d : H →L[ℂ] H} + (hd : d ∈ cornerNonUnitalStarSubalgebra N hp) : + d⁺ ∈ cornerNonUnitalStarSubalgebra N hp := by + haveI : IsClosed ((cornerNonUnitalStarSubalgebra N hp : Set (H →L[ℂ] H))) := + isClosed_cornerNonUnitalStarSubalgebra N hp + haveI : IsScalarTower ℝ ℂ (H →L[ℂ] H) := IsScalarTower.complexToReal + rw [CFC.posPart_def] + exact cfcₙ_mem _ hd + +/-- The negative part of a corner element stays in the corner. -/ +theorem negPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + (hp : IsStarProjection p) {d : H →L[ℂ] H} + (hd : d ∈ cornerNonUnitalStarSubalgebra N hp) : + d⁻ ∈ cornerNonUnitalStarSubalgebra N hp := by + haveI : IsClosed ((cornerNonUnitalStarSubalgebra N hp : Set (H →L[ℂ] H))) := + isClosed_cornerNonUnitalStarSubalgebra N hp + haveI : IsScalarTower ℝ ℂ (H →L[ℂ] H) := IsScalarTower.complexToReal + rw [CFC.negPart_def] + exact cfcₙ_mem _ hd + +/-! ### Range projections + +For `x ∈ N`, the orthogonal projection onto the closure of `range x` lies in `N`; it is nonzero +when `x` is, it is dominated by any projection acting as the identity on the left of `x`, and the +range projections of two operators with `x₁ x₂ = 0`, `x₁` self-adjoint, are orthogonal. -/ + +/-- The orthogonal projection onto the closure of the range of `x ∈ N` lies in `N`, because that +subspace is invariant under the commutant. -/ +theorem starProjection_range_mem {N : VonNeumannAlgebra H} {x : H →L[ℂ] H} (hx : x ∈ N) : + (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection ∈ N := by + set M : Submodule ℂ H := (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure with hM + have hpproj : IsStarProjection M.starProjection := isStarProjection_starProjection + rw [IsStarProjection.mem_iff hpproj N] + intro y hyN' + rw [Submodule.range_starProjection] + have hcl : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by + rw [Submodule.comap_coe] + exact ((LinearMap.range (x : H →ₗ[ℂ] H)).isClosed_topologicalClosure).preimage y.continuous + have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by + refine Submodule.topologicalClosure_minimal _ ?_ hcl + rintro z ⟨v, rfl⟩ + simp only [Submodule.mem_comap, ContinuousLinearMap.coe_coe] + have hxy : x * y = y * x := mem_commutant_iff.mp hyN' x hx + rw [show y (x v) = (y * x) v from rfl, ← hxy] + exact Submodule.le_topologicalClosure _ ⟨y v, rfl⟩ + exact hle + +/-- The range projection of a nonzero operator is nonzero. -/ +theorem starProjection_range_ne_zero {x : H →L[ℂ] H} (hx0 : x ≠ 0) : + (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection ≠ 0 := by + intro h0 + apply hx0 + ext v + have hmem : x v ∈ (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure := + Submodule.le_topologicalClosure _ ⟨v, rfl⟩ + have hfix := Submodule.starProjection_eq_self_iff.mpr hmem + rw [h0] at hfix + simpa using hfix.symm + +/-- If `p * x = x`, then the range projection of `x` is a subprojection of `p`. -/ +theorem starProjection_range_subproj {p x : H →L[ℂ] H} (hpx : p * x = x) : + p * (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection + = (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection := by + set M : Submodule ℂ H := (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure with hM + have hle : M ≤ LinearMap.ker ((p - 1 : H →L[ℂ] H) : H →ₗ[ℂ] H) := by + refine Submodule.topologicalClosure_minimal _ ?_ (p - 1).isClosed_ker + rintro z ⟨v, rfl⟩ + simp only [LinearMap.mem_ker, ContinuousLinearMap.coe_coe, ContinuousLinearMap.sub_apply, + ContinuousLinearMap.one_apply] + rw [show p (x v) = (p * x) v from rfl, hpx] + exact sub_self _ + ext w + have hker := hle (M.starProjection_apply_mem w) + simp only [LinearMap.mem_ker, ContinuousLinearMap.coe_coe, ContinuousLinearMap.sub_apply, + ContinuousLinearMap.one_apply, sub_eq_zero] at hker + exact hker + +/-- The range projections of `x₁` and `x₂` with `x₁` self-adjoint and `x₁ * x₂ = 0` are +orthogonal. -/ +theorem starProjection_range_mul_eq_zero {x₁ x₂ : H →L[ℂ] H} (hsa : star x₁ = x₁) + (h12 : x₁ * x₂ = 0) : + (LinearMap.range (x₁ : H →ₗ[ℂ] H)).topologicalClosure.starProjection + * (LinearMap.range (x₂ : H →ₗ[ℂ] H)).topologicalClosure.starProjection = 0 := by + set M₁ : Submodule ℂ H := (LinearMap.range (x₁ : H →ₗ[ℂ] H)).topologicalClosure with hM₁ + set M₂ : Submodule ℂ H := (LinearMap.range (x₂ : H →ₗ[ℂ] H)).topologicalClosure with hM₂ + have hadj : ContinuousLinearMap.adjoint x₁ = x₁ := by + rw [← ContinuousLinearMap.star_eq_adjoint, hsa] + have hortho : M₂ ⟂ M₁ := by + rw [Submodule.isOrtho_iff_le] + refine Submodule.topologicalClosure_minimal _ ?_ M₁.isClosed_orthogonal + rintro z ⟨u, rfl⟩ + rw [Submodule.mem_orthogonal] + intro m hm + have hker : M₁ ≤ LinearMap.ker ((innerSL ℂ (x₂ u)) : H →ₗ[ℂ] ℂ) := by + refine Submodule.topologicalClosure_minimal _ ?_ (innerSL ℂ _).isClosed_ker + rintro w ⟨v, rfl⟩ + simp only [LinearMap.mem_ker, ContinuousLinearMap.coe_coe, innerSL_apply_apply] + rw [← ContinuousLinearMap.adjoint_inner_left x₁, hadj, + show x₁ (x₂ u) = (x₁ * x₂) u from rfl, h12] + simp + have h0 := hker hm + simp only [LinearMap.mem_ker, ContinuousLinearMap.coe_coe, innerSL_apply_apply] at h0 + exact inner_eq_zero_symm.mp h0 + rw [ContinuousLinearMap.mul_def] + exact Submodule.starProjection_comp_starProjection_eq_zero_iff.mpr hortho.symm + +/-! ### Order-minimality implies corner triviality + +The dichotomy: a self-adjoint corner element of an order-minimal projection is comparable to `0` +in the Loewner order, because its positive and negative parts would otherwise produce two +orthogonal nonzero subprojections of `p`. A Dedekind-cut argument on +`{c : ℝ | 0 ≤ x - c • p}` then pins every self-adjoint corner element to `x = c₀ • p`. -/ + +/-- **Dichotomy.** If `p` has no proper nonzero subprojection in `N`, every self-adjoint corner +element `d` satisfies `0 ≤ d` or `d ≤ 0`. -/ +theorem nonneg_or_nonpos_of_forall_subprojection {N : VonNeumannAlgebra H} + {p : H →L[ℂ] H} (hp : IsStarProjection p) (hp0 : p ≠ 0) + (hmin : ∀ q, IsStarProjection q → q ∈ N → p * q = q → q = 0 ∨ q = p) + {d : H →L[ℂ] H} (hdsa : IsSelfAdjoint d) + (hd : d ∈ cornerNonUnitalStarSubalgebra N hp) : + 0 ≤ d ∨ d ≤ 0 := by + have hdplus := posPart_mem_cornerNonUnitalStarSubalgebra hp hd + have hdminus := negPart_mem_cornerNonUnitalStarSubalgebra hp hd + have hsub : d⁺ - d⁻ = d := CFC.posPart_sub_negPart d hdsa + by_cases hplus0 : d⁺ = 0 + · right + rw [← hsub, hplus0, zero_sub] + exact neg_nonpos.mpr (CFC.negPart_nonneg d) + by_cases hminus0 : d⁻ = 0 + · left + rw [← hsub, hminus0, sub_zero] + exact CFC.posPart_nonneg d + exfalso + have hPplus := hmin _ isStarProjection_starProjection (starProjection_range_mem hdplus.1) + (starProjection_range_subproj hdplus.2.1) + have hPminus := hmin _ isStarProjection_starProjection (starProjection_range_mem hdminus.1) + (starProjection_range_subproj hdminus.2.1) + rcases hPplus with h | hPp + · exact starProjection_range_ne_zero hplus0 h + rcases hPminus with h | hPm + · exact starProjection_range_ne_zero hminus0 h + have horth := starProjection_range_mul_eq_zero + (CFC.posPart_nonneg d).isSelfAdjoint.star_eq (CFC.posPart_mul_negPart d) + rw [hPp, hPm, hp.isIdempotentElem] at horth + exact hp0 horth + +/-- **Cut.** If `p` has no proper nonzero subprojection in `N`, every self-adjoint corner +element is a real multiple of `p`: the supremum `c₀` of `{c : ℝ | 0 ≤ x - c • p}` (nonempty, +bounded, closed) satisfies `x = c₀ • p`, since by the dichotomy `x - c • p ≤ 0` for every +`c > c₀`. -/ +theorem exists_real_smul_eq_of_forall_subprojection {N : VonNeumannAlgebra H} + {p : H →L[ℂ] H} (hp : IsStarProjection p) (hpN : p ∈ N) (hp0 : p ≠ 0) + (hmin : ∀ q, IsStarProjection q → q ∈ N → p * q = q → q = 0 ∨ q = p) + {x : H →L[ℂ] H} (hxsa : IsSelfAdjoint x) + (hx : x ∈ cornerNonUnitalStarSubalgebra N hp) : + ∃ c : ℝ, x = (c : ℂ) • p := by + obtain ⟨hxN, hpx, hxp⟩ := hx + -- positivity of a self-adjoint operator through diagonal inner products + have hpos_iff : ∀ T : H →L[ℂ] H, IsSelfAdjoint T → + (0 ≤ T ↔ ∀ v, 0 ≤ RCLike.re (inner ℂ (T v) v)) := by + intro T hT + rw [ContinuousLinearMap.nonneg_iff_isPositive, ContinuousLinearMap.isPositive_def'] + simp only [ContinuousLinearMap.reApplyInnerSelf_apply] + exact ⟨fun h => h.2, fun h => ⟨hT, h⟩⟩ + have hsa_c : ∀ c : ℝ, IsSelfAdjoint (x - (c : ℂ) • p) := by + intro c + rw [IsSelfAdjoint, star_sub, star_smul, hxsa.star_eq, hp.isSelfAdjoint.star_eq, + Complex.star_def, Complex.conj_ofReal] + have hcalc : ∀ (c : ℝ) (v : H), RCLike.re (inner ℂ ((x - (c : ℂ) • p) v) v) + = RCLike.re (inner ℂ (x v) v) - c * RCLike.re (inner ℂ (p v) v) := by + intro c v + rw [ContinuousLinearMap.sub_apply, ContinuousLinearMap.smul_apply, inner_sub_left, + inner_smul_left, Complex.conj_ofReal, map_sub, + show RCLike.re ((c : ℂ) * inner ℂ (p v) v) = c * RCLike.re (inner ℂ (p v) v) from + RCLike.re_ofReal_mul c _] + have hpvv : ∀ v, RCLike.re (inner ℂ (p v) v) = ‖p v‖ ^ 2 := by + intro v + have h1 : inner ℂ (p v) v = inner ℂ (p v) (p v) := by + calc inner ℂ (p v) v = inner ℂ (p (p v)) v := by + rw [show p (p v) = (p * p) v from rfl, hp.isIdempotentElem] + _ = inner ℂ (ContinuousLinearMap.adjoint p (p v)) v := by + rw [hp.isSelfAdjoint.adjoint_eq] + _ = inner ℂ (p v) (p v) := ContinuousLinearMap.adjoint_inner_left p v (p v) + rw [h1, inner_self_eq_norm_sq] + -- the cut set + set A : Set ℝ := {c : ℝ | 0 ≤ x - (c : ℂ) • p} with hA + have hmemA : ∀ c : ℝ, c ∈ A ↔ + ∀ v, c * ‖p v‖ ^ 2 ≤ RCLike.re (inner ℂ (x v) v) := by + intro c + rw [hA, Set.mem_setOf_eq, hpos_iff _ (hsa_c c)] + constructor + · intro h v + have := h v + rw [hcalc, hpvv, sub_nonneg] at this + exact this + · intro h v + rw [hcalc, hpvv, sub_nonneg] + exact h v + -- `x` is supported on the corner: `re ⟪x v, v⟫ = re ⟪x (p v), p v⟫` + have hxvv : ∀ v, RCLike.re (inner ℂ (x v) v) = RCLike.re (inner ℂ (x (p v)) (p v)) := by + intro v + have h1 : x v = x (p v) := by rw [← ContinuousLinearMap.mul_apply, hxp] + have h2 : x (p v) = p (x (p v)) := by + rw [show p (x (p v)) = (p * x) (p v) from rfl, hpx] + calc RCLike.re (inner ℂ (x v) v) = RCLike.re (inner ℂ (p (x (p v))) v) := by + conv_lhs => rw [h1, h2] + _ = RCLike.re (inner ℂ (x (p v)) (p v)) := by + have h3 : inner ℂ (p (x (p v))) v = inner ℂ (x (p v)) (p v) := by + conv_lhs => rw [show p (x (p v)) = ContinuousLinearMap.adjoint p (x (p v)) by + rw [hp.isSelfAdjoint.adjoint_eq]] + exact ContinuousLinearMap.adjoint_inner_left p v (x (p v)) + rw [h3] + -- nonempty: `-‖x‖ ∈ A` + have hAne : A.Nonempty := by + refine ⟨-‖x‖, (hmemA _).mpr fun v => ?_⟩ + rw [hxvv] + have hbound : |RCLike.re (inner ℂ (x (p v)) (p v))| ≤ ‖x‖ * ‖p v‖ ^ 2 := by + calc |RCLike.re (inner ℂ (x (p v)) (p v))| ≤ ‖inner ℂ (x (p v)) (p v)‖ := + RCLike.abs_re_le_norm _ + _ ≤ ‖x (p v)‖ * ‖p v‖ := norm_inner_le_norm _ _ + _ ≤ (‖x‖ * ‖p v‖) * ‖p v‖ := + mul_le_mul_of_nonneg_right (x.le_opNorm _) (norm_nonneg _) + _ = ‖x‖ * ‖p v‖ ^ 2 := by ring + calc -‖x‖ * ‖p v‖ ^ 2 = -(‖x‖ * ‖p v‖ ^ 2) := by ring + _ ≤ RCLike.re (inner ℂ (x (p v)) (p v)) := neg_le_of_abs_le hbound + -- bounded above + have hAbdd : BddAbove A := by + obtain ⟨w, hw⟩ : ∃ w, p w ≠ 0 := by + by_contra hcon + push Not at hcon + exact hp0 (ContinuousLinearMap.ext fun w => by simp [hcon w]) + refine ⟨RCLike.re (inner ℂ (x w) w) / ‖p w‖ ^ 2, fun c hc => ?_⟩ + have h1 := (hmemA c).mp hc w + have h2 : (0 : ℝ) < ‖p w‖ ^ 2 := by positivity + exact (le_div_iff₀ h2).mpr h1 + -- closed + have hAclosed : IsClosed A := by + have hAeq : A = ⋂ v : H, + {c : ℝ | c * ‖p v‖ ^ 2 ≤ RCLike.re (inner ℂ (x v) v)} := by + ext c + simp only [Set.mem_iInter, Set.mem_setOf_eq, ← hmemA c] + rw [hAeq] + exact isClosed_iInter fun v => + isClosed_le (continuous_id.mul continuous_const) continuous_const + set c₀ : ℝ := sSup A with hc₀ + have hc₀A : c₀ ∈ A := hAclosed.csSup_mem hAne hAbdd + refine ⟨c₀, ?_⟩ + -- for every `c > c₀`, the dichotomy forces `x - c • p ≤ 0` + have hpmem : p ∈ cornerNonUnitalStarSubalgebra N hp := + ⟨hpN, hp.isIdempotentElem, hp.isIdempotentElem⟩ + have hupper : ∀ ε : ℝ, 0 < ε → x - ((c₀ + ε : ℝ) : ℂ) • p ≤ 0 := by + intro ε hε + have hnotA : (c₀ + ε) ∉ A := fun hmem => + absurd (le_csSup hAbdd hmem) (by rw [← hc₀]; linarith) + have hdmem : x - ((c₀ + ε : ℝ) : ℂ) • p ∈ cornerNonUnitalStarSubalgebra N hp := + sub_mem ⟨hxN, hpx, hxp⟩ (SMulMemClass.smul_mem _ hpmem) + rcases nonneg_or_nonpos_of_forall_subprojection hp hp0 hmin (hsa_c _) hdmem with h | h + · exact absurd h hnotA + · exact h + -- `{c | x - c • p ≤ 0}` is pointwise-characterised, hence closed; it contains `(c₀, ∞)`, + -- hence its closure point `c₀` + have hnegpos_iff : ∀ c : ℝ, (x - (c : ℂ) • p ≤ 0) ↔ + ∀ v, RCLike.re (inner ℂ (x v) v) ≤ c * ‖p v‖ ^ 2 := by + intro c + have hsa' : IsSelfAdjoint ((c : ℂ) • p - x) := by + rw [IsSelfAdjoint, star_sub, star_smul, hxsa.star_eq, hp.isSelfAdjoint.star_eq, + Complex.star_def, Complex.conj_ofReal] + rw [ContinuousLinearMap.le_def, zero_sub, neg_sub, + ← ContinuousLinearMap.nonneg_iff_isPositive, hpos_iff _ hsa'] + have hstep : ∀ v, RCLike.re (inner ℂ (((c : ℂ) • p - x) v) v) + = c * ‖p v‖ ^ 2 - RCLike.re (inner ℂ (x v) v) := by + intro v + rw [ContinuousLinearMap.sub_apply, ContinuousLinearMap.smul_apply, inner_sub_left, + inner_smul_left, Complex.conj_ofReal, map_sub, + show RCLike.re ((c : ℂ) * inner ℂ (p v) v) = c * RCLike.re (inner ℂ (p v) v) from + RCLike.re_ofReal_mul c _, hpvv] + constructor + · intro h v + have := h v + rw [hstep, sub_nonneg] at this + exact this + · intro h v + rw [hstep, sub_nonneg] + exact h v + have hBclosed : IsClosed {c : ℝ | x - (c : ℂ) • p ≤ 0} := by + have hBeq : {c : ℝ | x - (c : ℂ) • p ≤ 0} + = ⋂ v : H, {c : ℝ | RCLike.re (inner ℂ (x v) v) ≤ c * ‖p v‖ ^ 2} := by + ext c + simp only [Set.mem_setOf_eq, Set.mem_iInter, hnegpos_iff c] + rw [hBeq] + exact isClosed_iInter fun v => + isClosed_le continuous_const (continuous_id.mul continuous_const) + have hIoi : Set.Ioi c₀ ⊆ {c : ℝ | x - (c : ℂ) • p ≤ 0} := by + intro c hc + have h := hupper (c - c₀) (sub_pos.mpr hc) + rw [show c₀ + (c - c₀) = c by ring] at h + exact h + have hc₀B : x - (c₀ : ℂ) • p ≤ 0 := by + have h1 : Set.Ici c₀ ⊆ {c : ℝ | x - (c : ℂ) • p ≤ 0} := by + rw [← closure_Ioi] + exact closure_minimal hIoi hBclosed + exact h1 Set.self_mem_Ici + have hge : (0 : H →L[ℂ] H) ≤ x - (c₀ : ℂ) • p := hc₀A + exact sub_eq_zero.mp (le_antisymm hc₀B hge) + +/-- **Order-minimality implies corner triviality**: a nonzero star projection `p ∈ N` with no +proper nonzero subprojection in `N` is a minimal projection, i.e. `p N p = ℂ p`. Self-adjoint +corner elements are real multiples of `p` by the cut lemma +(`exists_real_smul_eq_of_forall_subprojection`); a general corner element decomposes into real +and imaginary self-adjoint parts. -/ +theorem isMinimalProjection_of_forall_subprojection {N : VonNeumannAlgebra H} + {p : H →L[ℂ] H} (hp : IsStarProjection p) (hpN : p ∈ N) (hp0 : p ≠ 0) + (hmin : ∀ q, IsStarProjection q → q ∈ N → p * q = q → q = 0 ∨ q = p) : + IsMinimalProjection N p := by + refine ⟨hp, hpN, hp0, fun a haN => ?_⟩ + have hymem : p * a * p ∈ cornerNonUnitalStarSubalgebra N hp := by + refine ⟨mul_mem (mul_mem hpN haN) hpN, ?_, ?_⟩ + · calc p * (p * a * p) = (p * p) * a * p := by simp only [mul_assoc] + _ = p * a * p := by rw [hp.isIdempotentElem] + · rw [mul_assoc (p * a) p p, hp.isIdempotentElem] + set s : H →L[ℂ] H := star (p * a * p) with hs + have hsmem : s ∈ cornerNonUnitalStarSubalgebra N hp := star_mem hymem + have hy₁mem : (2⁻¹ : ℂ) • (p * a * p + s) ∈ cornerNonUnitalStarSubalgebra N hp := + SMulMemClass.smul_mem _ (add_mem hymem hsmem) + have hy₂mem : (-(Complex.I) * 2⁻¹ : ℂ) • (p * a * p - s) + ∈ cornerNonUnitalStarSubalgebra N hp := + SMulMemClass.smul_mem _ (sub_mem hymem hsmem) + have hy₁sa : IsSelfAdjoint ((2⁻¹ : ℂ) • (p * a * p + s)) := by + rw [IsSelfAdjoint, star_smul, star_add, hs, star_star, + show star (2⁻¹ : ℂ) = (2⁻¹ : ℂ) by simp, add_comm] + have hy₂sa : IsSelfAdjoint ((-(Complex.I) * 2⁻¹ : ℂ) • (p * a * p - s)) := by + rw [IsSelfAdjoint, star_smul, star_sub, hs, star_star, + show star (-(Complex.I) * 2⁻¹ : ℂ) = (Complex.I * 2⁻¹ : ℂ) by simp, + ← neg_sub (p * a * p) (star (p * a * p)), smul_neg, neg_mul, neg_smul] + obtain ⟨c₁, hc₁⟩ := exists_real_smul_eq_of_forall_subprojection hp hpN hp0 hmin hy₁sa hy₁mem + obtain ⟨c₂, hc₂⟩ := exists_real_smul_eq_of_forall_subprojection hp hpN hp0 hmin hy₂sa hy₂mem + refine ⟨(c₁ : ℂ) + Complex.I * (c₂ : ℂ), ?_⟩ + have hrec : (2⁻¹ : ℂ) • (p * a * p + s) + + Complex.I • ((-(Complex.I) * 2⁻¹ : ℂ) • (p * a * p - s)) = p * a * p := by + rw [smul_smul, show Complex.I * (-(Complex.I) * 2⁻¹) = (2⁻¹ : ℂ) by + rw [← mul_assoc, mul_neg, Complex.I_mul_I, neg_neg, one_mul], + smul_add, smul_sub] + calc (2⁻¹ : ℂ) • (p * a * p) + (2⁻¹ : ℂ) • s + + ((2⁻¹ : ℂ) • (p * a * p) - (2⁻¹ : ℂ) • s) + = (2⁻¹ : ℂ) • (p * a * p) + (2⁻¹ : ℂ) • (p * a * p) := by abel + _ = ((2⁻¹ : ℂ) + 2⁻¹) • (p * a * p) := (add_smul _ _ _).symm + _ = p * a * p := by norm_num + calc p * a * p + = (2⁻¹ : ℂ) • (p * a * p + s) + + Complex.I • ((-(Complex.I) * 2⁻¹ : ℂ) • (p * a * p - s)) := hrec.symm + _ = (c₁ : ℂ) • p + Complex.I • ((c₂ : ℂ) • p) := by rw [hc₁, hc₂] + _ = ((c₁ : ℂ) + Complex.I * (c₂ : ℂ)) • p := by rw [smul_smul, ← add_smul] + +/-- **In a factor, a nonzero abelian projection is minimal**: it is order-minimal +(`subprojection_eq_of_isAbelianProjection`), and order-minimality forces the trivial corner +(`isMinimalProjection_of_forall_subprojection`). -/ +theorem IsFactor.isMinimalProjection_of_isAbelianProjection [Nontrivial H] + {N : VonNeumannAlgebra H} (hN : IsFactor N) {p : H →L[ℂ] H} + (hp : IsAbelianProjection N p) (hp0 : p ≠ 0) : IsMinimalProjection N p := + isMinimalProjection_of_forall_subprojection hp.1 hp.2.1 hp0 fun _ hq hqN hsub => + hN.subprojection_eq_of_isAbelianProjection hp hq hqN hsub + +/-- **The abelian-projection characterisation of type I coincides with the minimal-projection one +on factors**: a factor is type I iff it has a minimal projection. Nontriviality of `H` is +essential in both directions (on a subsingleton `H` the type I condition is vacuous while no +nonzero projection exists). -/ +theorem IsFactor.isTypeI_iff_exists_isMinimalProjection [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) : IsTypeI N ↔ ∃ e : H →L[ℂ] H, IsMinimalProjection N e := by + constructor + · intro h + have hone : (1 : H →L[ℂ] H) ≠ 0 := by + obtain ⟨v, hv⟩ := exists_ne (0 : H) + intro h1 + apply hv + have h2 := congrArg (fun T : H →L[ℂ] H => T v) h1 + simpa using h2 + obtain ⟨q, hab, hq0, -⟩ := h 1 (isCentralProjection_one N) hone + exact ⟨q, hN.isMinimalProjection_of_isAbelianProjection hab hq0⟩ + · exact hN.isTypeI_of_exists_isMinimalProjection + +/-- The factor-specialised definition `IsTypeIFactor` agrees with the conjunction of the general +abelian-projection type I property and factor-ness. -/ +theorem isTypeIFactor_iff_isFactor_and_isTypeI [Nontrivial H] {N : VonNeumannAlgebra H} : + IsTypeIFactor N ↔ IsFactor N ∧ IsTypeI N := by + constructor + · rintro ⟨hf, he⟩ + exact ⟨hf, hf.isTypeI_of_exists_isMinimalProjection he⟩ + · rintro ⟨hf, ht⟩ + exact ⟨hf, hf.isTypeI_iff_exists_isMinimalProjection.mp ht⟩ + end VonNeumannAlgebra diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean index 33830ef..279b048 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -66,6 +66,14 @@ commutant of its commutant. -/ noncomputable def generated (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H := (commutantSet s).commutant +/-- The carrier of a von Neumann algebra is norm-closed: it is a double centralizer, and +centralizers are closed. (Von Neumann algebras are even weakly closed, but the norm-closedness +is what the subalgebra-membership lemmas of the continuous functional calculus consume.) -/ +theorem isClosed_coe (N : VonNeumannAlgebra H) : IsClosed (N : Set (H →L[ℂ] H)) := by + rw [show (N : Set (H →L[ℂ] H)) = Set.centralizer (Set.centralizer (N : Set (H →L[ℂ] H))) from + N.centralizer_centralizer.symm] + exact Set.isClosed_centralizer _ + /-- `M′` denotes the commutant `VonNeumannAlgebra.commutant M`, the prime of the operator-algebra literature. -/ scoped postfix:max "′" => VonNeumannAlgebra.commutant From a3b7bed6e7ebceda01c9f9507499af30b564f46f Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 15:30:53 +0000 Subject: [PATCH 051/113] refactor: keep ForMathlib modules importing only Mathlib Inline the sole cross-module dependency of each ForMathlib file so the QuantumSystem/ForMathlib tree imports nothing but Mathlib: * Commutant.lean absorbs `Set.image_centralizer` (was ForMathlib/Algebra/Group/Center.lean) and imports Mathlib.Algebra.Group.* directly; Center.lean is removed. * TensorProductCompletion.lean absorbs the completion helpers (`LinearIsometryEquiv.completion*`, `FiniteDimensional.completion`) and imports Mathlib.Analysis.Normed.Module.FiniteDimension / Mathlib.Topology.Algebra.LinearMapCompletion directly. Drop the deleted Center module from the aggregate root. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 1 - .../ForMathlib/Algebra/Group/Center.lean | 31 ---- .../TensorProductCompletion.lean | 142 ++++++++++++++++++ .../Analysis/VonNeumannAlgebra/Commutant.lean | 62 +++++++- 4 files changed, 203 insertions(+), 33 deletions(-) delete mode 100644 QuantumSystem/ForMathlib/Algebra/Group/Center.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index b47fb1c..90d4702 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -46,7 +46,6 @@ public import QuantumSystem.Analysis.Matrix.Pinching public import QuantumSystem.Analysis.Matrix.PosDef public import QuantumSystem.Channel public import QuantumSystem.ForMathlib.Algebra.Colimit.DirectLimitStar -public import QuantumSystem.ForMathlib.Algebra.Group.Center public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry public import QuantumSystem.ForMathlib.Analysis.Calculus.Deriv.Sign public import QuantumSystem.ForMathlib.Analysis.Complex.Basic diff --git a/QuantumSystem/ForMathlib/Algebra/Group/Center.lean b/QuantumSystem/ForMathlib/Algebra/Group/Center.lean deleted file mode 100644 index 2d8f898..0000000 --- a/QuantumSystem/ForMathlib/Algebra/Group/Center.lean +++ /dev/null @@ -1,31 +0,0 @@ -module - -public import Mathlib.Algebra.Group.Center -public import Mathlib.Algebra.Group.Equiv.Defs - -/-! -# Centralizers under multiplicative bijections - -A multiplicative bijection carries the centralizer of a set onto the centralizer of the image. -This is the algebraic core of the fact that a spatial isomorphism of von Neumann algebras -commutes with taking commutants. --/ - -@[expose] public section - -/-- A multiplicative bijection carries the centralizer of a set onto the centralizer of the image: -`φ '' s' = (φ '' s)'`. -/ -theorem Set.image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] - [EquivLike F M₁ M₂] [MulEquivClass F M₁ M₂] (φ : F) (s : Set M₁) : - ⇑φ '' Set.centralizer s = Set.centralizer (⇑φ '' s) := by - ext y - simp only [Set.mem_image, Set.mem_centralizer_iff] - constructor - · rintro ⟨x, hx, rfl⟩ _ ⟨a, ha, rfl⟩ - rw [← map_mul, ← map_mul, hx a ha] - · intro hy - obtain ⟨x, rfl⟩ := EquivLike.surjective φ y - refine ⟨x, fun a ha => ?_, rfl⟩ - have h := hy (φ a) ⟨a, ha, rfl⟩ - apply EquivLike.injective φ - rw [map_mul, map_mul, h] diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean index cc4bd1f..53490cd 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean @@ -3,6 +3,9 @@ module public import Mathlib.Analysis.InnerProductSpace.Completion public import Mathlib.Analysis.InnerProductSpace.TensorProduct public import Mathlib.Analysis.InnerProductSpace.l2Space +public import Mathlib.RingTheory.TensorProduct.Finite +public import Mathlib.Analysis.Normed.Module.FiniteDimension +public import Mathlib.Topology.Algebra.LinearMapCompletion /-! # The completed Hilbert-space tensor product and operator amplification @@ -62,6 +65,82 @@ The textbook symbols `⊗̂` (completed tensor) and `⊗ₕ` (pure tensor) live open scoped TensorProduct +/-! ### Completion of a linear isometric equivalence and of a finite-dimensional space + +These are general facts about `UniformSpace.Completion` phrased for normed spaces; they are the +analytic inputs to the constructions below. The completion of a linear isometric equivalence +extends it to the completions, and the completion of a finite-dimensional space is again +finite-dimensional. -/ + +section Completion + +open UniformSpace UniformSpace.Completion + +namespace LinearIsometryEquiv + +variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] + [NormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedAddCommGroup F] [NormedSpace 𝕜 F] + +/-- The completed forward map of a linear isometric equivalence, as a continuous linear map. -/ +noncomputable def completionCLM (f : E ≃ₗᵢ[𝕜] F) : Completion E →L[𝕜] Completion F := + f.toLinearIsometry.toContinuousLinearMap.completion + +@[simp] theorem completionCLM_coe (f : E ≃ₗᵢ[𝕜] F) (a : E) : + f.completionCLM (a : Completion E) = (f a : Completion F) := by + rw [completionCLM, ContinuousLinearMap.completion_apply_coe, + LinearIsometry.coe_toContinuousLinearMap, LinearIsometryEquiv.coe_toLinearIsometry] + +theorem completionCLM_left (f : E ≃ₗᵢ[𝕜] F) (x : Completion E) : + f.symm.completionCLM (f.completionCLM x) = x := by + induction x using Completion.induction_on with + | hp => exact isClosed_eq ((map_continuous _).comp (map_continuous _)) continuous_id + | ih a => rw [completionCLM_coe, completionCLM_coe, LinearIsometryEquiv.symm_apply_apply] + +/-- The completion of a linear isometric equivalence `f : E ≃ₗᵢ[𝕜] F`, a linear isometric +equivalence `Completion E ≃ₗᵢ[𝕜] Completion F`. -/ +noncomputable def completion (f : E ≃ₗᵢ[𝕜] F) : Completion E ≃ₗᵢ[𝕜] Completion F where + toFun := f.completionCLM + invFun := f.symm.completionCLM + map_add' x y := _root_.map_add f.completionCLM x y + map_smul' m x := _root_.map_smul f.completionCLM m x + left_inv := f.completionCLM_left + right_inv x := by + have h := f.symm.completionCLM_left x + rwa [LinearIsometryEquiv.symm_symm] at h + norm_map' x := by + induction x using Completion.induction_on with + | hp => exact isClosed_eq (continuous_norm.comp f.completionCLM.continuous) continuous_norm + | ih a => + change ‖f.completionCLM (a : Completion E)‖ = ‖(a : Completion E)‖ + rw [completionCLM_coe, Completion.norm_coe, Completion.norm_coe, f.norm_map] + +@[simp] theorem completion_coe (f : E ≃ₗᵢ[𝕜] F) (a : E) : + f.completion (a : Completion E) = (f a : Completion F) := by + change f.completionCLM (a : Completion E) = _ + exact f.completionCLM_coe a + +end LinearIsometryEquiv + +/-- The completion of a finite-dimensional normed space (over a complete field) is +finite-dimensional. The coercion `toComplL : E → Completion E` is a linear map with dense range +whose image is a finite-dimensional (hence closed) subspace, so it is surjective, and +finite-dimensionality transfers along a surjection. -/ +theorem FiniteDimensional.completion {𝕜 E : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] + [NormedAddCommGroup E] [NormedSpace 𝕜 E] [FiniteDimensional 𝕜 E] : + FiniteDimensional 𝕜 (Completion E) := by + set f : E →L[𝕜] Completion E := Completion.toComplL with hf + have hdense : DenseRange f := by + simpa [hf, Completion.coe_toComplL] using Completion.denseRange_coe (α := E) + have hclosed : IsClosed (Set.range f) := by + have h := (LinearMap.range (f : E →ₗ[𝕜] Completion E)).closed_of_finiteDimensional + rwa [LinearMap.coe_range] at h + have hsurj : Function.Surjective f := by + have hu : Set.range f = Set.univ := by rw [← hclosed.closure_eq, hdense.closure_eq] + exact Set.range_eq_univ.mp hu + exact Module.Finite.of_surjective (f : E →ₗ[𝕜] Completion E) hsurj + +end Completion + variable {H₁ H₂ : Type*} [NormedAddCommGroup H₁] [InnerProductSpace ℂ H₁] [NormedAddCommGroup H₂] [InnerProductSpace ℂ H₂] @@ -76,6 +155,14 @@ abbrev HilbertTensor (H₁ H₂ : Type*) [NormedAddCommGroup H₂] [InnerProductSpace ℂ H₂] : Type _ := UniformSpace.Completion (H₁ ⊗[ℂ] H₂) +/-- The completed tensor product of two finite-dimensional Hilbert spaces is finite-dimensional: +the algebraic tensor product is already finite-dimensional (hence complete), so completing it +changes nothing. -/ +instance instFiniteDimensionalHilbertTensor [FiniteDimensional ℂ H₁] [FiniteDimensional ℂ H₂] : + FiniteDimensional ℂ (HilbertTensor H₁ H₂) := by + haveI : FiniteDimensional ℂ (H₁ ⊗[ℂ] H₂) := Module.Finite.tensorProduct ℂ H₁ H₂ + exact FiniteDimensional.completion + namespace HilbertTensor /-- A pure tensor `x ⊗ y` regarded as an element of the completed tensor product. -/ @@ -474,6 +561,61 @@ theorem amplifyRight_smul (c : ℂ) (B : H₂ →L[ℂ] H₂) : rw [amplifyRight_coe, algAmplifyRight_smul_apply, UniformSpace.Completion.coe_smul, ContinuousLinearMap.smul_apply, amplifyRight_coe] +/-! ### The commutation (swap) equivalence + +Swapping the two tensor factors is a linear isometric equivalence +`HilbertTensor H₁ H₂ ≃ₗᵢ HilbertTensor H₂ H₁`, the completion of Mathlib's algebraic +`TensorProduct.commIsometry`. Conjugating by it turns a right amplification `1 ⊗̂ B` into the left +amplification `B ⊗̂ 1` on the swapped space, which is what lets the right-hand slice lemma be +reused verbatim on the left. -/ + +/-- The **commutation (swap) equivalence** `x ⊗̂ y ↦ y ⊗̂ x`, a linear isometric equivalence +`HilbertTensor H₁ H₂ ≃ₗᵢ HilbertTensor H₂ H₁`, obtained by completing `TensorProduct.commIsometry`. -/ +noncomputable def commEquiv : HilbertTensor H₁ H₂ ≃ₗᵢ[ℂ] HilbertTensor H₂ H₁ := + (TensorProduct.commIsometry ℂ H₁ H₂).completion + +@[simp] theorem commEquiv_tmul (x : H₁) (y : H₂) : commEquiv (x ⊗ₕ y) = y ⊗ₕ x := by + rw [commEquiv, tmul, LinearIsometryEquiv.completion_coe, TensorProduct.commIsometry_apply, + TensorProduct.comm_tmul, tmul] + +@[simp] theorem commEquiv_symm_tmul (y : H₂) (x : H₁) : + commEquiv.symm (y ⊗ₕ x) = x ⊗ₕ y := by + rw [← commEquiv_tmul x y, LinearIsometryEquiv.symm_apply_apply] + +/-- Conjugating a right amplification `1 ⊗̂ B` by the swap equivalence yields the left +amplification `B ⊗̂ 1` on the swapped space. -/ +theorem conjStarAlgEquiv_commEquiv_amplifyRight (B : H₂ →L[ℂ] H₂) : + commEquiv.conjStarAlgEquiv (amplifyRight (H₁ := H₁) B) = amplifyLeft (H₂ := H₁) B := by + refine ContinuousLinearMap.ext fun w => ?_ + rw [LinearIsometryEquiv.conjStarAlgEquiv_apply_apply] + refine UniformSpace.Completion.induction_on w + (isClosed_eq (by fun_prop) (by fun_prop)) (fun a => ?_) + induction a using TensorProduct.induction_on with + | zero => simp only [UniformSpace.Completion.coe_zero, map_zero] + | tmul y x => + change commEquiv (amplifyRight B (commEquiv.symm (y ⊗ₕ x))) = amplifyLeft B (y ⊗ₕ x) + rw [commEquiv_symm_tmul, amplifyRight_tmul, commEquiv_tmul, amplifyLeft_tmul] + | add p q hp hq => + simp only [UniformSpace.Completion.coe_add, map_add, hp, hq] + +/-- Conjugating a right amplification `1 ⊗̂ S` by the *inverse* swap equivalence yields the left +amplification `S ⊗̂ 1`. This is the back-transport companion of +`conjStarAlgEquiv_commEquiv_amplifyRight`, used to carry the right-hand slice lemma back to the +original space. -/ +theorem conjStarAlgEquiv_symm_commEquiv_amplifyRight (S : H₁ →L[ℂ] H₁) : + commEquiv.conjStarAlgEquiv.symm (amplifyRight (H₁ := H₂) S) = amplifyLeft (H₂ := H₂) S := by + refine ContinuousLinearMap.ext fun w => ?_ + rw [LinearIsometryEquiv.symm_conjStarAlgEquiv_apply_apply] + refine UniformSpace.Completion.induction_on w + (isClosed_eq (by fun_prop) (by fun_prop)) (fun a => ?_) + induction a using TensorProduct.induction_on with + | zero => simp only [UniformSpace.Completion.coe_zero, map_zero] + | tmul x y => + change commEquiv.symm (amplifyRight S (commEquiv (x ⊗ₕ y))) = amplifyLeft S (x ⊗ₕ y) + rw [commEquiv_tmul, amplifyRight_tmul, commEquiv_symm_tmul, amplifyLeft_tmul] + | add p q hp hq => + simp only [UniformSpace.Completion.coe_add, map_add, hp, hq] + /-! ### Adjoints On genuine Hilbert spaces (`CompleteSpace H₁`, `CompleteSpace H₂`) the amplifications are diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean index 279b048..4429c1c 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -2,7 +2,8 @@ module public import Mathlib.Analysis.VonNeumannAlgebra.Basic public import Mathlib.Analysis.InnerProductSpace.Adjoint -public import QuantumSystem.ForMathlib.Algebra.Group.Center +public import Mathlib.Algebra.Group.Center +public import Mathlib.Algebra.Group.Equiv.Defs /-! # The commutant of a set, the generated von Neumann algebra, and unitary conjugation @@ -40,10 +41,35 @@ scope; activate it with `open scoped VonNeumannAlgebra`. @[expose] public section +/-- A multiplicative bijection carries the centralizer of a set onto the centralizer of the image: +`φ '' s' = (φ '' s)'`. This is the algebraic core of the fact that a spatial isomorphism of von +Neumann algebras commutes with taking commutants. -/ +theorem Set.image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] + [EquivLike F M₁ M₂] [MulEquivClass F M₁ M₂] (φ : F) (s : Set M₁) : + ⇑φ '' Set.centralizer s = Set.centralizer (⇑φ '' s) := by + ext y + simp only [Set.mem_image, Set.mem_centralizer_iff] + constructor + · rintro ⟨x, hx, rfl⟩ _ ⟨a, ha, rfl⟩ + rw [← map_mul, ← map_mul, hx a ha] + · intro hy + obtain ⟨x, rfl⟩ := EquivLike.surjective φ y + refine ⟨x, fun a ha => ?_, rfl⟩ + have h := hy (φ a) ⟨a, ha, rfl⟩ + apply EquivLike.injective φ + rw [map_mul, map_mul, h] + namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] +/-- A von Neumann algebra is closed under scalar multiplication. This upgrades the `SubringClass` +and `StarMemClass` instances of `VonNeumannAlgebra` with the missing `ℂ`-scalar closure, so that +the subtype `↥N` inherits an `Algebra ℂ ↥N` structure (via `SubalgebraClass.toAlgebra`) and +`*`-algebra equivalences `N ≃⋆ₐ[ℂ] _` typecheck. -/ +instance instSMulMemClass : SMulMemClass (VonNeumannAlgebra H) ℂ (H →L[ℂ] H) where + smul_mem {s} c _ hx := s.toStarSubalgebra.smul_mem hx c + /-- The commutant `(s ∪ s⋆)′` of the *symmetrized* set of an arbitrary set of bounded operators, packaged as a von Neumann algebra. For star-closed `s` — in particular for every self-adjoint generating set — this coincides with the commutant `s′` of the operator-algebra literature; for @@ -180,4 +206,38 @@ theorem conj_generated (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : conj U (generated s) = generated (⇑U.conjStarAlgEquiv '' s) := by rw [generated, ← conj_commutant, conj_commutantSet, generated] +/-! ### Transport of a von Neumann algebra as a `*`-algebra -/ + +/-- **Spatial conjugation as a `*`-algebra equivalence.** The conjugation `*`-isomorphism +`U.conjStarAlgEquiv : B(H) ≃⋆ₐ B(H')` restricts to a `*`-isomorphism `N ≃⋆ₐ U N U⋆` of the +subtypes: the carrier of `conj U N` is exactly the image of `N` (`coe_conj`), so `x ↦ U x U⋆` +is a bijection between the two. -/ +noncomputable def conjEquiv (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : + N ≃⋆ₐ[ℂ] conj U N where + toFun x := ⟨U.conjStarAlgEquiv (x : H →L[ℂ] H), by + rw [← SetLike.mem_coe, coe_conj]; exact ⟨x, x.2, rfl⟩⟩ + invFun y := ⟨U.conjStarAlgEquiv.symm (y : H' →L[ℂ] H'), by + have hy : (y : H' →L[ℂ] H') ∈ ⇑U.conjStarAlgEquiv '' (N : Set (H →L[ℂ] H)) := by + rw [← coe_conj]; exact y.2 + obtain ⟨x, hx, hxy⟩ := hy + rw [← SetLike.mem_coe, ← hxy, StarAlgEquiv.symm_apply_apply]; exact hx⟩ + left_inv x := Subtype.ext (U.conjStarAlgEquiv.symm_apply_apply (x : H →L[ℂ] H)) + right_inv y := Subtype.ext (U.conjStarAlgEquiv.apply_symm_apply (y : H' →L[ℂ] H')) + map_mul' x y := Subtype.ext (map_mul U.conjStarAlgEquiv (x : H →L[ℂ] H) (y : H →L[ℂ] H)) + map_add' x y := Subtype.ext (map_add U.conjStarAlgEquiv (x : H →L[ℂ] H) (y : H →L[ℂ] H)) + map_smul' c x := Subtype.ext (map_smul U.conjStarAlgEquiv c (x : H →L[ℂ] H)) + map_star' x := Subtype.ext (map_star U.conjStarAlgEquiv (x : H →L[ℂ] H)) + +/-- **Definitional-equality transport as a `*`-algebra equivalence.** Two equal von Neumann +algebras have `*`-isomorphic subtypes via the identity on operators. -/ +def equivOfEq {N M : VonNeumannAlgebra H} (h : N = M) : N ≃⋆ₐ[ℂ] M where + toFun x := ⟨x, h ▸ x.2⟩ + invFun x := ⟨x, h ▸ x.2⟩ + left_inv _ := rfl + right_inv _ := rfl + map_mul' _ _ := rfl + map_add' _ _ := rfl + map_smul' _ _ := rfl + map_star' _ := rfl + end VonNeumannAlgebra From f6936441f7d4e36c63a455861b9078a7fbe797e2 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 15:31:39 +0000 Subject: [PATCH 052/113] feat: add supporting API for the B(H) type I factor development MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre-existing structure-theory additions building toward "B(H) is a type I factor" and the spatial tensor identification: * ForMathlib/…/RankOne: `finiteDimensional_range_rankOne` — a rank-one operator has finite- (one-) dimensional range. * VonNeumannAlgebra/BoundedLinearOperators: `B(H)` is a factor, has a minimal projection, and is a type I (I_∞ when `H` is infinite-dimensional) factor. * ForMathlib/…/VonNeumannAlgebra/Lattice: the lattice `⊤`/`mem_top` API. * VonNeumannAlgebra/Factor: `IsMinimalProjection.nontrivial`. * VonNeumannAlgebra/TensorFactor: amplification injectivity and the `amplifyLeftStarAlgEquiv` `⋆`-isomorphism onto `B(H₁) ⊗̄ 1`. * VonNeumannAlgebra/TensorIdentification: spatial tensor-decomposition API. Register the two new modules in the aggregate root. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- QuantumSystem.lean | 2 + .../BoundedLinearOperators.lean | 121 ++++++++++++++++++ .../Algebra/VonNeumannAlgebra/Factor.lean | 7 + .../VonNeumannAlgebra/TensorFactor.lean | 88 +++++++++++++ .../TensorIdentification.lean | 31 ++++- .../Analysis/InnerProductSpace/RankOne.lean | 20 ++- .../Analysis/VonNeumannAlgebra/Lattice.lean | 46 +++++++ 7 files changed, 312 insertions(+), 3 deletions(-) create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean create mode 100644 QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 90d4702..b79ebde 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -22,6 +22,7 @@ public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra +public import QuantumSystem.Algebra.VonNeumannAlgebra.BoundedLinearOperators public import QuantumSystem.Algebra.VonNeumannAlgebra.CentralProjection public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily @@ -67,6 +68,7 @@ public import QuantumSystem.ForMathlib.Analysis.Matrix.Basic public import QuantumSystem.ForMathlib.Analysis.Matrix.Hermitian public import QuantumSystem.ForMathlib.Analysis.Matrix.Order public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Lattice public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PosDef diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean new file mode 100644 index 0000000..3930d73 --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean @@ -0,0 +1,121 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Lattice + +/-! +# The algebra of all bounded operators is a type I factor + +The algebra `B(H) = H →L[ℂ] H` of *all* bounded operators — realised as the greatest von Neumann +algebra `⊤ : VonNeumannAlgebra H` — is a factor: its centre is the scalars, by the elementary fact +that an operator commuting with every rank-one operator is scalar. It possesses a minimal +projection, namely any rank-one orthogonal projection `|u⟩⟨u|` with `‖u‖ = 1`. Hence `B(H)` is a +**type I factor**, and by the abstract structure theorem `IsTypeIFactor.exists_starAlgEquiv` it is +`⋆`-isomorphic to `B(K)` for some Hilbert space `K` (which is `ℓ²` of an orthonormal basis of `H`); +when `H` is infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor**. + +## Main results + +* `VonNeumannAlgebra.isFactor_boundedLinearOperators` — `B(H)` is a factor. +* `VonNeumannAlgebra.exists_isMinimalProjection_boundedLinearOperators` — `B(H)` has a minimal + projection (rank-one). +* `VonNeumannAlgebra.isTypeIFactor_boundedLinearOperators` — `B(H)` is a type I factor. +* `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(K)` for some + Hilbert space `K`. +* `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, the + space `K` is infinite-dimensional (`B(H)` is type I_∞). +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +open InnerProductSpace + +universe u + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- **`B(H)` is a factor.** The centre of the full algebra is trivial: an operator lying in the +commutant of `⊤` commutes with every operator, in particular with every rank-one operator, hence is +a scalar (`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ +theorem isFactor_boundedLinearOperators : IsFactor (⊤ : VonNeumannAlgebra H) := by + intro x _ hxComm + rw [VonNeumannAlgebra.mem_commutant_iff] at hxComm + refine ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm (fun a b => ?_) + have hg := hxComm (rankOne ℂ a b) (mem_top _) + rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] at hg + exact hg.symm + +/-- **A rank-one projection is minimal in `B(H)`.** For a unit vector `u`, the rank-one orthogonal +projection `|u⟩⟨u|` is a minimal projection of `⊤`: it is a star projection, nonzero, and its corner +is trivial because `|u⟩⟨u| ∘ a ∘ |u⟩⟨u| = ⟪u, a u⟫ • |u⟩⟨u|`. -/ +theorem isMinimalProjection_rankOne_boundedLinearOperators {u : H} (hu : ‖u‖ = 1) : + IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := by + have hu_ne : u ≠ 0 := by rw [← norm_pos_iff, hu]; norm_num + refine ⟨⟨isIdempotentElem_rankOne_self hu, ?_⟩, mem_top _, + rankOne_ne_zero hu_ne hu_ne, fun a _ => ?_⟩ + · rw [isSelfAdjoint_iff, ContinuousLinearMap.star_eq_adjoint, adjoint_rankOne] + · exact ⟨inner ℂ u (a u), by + rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def, + ContinuousLinearMap.comp_assoc, comp_rankOne, rankOne_comp_rankOne]⟩ + +omit [CompleteSpace H] in +/-- A normalised nonzero vector of a nontrivial space, packaged as a unit vector. -/ +private theorem exists_unit_vector [Nontrivial H] : ∃ u : H, ‖u‖ = 1 := by + obtain ⟨v, hv⟩ := exists_ne (0 : H) + exact ⟨(‖v‖⁻¹ : ℂ) • v, by + rw [norm_smul, norm_inv, Complex.norm_real, norm_norm, + inv_mul_cancel₀ (norm_ne_zero_iff.mpr hv)]⟩ + +/-- **`B(H)` has a minimal projection** (a rank-one projection). Needs `H` nonzero. -/ +theorem exists_isMinimalProjection_boundedLinearOperators [Nontrivial H] : + ∃ e : H →L[ℂ] H, IsMinimalProjection (⊤ : VonNeumannAlgebra H) e := + let ⟨u, hu⟩ := exists_unit_vector (H := H) + ⟨rankOne ℂ u u, isMinimalProjection_rankOne_boundedLinearOperators hu⟩ + +/-- **`B(H)` is a type I factor** (for nonzero `H`). -/ +theorem isTypeIFactor_boundedLinearOperators [Nontrivial H] : + IsTypeIFactor (⊤ : VonNeumannAlgebra H) := + ⟨isFactor_boundedLinearOperators, exists_isMinimalProjection_boundedLinearOperators⟩ + +/-- **`B(H)` is `⋆`-isomorphic to `B(K)`** for some complex Hilbert space `K`. This applies the +abstract type I factor structure theorem `IsTypeIFactor.exists_starAlgEquiv` to the full algebra; +`K` is `ℓ²` of an orthonormal basis of `H`. -/ +theorem exists_starAlgEquiv_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] : + ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), + Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := + isTypeIFactor_boundedLinearOperators.exists_starAlgEquiv + +/-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** The full algebra is +`⋆`-isomorphic to `B(K)` for a complex Hilbert space `K` that is itself infinite-dimensional. Here +`K = ℓ²(F)` for `F` an orthonormal basis of `H`; a finite `F` would, through the spatial +decomposition `H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` with one-dimensional multiplicity `eH` (the range of the +rank-one minimal projection), force `H` finite-dimensional. Expressing type I_∞ as +`¬FiniteDimensional ℂ K` is the standard reading: a type I_n factor is `B(K)` with `dim K = n`, so +I_∞ is exactly the infinite-dimensional `K`. -/ +theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] (hinf : ¬FiniteDimensional ℂ H) : + ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), + ¬FiniteDimensional ℂ K ∧ + Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by + obtain ⟨u, hu⟩ := exists_unit_vector (H := H) + have he : IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := + isMinimalProjection_rankOne_boundedLinearOperators hu + obtain ⟨F, U, hU, -⟩ := isFactor_boundedLinearOperators.exists_spatial_tensorDecomposition he + haveI : CompleteSpace (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := + he.1.completeSpace_range + haveI hfd : FiniteDimensional ℂ (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := + finiteDimensional_range_rankOne u + haveI : Nontrivial (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := by + rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] + exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective + (h.trans ContinuousLinearMap.coe_zero.symm)) + refine ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, ?_, + ⟨(conjEquiv U ⊤).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ + intro hK + haveI := hK + exact hinf U.symm.toLinearEquiv.finiteDimensional + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean index 5de4334..a2c4eba 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean @@ -60,6 +60,13 @@ supports comparison theory without invoking Borel functional calculus. -/ def IsMinimalProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := IsStarProjection e ∧ e ∈ N ∧ e ≠ 0 ∧ ∀ a ∈ N, ∃ c : ℂ, e * a * e = c • e +/-- A von Neumann algebra with a minimal projection acts on a nonzero space: the minimal +projection is nonzero, so it sends some vector to a nonzero vector, witnessing `Nontrivial H`. -/ +theorem IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) : Nontrivial H := + let ⟨x, hx⟩ := ContinuousLinearMap.exists_ne_zero he.2.2.1 + ⟨⟨e x, 0, hx⟩⟩ + /-- A minimal projection has no proper nonzero subprojection in `N`: if a projection `f ∈ N` satisfies `f ≤ e` (the Loewner order on projections, equivalently the range inclusion `ran f ⊆ ran e`, written algebraically as `e * f = f`), then `f = 0` or `f = e`. This recovers the diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index a1c9e93..e9657c3 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -336,4 +336,92 @@ theorem isFactor_vnTensorRight [CompleteSpace H₁] [CompleteSpace H₂] [Nontri VonNeumannAlgebra.IsFactor (vnTensorRight (H₁ := H₁) (H₂ := H₂)) := fun _ hx hx' => eq_smul_one_of_mem_vnTensorLeft_of_mem_vnTensorRight (by rwa [← vnTensorRight_commutant]) hx +/-! ### `B(H₁) ⊗̄ 1` is `⋆`-isomorphic to `B(H₁)` + +The left amplification `amplifyLeft : B(H₁) → B(H₁)⊗̄1` is a `⋆`-algebra homomorphism that is +injective (`amplifyLeft_injective`) and, by the slice lemma transported through the swap +equivalence, surjective onto `vnTensorLeft` (`exists_amplifyLeft_of_mem_vnTensorLeft`). Hence it +is a `⋆`-isomorphism `B(H₁) ≃⋆ₐ B(H₁) ⊗̄ 1` (`amplifyLeftStarAlgEquiv`). -/ + +/-- The left amplification `A ↦ A ⊗̂ 1` is injective (for nontrivial `H₂`): evaluating on pure +tensors `x ⊗̂ g` with `g ≠ 0` recovers `A x` up to the norm factor `‖g‖`. -/ +theorem amplifyLeft_injective [Nontrivial H₂] : + Function.Injective (amplifyLeft (H₁ := H₁) (H₂ := H₂)) := by + intro A₁ A₂ h + obtain ⟨g, hg⟩ := exists_ne (0 : H₂) + ext x + have h1 := congrArg + (fun L : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂ => L (tmul x g)) h + simp only [amplifyLeft_tmul] at h1 + have h2 : tmul (A₁ x - A₂ x) g = 0 := by + rw [sub_eq_add_neg, add_tmul, ← neg_one_smul ℂ (A₂ x), tmul_smul_left, h1, neg_one_smul, + add_neg_cancel] + have h3 : ‖A₁ x - A₂ x‖ * ‖g‖ = 0 := by rw [← norm_tmul, h2, norm_zero] + rcases mul_eq_zero.mp h3 with h4 | h4 + · exact sub_eq_zero.mp (norm_eq_zero.mp h4) + · exact absurd (norm_eq_zero.mp h4) hg + +/-- Every right amplification `1 ⊗̂ B` commutes with the factor `B(H₁) ⊗̄ 1`, i.e. lies in its +commutant. This is the easy inclusion of the commutation theorem and needs no completeness or +nontriviality hypotheses. -/ +theorem amplifyRight_mem_commutant_vnTensorLeft [CompleteSpace H₁] (B : H₂ →L[ℂ] H₂) : + amplifyRight (H₁ := H₁) B ∈ (vnTensorLeft (H₁ := H₁) (H₂ := H₂)).commutant := by + rw [vnTensorLeft_commutant_eq_commutantSet, VonNeumannAlgebra.mem_commutantSet_iff] + rintro h ⟨A, rfl⟩ + refine ⟨?_, ?_⟩ + · rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] + exact amplifyLeft_comp_amplifyRight A B + · rw [amplifyLeft_star, ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] + exact amplifyLeft_comp_amplifyRight (star A) B + +/-- **Surjectivity of the left amplification onto `B(H₁) ⊗̄ 1`.** Every operator in the factor +`vnTensorLeft` is a left amplification `A ⊗̂ 1`. An element `T ∈ vnTensorLeft` commutes with every +right amplification (`amplifyRight_mem_commutant_vnTensorLeft`); transporting through the swap +equivalence `commEquiv` turns this into commutation with every left amplification on the swapped +space, where the slice lemma `exists_amplifyRight_of_commutes` produces the operator. -/ +theorem exists_amplifyLeft_of_mem_vnTensorLeft [CompleteSpace H₁] [Nontrivial H₂] + {T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂} + (hT : T ∈ vnTensorLeft (H₁ := H₁) (H₂ := H₂)) : + ∃ A : H₁ →L[ℂ] H₁, T = amplifyLeft A := by + have hcomm : ∀ B : H₂ →L[ℂ] H₂, T * amplifyRight B = amplifyRight B * T := fun B => + VonNeumannAlgebra.mem_commutant_iff.mp (amplifyRight_mem_commutant_vnTensorLeft B) T hT + obtain ⟨u, hu⟩ := exists_ne (0 : H₂) + have he : ‖(‖u‖⁻¹ : ℂ) • u‖ = 1 := by + rw [norm_smul, norm_inv, Complex.norm_real, norm_norm, + inv_mul_cancel₀ (norm_ne_zero_iff.mpr hu)] + have hhyp : ∀ A : H₂ →L[ℂ] H₂, + (commEquiv.conjStarAlgEquiv T).comp (amplifyLeft A) + = (amplifyLeft A).comp (commEquiv.conjStarAlgEquiv T) := fun A => by + rw [← ContinuousLinearMap.mul_def, ← ContinuousLinearMap.mul_def, + ← conjStarAlgEquiv_commEquiv_amplifyRight A, ← map_mul, ← map_mul, hcomm A] + obtain ⟨S, hS⟩ := exists_amplifyRight_of_commutes (H₁ := H₂) (H₂ := H₁) + ((‖u‖⁻¹ : ℂ) • u) he (commEquiv.conjStarAlgEquiv T) hhyp + refine ⟨S, ?_⟩ + have hsymm := congrArg (⇑commEquiv.conjStarAlgEquiv.symm) hS + rw [StarAlgEquiv.symm_apply_apply, conjStarAlgEquiv_symm_commEquiv_amplifyRight] at hsymm + exact hsymm + +/-- The left amplification as a unital `⋆`-algebra homomorphism `B(H₁) →⋆ₐ[ℂ] B(H₁) ⊗̄ 1` onto the +factor, i.e. with codomain restricted to `vnTensorLeft`. -/ +noncomputable def amplifyLeftVnₐ [CompleteSpace H₁] : + (H₁ →L[ℂ] H₁) →⋆ₐ[ℂ] (vnTensorLeft (H₁ := H₁) (H₂ := H₂)) where + toFun A := ⟨amplifyLeft A, amplifyLeft_mem_vnTensorLeft A⟩ + map_one' := Subtype.ext amplifyLeft_one + map_mul' A B := Subtype.ext (amplifyLeft_mul A B) + map_zero' := Subtype.ext amplifyLeft_zero + map_add' A B := Subtype.ext (amplifyLeft_add A B) + commutes' r := Subtype.ext <| by + simp [Algebra.algebraMap_eq_smul_one, amplifyLeft_smul, amplifyLeft_one] + map_star' A := Subtype.ext (amplifyLeft_star A).symm + +/-- **`B(H₁) ⊗̄ 1` is `⋆`-isomorphic to `B(H₁)`.** The left amplification is a `⋆`-isomorphism of +`B(H₁)` onto the factor `vnTensorLeft`, for nontrivial complete `H₁` and nontrivial `H₂`. -/ +noncomputable def amplifyLeftStarAlgEquiv [CompleteSpace H₁] [Nontrivial H₂] : + (H₁ →L[ℂ] H₁) ≃⋆ₐ[ℂ] (vnTensorLeft (H₁ := H₁) (H₂ := H₂)) := + StarAlgEquiv.ofBijective amplifyLeftVnₐ + ⟨fun A B hAB => amplifyLeft_injective (H₂ := H₂) (Subtype.ext_iff.mp hAB), + fun ⟨T, hT⟩ => by + obtain ⟨A, rfl⟩ := exists_amplifyLeft_of_mem_vnTensorLeft hT + exact ⟨A, rfl⟩⟩ + end HilbertTensor diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean index faa4bfc..3920930 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean @@ -343,12 +343,13 @@ projection `e` (acting on a nonzero Hilbert space) is, up to a spatial isomorphi `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)`, exactly the tensor factor `B(ℓ²(F)) ⊗̄ 1`, with commutant `1 ⊗̄ B(eH)`: conjugation by `U` carries `N` onto `vnTensorLeft` and `N'` onto `vnTensorRight`. This is Yngvason §5.1 (38)→(39) in its model-independent von-Neumann-algebraic form. -/ -theorem IsFactor.exists_spatial_tensorDecomposition [Nontrivial H] {N : VonNeumannAlgebra H} +theorem IsFactor.exists_spatial_tensorDecomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), VonNeumannAlgebra.conj U N = vnTensorLeft ∧ VonNeumannAlgebra.conj U N′ = vnTensorRight := by + haveI := he.nontrivial obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range haveI : DecidableEq F := Classical.decEq _ @@ -363,7 +364,7 @@ theorem IsFactor.exists_spatial_tensorDecomposition [Nontrivial H] {N : VonNeuma factor `B(ℓ²(F)) ⊗̄ 1` and `A₂` lands in the right factor `1 ⊗̄ B(eH)`, with `N` and its commutant identified exactly. The existence of such an intermediate type I factor `N` is the model-dependent split-property input; everything downstream of it is proved here. -/ -theorem IsFactor.exists_split_tensorDecomposition [Nontrivial H] {N : VonNeumannAlgebra H} +theorem IsFactor.exists_split_tensorDecomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) {A₁ A₂ : VonNeumannAlgebra H} (h₁ : A₁ ≤ N) (h₂ : N ≤ A₂′) : ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] @@ -372,6 +373,7 @@ theorem IsFactor.exists_split_tensorDecomposition [Nontrivial H] {N : VonNeumann VonNeumannAlgebra.conj U N′ = vnTensorRight ∧ VonNeumannAlgebra.conj U A₁ ≤ vnTensorLeft ∧ VonNeumannAlgebra.conj U A₂ ≤ vnTensorRight := by + haveI := he.nontrivial obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range haveI : DecidableEq F := Classical.decEq _ @@ -381,4 +383,29 @@ theorem IsFactor.exists_split_tensorDecomposition [Nontrivial H] {N : VonNeumann hF.conj_spatialEquiv_le_vnTensorLeft he htop h₁, hF.conj_spatialEquiv_le_vnTensorRight he htop h₂⟩ +universe u + +/-- **Type I factor abstract structure theorem.** A type I factor `N` (a factor with a minimal +projection, acting on a nonzero Hilbert space) is `⋆`-isomorphic to the algebra `B(K)` of all +bounded operators on *some* complex Hilbert space `K`. This is the model-independent form of the +classification of type I factors: `B(K)` for `K = ℓ²(F)` is exactly the type `I_{|F|}` factor, and +`K = H` recovers the full algebra `B(H)` as the type `I` factor `⊤`. The spatial content — that the +isomorphism is implemented by a unitary and that `K` is the multiplicity space of the minimal +projection — is `IsFactor.exists_spatial_tensorDecomposition`; here it is packaged as an abstract +`⋆`-isomorphism, hiding the specific model `K = ℓ²(F)` behind an existential. -/ +theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] {N : VonNeumannAlgebra H} + (hN : IsTypeIFactor N) : + ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), + Nonempty (N ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by + obtain ⟨hFactor, e, he⟩ := hN + obtain ⟨F, U, hU, -⟩ := hFactor.exists_spatial_tensorDecomposition he + haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range + haveI : Nontrivial (LinearMap.range (e : H →ₗ[ℂ] H)) := by + rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] + exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective + (h.trans ContinuousLinearMap.coe_zero.symm)) + exact ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, + ⟨(conjEquiv U N).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ + end VonNeumannAlgebra diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean index 909b3c0..560379e 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean @@ -1,6 +1,7 @@ module public import Mathlib.Analysis.InnerProductSpace.LinearMap +public import Mathlib.LinearAlgebra.FiniteDimensional.Basic /-! # Operators commuting with all rank-one operators are scalar @@ -8,7 +9,9 @@ public import Mathlib.Analysis.InnerProductSpace.LinearMap A continuous linear operator on an inner product space that commutes with every rank-one operator `|x⟩⟨y|` is a scalar multiple of the identity. This is the elementary computation behind "the centre of `B(H)` is trivial" and, downstream, behind the factor property of the tensor -von Neumann algebras `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)`. +von Neumann algebras `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)`. We also record that a rank-one operator has +finite- (in fact one-) dimensional range, used to see that a rank-one minimal projection of `B(H)` +has one-dimensional multiplicity space. -/ @[expose] public section @@ -35,3 +38,18 @@ theorem ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm calc S x = (inner ℂ y y)⁻¹ • ((inner ℂ y y : ℂ) • S x) := (inv_smul_smul₀ hyy _).symm _ = (inner ℂ y y)⁻¹ • (inner ℂ y (S y) • x) := by rw [h1] _ = (inner ℂ y (S y) / inner ℂ y y) • x := by rw [smul_smul, div_eq_inv_mul] + +/-- The range of a rank-one operator `|u⟩⟨u|` is finite-dimensional (it is contained in the line +`ℂ ∙ u`). For a unit vector this is the one-dimensional multiplicity space of the corresponding +minimal projection of `B(H)`. -/ +theorem finiteDimensional_range_rankOne {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] + (u : H) : + FiniteDimensional ℂ (LinearMap.range ((InnerProductSpace.rankOne ℂ u u : H →L[ℂ] H) + : H →ₗ[ℂ] H)) := by + have hle : LinearMap.range ((InnerProductSpace.rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H) + ≤ Submodule.span ℂ {u} := by + rw [LinearMap.range_le_iff_comap, eq_top_iff] + intro z _ + simp only [Submodule.mem_comap, ContinuousLinearMap.coe_coe, InnerProductSpace.rankOne_apply] + exact Submodule.smul_mem _ _ (Submodule.mem_span_singleton_self u) + exact Submodule.finiteDimensional_of_le hle diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean new file mode 100644 index 0000000..c1f1c9b --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean @@ -0,0 +1,46 @@ +module + +public import Mathlib.Analysis.VonNeumannAlgebra.Basic + +/-! +# The greatest von Neumann algebra: the algebra of all bounded operators + +The von Neumann subalgebras of `B(H) = H →L[ℂ] H` form a bounded lattice under inclusion, whose +greatest element is `B(H)` itself — the algebra of *all* bounded linear operators (the operator- +algebra literature's name for it; "top element" is the order-theoretic name for the same object). +Mathlib's `VonNeumannAlgebra H` carries only a `PartialOrder` (via `SetLike`) and no `Top` instance, +so `(⊤ : VonNeumannAlgebra H)` does not yet elaborate. This file supplies that `Top` instance: the +carrier is all of `H →L[ℂ] H`, and the double-commutant law holds because the bicommutant of the +whole set is itself (`Set.subset_centralizer_centralizer` together with `Set.subset_univ`). + +This is the natural home for further lattice structure on `VonNeumannAlgebra H` (meets as +intersections, joins as generated algebras) should it be added; only the top element is needed here. + +## Main declarations + +* `Top (VonNeumannAlgebra H)` — the greatest element `⊤`, the algebra of all bounded operators. +* `VonNeumannAlgebra.coe_top` / `VonNeumannAlgebra.mem_top` — its carrier is everything. +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- The **algebra of all bounded operators** `B(H) = H →L[ℂ] H`, as the greatest element `⊤` of the +inclusion order on `VonNeumannAlgebra H`. Its carrier is `Set.univ`; the double-commutant property is +the bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest +set. -/ +noncomputable instance : Top (VonNeumannAlgebra H) where + top := + { toStarSubalgebra := ⊤ + centralizer_centralizer' := + Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } + +@[simp] theorem coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl + +/-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ +@[simp] theorem mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x + +end VonNeumannAlgebra From fa3e223d5048dea64c877f88b7f804fc35f497ce Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 15:32:02 +0000 Subject: [PATCH 053/113] refactor: remove unused theorems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop declarations that are unused across the repository and redundant (restatements, dead scaffolding), verified to have no references: * GNS/Construction: `inner_kernel_elem_zero`, `πω'_lipschitz`, `quotient_in_cyclic_closure`. * VonNeumannAlgebra/MatrixUnits: `matrixUnit_self`, `star_matrixUnit`. * VonNeumannAlgebra/TensorFactor: `vnTensorRight_commutant_eq_commutantSet`. * VonNeumannAlgebra/Comparison: `IsPartialIsometry.range_mul_self` (body was `:= h`, a restatement of the `IsPartialIsometry` definition). * Analysis/Matrix/LiebConcavity: `hsInnerProduct_leftMul_rightMul`. * Analysis/Matrix/Order: `rpow_concavity_quadform_nonneg`. Update the module docstrings/comments that referenced them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- .../CStarAlgebra/GNS/Construction.lean | 15 ---------- .../Algebra/VonNeumannAlgebra/Comparison.lean | 7 +---- .../VonNeumannAlgebra/MatrixUnits.lean | 9 ------ .../VonNeumannAlgebra/TensorFactor.lean | 6 ---- .../Analysis/Matrix/LiebConcavity.lean | 29 ++----------------- QuantumSystem/Analysis/Matrix/Order.lean | 23 --------------- 6 files changed, 3 insertions(+), 86 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean index adf996a..38084ab 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean @@ -117,11 +117,6 @@ private lemma norm_sq_eq_inner (x : A) : simp only [Quotient.liftOn₂'_mk''] rfl -/-- Inner products with elements of the kernel ideal vanish: if `s ∈ Nω` then -`ω (star x * s) = 0`. -/ -private lemma inner_kernel_elem_zero (x : A) (s : Nω) : ω (star x * s.val) = 0 := - State.kernel_degenerate_left (ω := ω) (x := s.val) (a := x) s.property - /-- The GNS Hilbert space `Hω`, defined as the completion of the quotient `A ⧸ Nω`. -/ abbrev Hω := UniformSpace.Completion (A ⧸ Nω) local notation "Hω" => (Hω (ω := ω)) @@ -220,10 +215,6 @@ lemma πω'_norm_le (a : A) (b : A ⧸ Nω) : ‖πω' ω a b‖ ≤ ‖a‖ * simpa [Real.sqrt_sq (norm_nonneg _), mul_nonneg (norm_nonneg a) (norm_nonneg b)] using Real.sqrt_le_sqrt h_sq -/-- Lipschitz continuity of `b ↦ πω'(a)b` with optimal constant `‖a‖`. -/ -lemma πω'_lipschitz (a : A) : ∃ C : ℝ≥0, ∀ b : A ⧸ Nω, ‖πω' ω a b‖ ≤ C * ‖b‖ := - ⟨⟨‖a‖, norm_nonneg a⟩, fun b => by simpa using πω'_norm_le (ω := ω) a b⟩ - /-- Continuous linear map version of the pre-representation: `πω'(a) : A ⧸ Nω →L[ℂ] A ⧸ Nω`. -/ noncomputable def πω'CLM (a : A) : (A ⧸ Nω) →L[ℂ] (A ⧸ Nω) := LinearMap.mkContinuous @@ -487,12 +478,6 @@ lemma πω_cyclic_identity (b : A) : -- Lift inner product from dense subspace into completion simp [UniformSpace.Completion.inner_coe] -/-- The quotient image of any element lies in the closure of the cyclic orbit. -/ -lemma quotient_in_cyclic_closure (b : A) : - (↑(Quotient.mk'' b : A ⧸ Nω) : Hω) ∈ closure (⋃ (a : A), {πω ω a (ξω ω)}) := by - rw [← πω_cyclic_identity] - exact subset_closure (Set.mem_iUnion.mpr ⟨b, rfl⟩) - /-- Cyclicity of `ξω`: the span of `{πω a ξω | a : A}` is dense in `Hω`. -/ lemma ξω_is_cyclic : Dense (↑(Submodule.span ℂ {πω ω a (ξω ω) | a : A}) : Set Hω) := by rw [Metric.dense_iff] diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean index d5192ad..d7983ad 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean @@ -24,8 +24,7 @@ supports and polar decomposition; it is developed in subsequent steps. are star projections. * `isStarProjection_subproj_comm` — the subprojection relation `e * f = f` is left/right symmetric for projections. -* `IsPartialIsometry.range_mul_self` / `mul_source` — the range and source projections act as - one-sided identities. +* `IsPartialIsometry.mul_source` — the source projection acts as a one-sided identity. * `MvNEquiv.exists_subproj_equiv` — an equivalence `q ∼[N] r'` transports a subprojection `q' ≤ q` to a subprojection of `r'` equivalent to `q'`. * `MvNSub.refl` / `MvNSub.trans` — subordination is a preorder on projections. @@ -64,10 +63,6 @@ theorem isStarProjection_subproj_comm {R : Type*} [Ring R] [StarRing R] {e f : R have := congrArg star h rwa [star_mul, he.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this -/-- The range projection of a partial isometry acts as a left identity. -/ -theorem IsPartialIsometry.range_mul_self {R : Type*} [Monoid R] [StarMul R] {v : R} - (h : IsPartialIsometry v) : (v * star v) * v = v := h - /-- The source projection of a partial isometry acts as a right identity. -/ theorem IsPartialIsometry.mul_source {R : Type*} [Monoid R] [StarMul R] {v : R} (h : IsPartialIsometry v) : v * (star v * v) = v := by rw [← mul_assoc]; exact h diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean index fd96b56..1dec276 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean @@ -107,15 +107,6 @@ theorem OrthEquivFam.matrixUnit_mem (hF : OrthEquivFam N e F) (p q : F) : hF.matrixUnit p q ∈ N := mul_mem (hF.pisom_mem p) (star_mem (hF.pisom_mem q)) -/-- The diagonal matrix unit is the projection: `e_{pp} = p`. -/ -theorem OrthEquivFam.matrixUnit_self (hF : OrthEquivFam N e F) (p : F) : - hF.matrixUnit p p = (p : H →L[ℂ] H) := hF.pisom_range p - -/-- Matrix units are adjoint-symmetric: `e_{pq}⋆ = e_{qp}`. -/ -theorem OrthEquivFam.star_matrixUnit (hF : OrthEquivFam N e F) (p q : F) : - star (hF.matrixUnit p q) = hF.matrixUnit q p := by - rw [matrixUnit_def, matrixUnit_def, star_mul, star_star] - /-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, diagonal case `q = r`: `e_{pq} e_{qs} = e_{ps}`. -/ theorem OrthEquivFam.matrixUnit_mul_of_eq (hF : OrthEquivFam N e F) (p q s : F) : diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index e9657c3..7470416 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -81,12 +81,6 @@ theorem vnTensorLeft_commutant_eq_commutantSet : = VonNeumannAlgebra.commutantSet (Set.range (amplifyLeft (H₂ := H₂))) := VonNeumannAlgebra.commutant_generated _ -/-- The commutant of `1 ⊗̄ B(H₂)` is the commutant of the range of `amplifyRight`. -/ -theorem vnTensorRight_commutant_eq_commutantSet : - (vnTensorRight (H₁ := H₁) (H₂ := H₂)).commutant - = VonNeumannAlgebra.commutantSet (Set.range (amplifyRight (H₁ := H₁))) := - VonNeumannAlgebra.commutant_generated _ - /-! ### The tensor commutation theorem The commutant of `B(H₁) ⊗̄ 1` is exactly `1 ⊗̄ B(H₂)` — von Neumann's commutation theorem for the diff --git a/QuantumSystem/Analysis/Matrix/LiebConcavity.lean b/QuantumSystem/Analysis/Matrix/LiebConcavity.lean index da15b26..773834c 100644 --- a/QuantumSystem/Analysis/Matrix/LiebConcavity.lean +++ b/QuantumSystem/Analysis/Matrix/LiebConcavity.lean @@ -83,31 +83,6 @@ namespace QuantumInfo scoped notation "⟪" X ", " Y "⟫_HS" => Matrix.hsInnerProduct X Y end QuantumInfo -/-- Hilbert-Schmidt inner product is related to liebJointFunction via left/right multiplication. -For positive semidefinite A, B and real p: - ⟨A^p · K† · B^{1-p}, K†⟩_HS = Tr(A^p · K† · B^{1-p} · K) -This connects the operator-level perspective to the trace-level Lieb function. -/ -private lemma hsInnerProduct_leftMul_rightMul {m : Type*} [Fintype m] [DecidableEq m] - (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef) - (K : Matrix m m ℂ) (p : ℝ) : - hsInnerProduct ((A ^ p) * Kᴴ * (B ^ (1 - p))) Kᴴ = liebJointFunction K p A hA B hB := by - simp only [hsInnerProduct, liebJointFunction] - -- (A^p * K† * B^{1-p})† = B^{1-p}† * K * (A^p)† - -- Since A^p and B^{1-p} are Hermitian (rpow of PSD is PSD hence Hermitian): - have hAp_herm : (A ^ p)ᴴ = A ^ p := by - rw [CFC.rpow_eq_cfc_real (a := A) (ha := by rw [Matrix.le_iff, sub_zero]; exact hA)] - exact cfc_isHermitian hA.1 (fun x => x ^ p) - have hBp_herm : (B ^ (1 - p))ᴴ = B ^ (1 - p) := by - rw [CFC.rpow_eq_cfc_real (a := B) (ha := by rw [Matrix.le_iff, sub_zero]; exact hB)] - exact cfc_isHermitian hB.1 (fun x => x ^ (1 - p)) - simp only [Matrix.conjTranspose_mul, Matrix.conjTranspose_conjTranspose, - hAp_herm, hBp_herm, Matrix.mul_assoc] - -- LHS: Tr(B^{1-p} * K * A^p * K†), RHS: Tr(A^p * K† * B^{1-p} * K) - -- By trace cyclicity (two shifts) these are equal - simp only [← Matrix.mul_assoc] - rw [trace_mul_cycle, trace_mul_cycle] - simp only [Matrix.mul_assoc] - /-- The HS inner product ⟨v, matrixPerspective(f, L_A, R_B) v⟩ for f(t) = -t^p and v = vec(K†) equals -Tr(A^p K† B^{1-p} K). @@ -123,8 +98,8 @@ The proof is technical but the key insight is: - Combining: ⟨v, (-L^p R^{1-p}) v⟩ = -Tr(A^p K† B^{1-p} K) = -liebJointFunction For full generality this requires functional calculus on Kronecker products, -but the result follows from the trace identity hsInnerProduct_leftMul_rightMul -and the perspective structure. -/ +but the result follows from the underlying trace identity and the perspective +structure. -/ private lemma matrixPerspective_inner_eq_neg_liebJointFunction {m : Type*} [Fintype m] [DecidableEq m] (K : Matrix m m ℂ) (p : ℝ) (hp : 0 ≤ p) (hp1 : p ≤ 1) (A B : Matrix m m ℂ) (hA : A.PosDef) (hB : B.PosDef) diff --git a/QuantumSystem/Analysis/Matrix/Order.lean b/QuantumSystem/Analysis/Matrix/Order.lean index a307355..873cd1c 100644 --- a/QuantumSystem/Analysis/Matrix/Order.lean +++ b/QuantumSystem/Analysis/Matrix/Order.lean @@ -875,29 +875,6 @@ private lemma rpow_operator_concave_le {m : Type*} [Fintype m] [DecidableEq m] end RpowOperatorConcaveAux -/-- Helper: The difference in quadratic forms for operator concavity. -/ -private lemma rpow_concavity_quadform_nonneg {m : Type*} [Fintype m] [DecidableEq m] - {s : ℝ} (hs0 : 0 < s) (hs1 : s ≤ 1) - (A B : Matrix m m ℂ) (hA : A.PosSemidef) (hB : B.PosSemidef) - (t : ℝ) (ht0 : 0 ≤ t) (ht1 : t ≤ 1) - (hC : (t • A + (1 - t) • B).IsHermitian) (v : m → ℂ) : - 0 ≤ (star v ⬝ᵥ - ((t • A + (1 - t) • B) ^ s - t • A ^ s - (1 - t) • B ^ s) *ᵥ v).re := by - have hle : t • A ^ s + (1 - t) • B ^ s ≤ (t • A + (1 - t) • B) ^ s := - rpow_operator_concave_le hs0 hs1 A B hA hB t ht0 ht1 hC - have hpsd : - ((t • A + (1 - t) • B) ^ s - (t • A ^ s + (1 - t) • B ^ s)).PosSemidef := by - simpa [Matrix.le_iff] using hle - have hpsd' : - ((t • A + (1 - t) • B) ^ s - t • A ^ s - (1 - t) • B ^ s).PosSemidef := by - have hcalc : - ((t • A + (1 - t) • B) ^ s - (t • A ^ s + (1 - t) • B ^ s)) = - ((t • A + (1 - t) • B) ^ s - t • A ^ s - (1 - t) • B ^ s) := by - module - simpa [hcalc] using hpsd - have hnonneg := hpsd'.dotProduct_mulVec_nonneg v - exact (Complex.nonneg_iff.mp hnonneg).1 - /-- The power function t^s (0 < s ≤ 1) is Löwner concave. This means: (λA + (1-λ)B)^s ≥ λ·A^s + (1-λ)·B^s in Löwner order. From 5a74a730140bd6fc9d2d93209640e37fb533a692 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 15:32:27 +0000 Subject: [PATCH 054/113] refactor: demote auxiliary theorems to lemma Reserve the `theorem` keyword for the headline results named in each module's "Main results/definitions" docstring; demote computational (`_apply`/`_coe`/ `_def`), `@[simp]`, monotonicity/congruence and other technical helpers to `lemma`, following the Mathlib convention. No statements or proofs change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- .../Representation/DirectSum.lean | 4 +- .../Algebra/LocalNet/Covariance.lean | 30 +++---- QuantumSystem/Algebra/LocalNet/Net.lean | 10 +-- .../Algebra/LocalNet/QuasiLocalAlgebra.lean | 42 +++++----- .../BoundedLinearOperators.lean | 2 +- .../VonNeumannAlgebra/CentralProjection.lean | 4 +- .../Algebra/VonNeumannAlgebra/Comparison.lean | 16 ++-- .../VonNeumannAlgebra/CoveringFamily.lean | 10 +-- .../Algebra/VonNeumannAlgebra/Factor.lean | 8 +- .../GeneratedByMatrixUnits.lean | 4 +- .../VonNeumannAlgebra/MatrixUnits.lean | 18 ++-- .../SpatialDecomposition.lean | 18 ++-- .../VonNeumannAlgebra/TensorFactor.lean | 24 +++--- .../TensorIdentification.lean | 22 ++--- .../Algebra/VonNeumannAlgebra/TypeI.lean | 22 ++--- .../Analysis/Entropy/KroneckerProduct.lean | 8 +- .../Analysis/Entropy/RelativeEntropy.lean | 4 +- .../Analysis/Entropy/VonNeumannEntropy.lean | 16 ++-- QuantumSystem/Analysis/Matrix/Effros.lean | 22 ++--- QuantumSystem/Channel.lean | 26 +++--- .../Algebra/Colimit/DirectLimitStar.lean | 2 +- .../Algebra/Star/PartialIsometry.lean | 2 +- .../Analysis/CStarAlgebra/DirectLimit.lean | 2 +- .../TensorProductCompletion.lean | 84 +++++++++---------- .../Analysis/VonNeumannAlgebra/Commutant.lean | 26 +++--- .../Analysis/VonNeumannAlgebra/Lattice.lean | 4 +- .../LinearAlgebra/Matrix/PartialTrace.lean | 4 +- .../LinearAlgebra/Matrix/StarAlgEquiv.lean | 8 +- .../ForMathlib/LinearAlgebra/Trace.lean | 8 +- .../Topology/Algebra/CStarCompletion.lean | 8 +- QuantumSystem/State.lean | 16 ++-- 31 files changed, 237 insertions(+), 237 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean index 499d7b0..cbe9998 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean @@ -113,7 +113,7 @@ lemma sectorEmbed_apply_coord_ne (F : SectorFamily.{u, v, w} A) exact lp.single_apply_ne (E := fun α'' : F.Index => (F.rep α'').H) 2 α v h -@[simp] theorem sectorComponent_sectorEmbed (F : SectorFamily.{u, v, w} A) +@[simp] lemma sectorComponent_sectorEmbed (F : SectorFamily.{u, v, w} A) (α : F.Index) (v : (F.rep α).H) : sectorComponent F α (sectorEmbed F α v) = v := by change (sectorEmbed F α v).val α = v @@ -295,7 +295,7 @@ noncomputable def directSumRep (F : SectorFamily.{u, v, w} A) : rfl /-- The operator-norm bound `‖F.directSumRep a‖ ≤ ‖a‖`. -/ -theorem directSumRep_norm_le (F : SectorFamily.{u, v, w} A) (a : A) : +lemma directSumRep_norm_le (F : SectorFamily.{u, v, w} A) (a : A) : ‖F.directSumRep a‖ ≤ ‖a‖ := by change ‖F.directSumCLM a‖ ≤ ‖a‖ exact LinearMap.mkContinuous_norm_le _ (norm_nonneg _) _ diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 0f0c9bd..460d395 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -57,7 +57,7 @@ def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding /-- **Extensionality** for covariances: two covariances with the same site permutation and the same local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality field `β_incl` is a proposition, hence irrelevant. -/ -@[ext (iff := false)] theorem ext {s t : N.Covariance} (hσ : s.σ = t.σ) +@[ext (iff := false)] lemma ext {s t : N.Covariance} (hσ : s.σ = t.σ) (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by revert hσ hβ @@ -72,14 +72,14 @@ def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding rfl /-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ -theorem β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : +lemma β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by have key := a.β_incl h ((a.β Λ).symm y) rw [StarAlgEquiv.apply_symm_apply] at key rw [← key, StarAlgEquiv.symm_apply_apply] /-- The local `*`-isomorphisms commute with the region-equality transport. -/ -theorem β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : +lemma β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by subst e; simp @@ -115,31 +115,31 @@ def inv (a : N.Covariance) : N.Covariance where rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), a.β_symm_incl] -@[simp] theorem id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : +@[simp] lemma id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : (Covariance.id N).β Λ x = N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := rfl -@[simp] theorem comp_β_apply (a b : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : +@[simp] lemma comp_β_apply (a b : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := rfl -@[simp] theorem inv_β_apply (a : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : +@[simp] lemma inv_β_apply (a : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : (Covariance.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by simp [Finset.map_map]).symm x) := rfl -@[simp] theorem region_id (Λ : Finset sites) : (Covariance.id N).region Λ = Λ := by +@[simp] lemma region_id (Λ : Finset sites) : (Covariance.id N).region Λ = Λ := by simp [region, Covariance.id] -@[simp] theorem region_comp (a b : N.Covariance) (Λ : Finset sites) : +@[simp] lemma region_comp (a b : N.Covariance) (Λ : Finset sites) : (a.comp b).region Λ = a.region (b.region Λ) := by simp [region, Covariance.comp, Finset.map_map, Equiv.trans_toEmbedding] -theorem id_comp (a : N.Covariance) : (Covariance.id N).comp a = a := by +lemma id_comp (a : N.Covariance) : (Covariance.id N).comp a = a := by refine Covariance.ext ?_ fun Λ x e => ?_ · simp [Covariance.comp, Covariance.id] · rw [algebraCongr_eq_iff] @@ -147,7 +147,7 @@ theorem id_comp (a : N.Covariance) : (Covariance.id N).comp a = a := by erw [algebraCongr_trans] rfl -theorem comp_id (a : N.Covariance) : a.comp (Covariance.id N) = a := by +lemma comp_id (a : N.Covariance) : a.comp (Covariance.id N) = a := by refine Covariance.ext ?_ fun Λ x e => ?_ · simp [Covariance.comp, Covariance.id] · rw [algebraCongr_eq_iff] @@ -155,7 +155,7 @@ theorem comp_id (a : N.Covariance) : a.comp (Covariance.id N) = a := by erw [a.β_algebraCongr, algebraCongr_trans] rfl -theorem comp_assoc (a b c : N.Covariance) : (a.comp b).comp c = a.comp (b.comp c) := by +lemma comp_assoc (a b c : N.Covariance) : (a.comp b).comp c = a.comp (b.comp c) := by refine Covariance.ext ?_ fun Λ x e => ?_ · simp [Covariance.comp, Equiv.trans_assoc] · rw [algebraCongr_eq_iff] @@ -163,7 +163,7 @@ theorem comp_assoc (a b c : N.Covariance) : (a.comp b).comp c = a.comp (b.comp c erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] rfl -theorem inv_comp (a : N.Covariance) : (Covariance.inv a).comp a = Covariance.id N := by +lemma inv_comp (a : N.Covariance) : (Covariance.inv a).comp a = Covariance.id N := by refine Covariance.ext ?_ fun Λ x e => ?_ · simp [Covariance.comp, Covariance.inv, Covariance.id, Equiv.self_trans_symm] · rw [algebraCongr_eq_iff] @@ -185,13 +185,13 @@ noncomputable instance : Group N.Covariance where inv_mul_cancel := Covariance.inv_comp /-- The group multiplication is composition of covariances. -/ -theorem mul_def (a b : N.Covariance) : a * b = a.comp b := rfl +lemma mul_def (a b : N.Covariance) : a * b = a.comp b := rfl /-- The group unit is the identity covariance. -/ -theorem one_def : (1 : N.Covariance) = Covariance.id N := rfl +lemma one_def : (1 : N.Covariance) = Covariance.id N := rfl /-- The group inverse is the inverse covariance. -/ -theorem inv_def (a : N.Covariance) : a⁻¹ = a.inv := rfl +lemma inv_def (a : N.Covariance) : a⁻¹ = a.inv := rfl end Covariance diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 5df7b9e..9494ac0 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -77,28 +77,28 @@ class Faithful {sites : Type*} [DecidableEq sites] (N : LocalNet sites) : Prop w def algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') : N.algebra Λ ≃⋆ₐ[ℂ] N.algebra Λ' := by subst h; exact StarAlgEquiv.refl -@[simp] theorem algebraCongr_apply {Λ : Finset sites} (x : N.algebra Λ) : +@[simp] lemma algebraCongr_apply {Λ : Finset sites} (x : N.algebra Λ) : N.algebraCongr (rfl : Λ = Λ) x = x := rfl /-- The isotony embeddings are natural with respect to the region-equality transport. -/ -theorem incl_algebraCongr {Λ₁ Λ₂ Λ₁' Λ₂' : Finset sites} (e₁ : Λ₁ = Λ₁') (e₂ : Λ₂ = Λ₂') +lemma incl_algebraCongr {Λ₁ Λ₂ Λ₁' Λ₂' : Finset sites} (e₁ : Λ₁ = Λ₁') (e₂ : Λ₂ = Λ₂') (h : Λ₁ ⊆ Λ₂) (h' : Λ₁' ⊆ Λ₂') (x : N.algebra Λ₁) : N.algebraCongr e₂ (N.incl h x) = N.incl h' (N.algebraCongr e₁ x) := by subst e₁; subst e₂; rfl /-- Transports along composable region equalities compose. -/ -@[simp] theorem algebraCongr_trans {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁ : Λ₁ = Λ₂) (h₂ : Λ₂ = Λ₃) +@[simp] lemma algebraCongr_trans {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁ : Λ₁ = Λ₂) (h₂ : Λ₂ = Λ₃) (x : N.algebra Λ₁) : N.algebraCongr h₂ (N.algebraCongr h₁ x) = N.algebraCongr (h₁.trans h₂) x := by subst h₁; subst h₂; rfl /-- A transport along a reflexive region equality is the identity. -/ -@[simp] theorem algebraCongr_self {Λ : Finset sites} (h : Λ = Λ) (x : N.algebra Λ) : +@[simp] lemma algebraCongr_self {Λ : Finset sites} (h : Λ = Λ) (x : N.algebra Λ) : N.algebraCongr h x = x := by rw [Subsingleton.elim h rfl]; rfl /-- Cancelling a transport against a target value moves it to the other side. -/ -theorem algebraCongr_eq_iff {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) +lemma algebraCongr_eq_iff {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) (y : N.algebra Λ') : N.algebraCongr h x = y ↔ x = N.algebraCongr h.symm y := by subst h; simp diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean index ff48d94..413c41e 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean @@ -47,7 +47,7 @@ noncomputable abbrev quasiLocalAlgebra : Type _ := `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general direct-limit constructions, since each `algebra Λ` is a `ℂ`-`*`-algebra and `incl` is a `*`-algebra homomorphism. -/ -@[simp] theorem star_mk {Λ : Finset sites} (X : N.algebra Λ) : +@[simp] lemma star_mk {Λ : Finset sites} (X : N.algebra Λ) : star (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl /-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local @@ -58,17 +58,17 @@ noncomputable def ιLocal (Λ : Finset sites) : /-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ -@[simp] theorem ιLocal_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (X : N.algebra Λ) : +@[simp] lemma ιLocal_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (X : N.algebra Λ) : N.ιLocal Λ' (N.incl h X) = N.ιLocal Λ X := DirectLimit.Ring.of_f (G := N.algebra) (f := fun _ _ h => N.incl h) h X /-- The cocone is a `*`-homomorphism: it intertwines the local and quasi-local involutions. -/ -@[simp] theorem ιLocal_star {Λ : Finset sites} (X : N.algebra Λ) : +@[simp] lemma ιLocal_star {Λ : Finset sites} (X : N.algebra Λ) : N.ιLocal Λ (star X) = star (N.ιLocal Λ X) := (star_mk (N := N) X).symm /-- The cocone of the inductive limit absorbs the region-equality transport. -/ -@[simp] theorem ιLocal_algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) : +@[simp] lemma ιLocal_algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) : N.ιLocal Λ' (N.algebraCongr h x) = N.ιLocal Λ x := by subst h; rfl @@ -109,7 +109,7 @@ variable [N.Faithful] noncomputable instance : NormedRing N.quasiLocalAlgebra := DirectLimit.cstarNormedRing (fun _ _ h => Faithful.incl_injective h) -@[simp] theorem norm_mk {Λ : Finset sites} (X : N.algebra Λ) : +@[simp] lemma norm_mk {Λ : Finset sites} (X : N.algebra Λ) : ‖(⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl /-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ @@ -178,12 +178,12 @@ noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalA rw [a.β_incl h] exact N.ιLocal_incl _ _) -@[simp] theorem quasiLocalCovariance_mk {Λ : Finset sites} (X : N.algebra Λ) : +@[simp] lemma quasiLocalCovariance_mk {Λ : Finset sites} (X : N.algebra Λ) : a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := rfl /-- The covariance action of the identity covariance is the identity: `β_{id} = id`. -/ -@[simp] theorem quasiLocalCovariance_id : +@[simp] lemma quasiLocalCovariance_id : (Covariance.id N).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with @@ -191,7 +191,7 @@ noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalA /-- **Functoriality of the covariance action**: composing covariances composes their actions, `β_{a∘b} = β_a ∘ β_b`. -/ -@[simp] theorem quasiLocalCovariance_comp (a b : N.Covariance) : +@[simp] lemma quasiLocalCovariance_comp (a b : N.Covariance) : (a.comp b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with @@ -200,19 +200,19 @@ noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalA exact N.ιLocal_algebraCongr _ _ /-- The covariance action sends the unit covariance to the identity: `β_1 = id`. -/ -@[simp] theorem quasiLocalCovariance_one : +@[simp] lemma quasiLocalCovariance_one : (1 : N.Covariance).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by rw [one_def, quasiLocalCovariance_id] /-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. -/ -theorem quasiLocalCovariance_mul (a b : N.Covariance) : +lemma quasiLocalCovariance_mul (a b : N.Covariance) : (a * b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by rw [mul_def, quasiLocalCovariance_comp] /-! #### The covariance action as a `*`-automorphism -/ /-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ -theorem quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : +lemma quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : a.quasiLocalCovariance (c • z) = c • a.quasiLocalCovariance z := by induction z using DirectLimit.induction with | _ Λ X => @@ -222,7 +222,7 @@ theorem quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : /-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` is a `*`-isomorphism. -/ -theorem quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : +lemma quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : a.quasiLocalCovariance (star z) = star (a.quasiLocalCovariance z) := by induction z using DirectLimit.induction with | _ Λ X => @@ -246,10 +246,10 @@ noncomputable def quasiLocalCovarianceEquiv : map_smul' := a.quasiLocalCovariance_smul map_star' := a.quasiLocalCovariance_star -@[simp] theorem quasiLocalCovarianceEquiv_apply (z : N.quasiLocalAlgebra) : +@[simp] lemma quasiLocalCovarianceEquiv_apply (z : N.quasiLocalAlgebra) : a.quasiLocalCovarianceEquiv z = a.quasiLocalCovariance z := rfl -@[simp] theorem quasiLocalCovarianceEquiv_symm_apply (z : N.quasiLocalAlgebra) : +@[simp] lemma quasiLocalCovarianceEquiv_symm_apply (z : N.quasiLocalAlgebra) : a.quasiLocalCovarianceEquiv.symm z = a⁻¹.quasiLocalCovariance z := rfl /-- A covariance of the net acts on the algebra of local observables by `*`-algebra automorphisms, @@ -266,7 +266,7 @@ noncomputable def quasiLocalCovarianceHom : simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_mul, RingHom.comp_apply, StarAlgEquiv.mul_apply] -@[simp] theorem quasiLocalCovarianceHom_apply (z : N.quasiLocalAlgebra) : +@[simp] lemma quasiLocalCovarianceHom_apply (z : N.quasiLocalAlgebra) : quasiLocalCovarianceHom a z = a.quasiLocalCovariance z := rfl /-! #### The covariance automorphism of the quasi-local C⋆-algebra -/ @@ -277,7 +277,7 @@ variable [N.Faithful] /-- The covariance action is **isometric** on the algebra of local observables: each `β` is a `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ -theorem quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : +lemma quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : ‖a.quasiLocalCovariance z‖ = ‖z‖ := by induction z using DirectLimit.induction with | _ Λ X => @@ -286,14 +286,14 @@ theorem quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : /-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is an isometry), so it extends to the C⋆-completion. -/ -theorem quasiLocalCovarianceEquiv_uniformContinuous : +lemma quasiLocalCovarianceEquiv_uniformContinuous : UniformContinuous a.quasiLocalCovarianceEquiv := (AddMonoidHomClass.isometry_of_norm _ (fun z => by rw [quasiLocalCovarianceEquiv_apply]; exact a.quasiLocalCovariance_norm z)).uniformContinuous /-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is also an isometry). -/ -theorem quasiLocalCovarianceEquiv_symm_uniformContinuous : +lemma quasiLocalCovarianceEquiv_symm_uniformContinuous : UniformContinuous a.quasiLocalCovarianceEquiv.symm := by have h : ∀ z, ‖a.quasiLocalCovarianceEquiv.symm z‖ = ‖z‖ := fun z => by rw [quasiLocalCovarianceEquiv_symm_apply]; exact a⁻¹.quasiLocalCovariance_norm z @@ -307,12 +307,12 @@ noncomputable def quasiLocalCStarCovarianceEquiv : a.quasiLocalCovarianceEquiv_uniformContinuous a.quasiLocalCovarianceEquiv_symm_uniformContinuous -@[simp] theorem quasiLocalCStarCovarianceEquiv_coe (z : N.quasiLocalAlgebra) : +@[simp] lemma quasiLocalCStarCovarianceEquiv_coe (z : N.quasiLocalAlgebra) : a.quasiLocalCStarCovarianceEquiv (↑z : N.quasiLocalCStarAlgebra) = ↑(a.quasiLocalCovariance z) := UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z -theorem quasiLocalCStarCovarianceEquiv_continuous : +lemma quasiLocalCStarCovarianceEquiv_continuous : Continuous (⇑a.quasiLocalCStarCovarianceEquiv) := UniformSpace.Completion.continuous_map @@ -339,7 +339,7 @@ noncomputable def quasiLocalCStarCovarianceHom : intro w simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_mul, RingHom.comp_apply] -@[simp] theorem quasiLocalCStarCovarianceHom_apply +@[simp] lemma quasiLocalCStarCovarianceHom_apply (z : N.quasiLocalCStarAlgebra) : quasiLocalCStarCovarianceHom a z = a.quasiLocalCStarCovarianceEquiv z := rfl diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean index 3930d73..b8477d3 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean @@ -50,7 +50,7 @@ theorem isFactor_boundedLinearOperators : IsFactor (⊤ : VonNeumannAlgebra H) : /-- **A rank-one projection is minimal in `B(H)`.** For a unit vector `u`, the rank-one orthogonal projection `|u⟩⟨u|` is a minimal projection of `⊤`: it is a star projection, nonzero, and its corner is trivial because `|u⟩⟨u| ∘ a ∘ |u⟩⟨u| = ⟪u, a u⟫ • |u⟩⟨u|`. -/ -theorem isMinimalProjection_rankOne_boundedLinearOperators {u : H} (hu : ‖u‖ = 1) : +lemma isMinimalProjection_rankOne_boundedLinearOperators {u : H} (hu : ‖u‖ = 1) : IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := by have hu_ne : u ≠ 0 := by rw [← norm_pos_iff, hu]; norm_num refine ⟨⟨isIdempotentElem_rankOne_self hu, ?_⟩, mem_top _, diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean index a610883..4f975c5 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean @@ -35,11 +35,11 @@ def IsCentralProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := IsStarProjection e ∧ e ∈ N ∧ e ∈ N.commutant /-- `0` is a central projection. -/ -theorem isCentralProjection_zero (N : VonNeumannAlgebra H) : IsCentralProjection N 0 := +lemma isCentralProjection_zero (N : VonNeumannAlgebra H) : IsCentralProjection N 0 := ⟨IsStarProjection.zero _, zero_mem _, zero_mem _⟩ /-- `1` is a central projection. -/ -theorem isCentralProjection_one (N : VonNeumannAlgebra H) : IsCentralProjection N 1 := +lemma isCentralProjection_one (N : VonNeumannAlgebra H) : IsCentralProjection N 1 := ⟨IsStarProjection.one _, one_mem _, one_mem _⟩ /-- In a factor, every central projection is trivial: it is `0` or `1`. This is the diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean index d7983ad..ed7380d 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean @@ -48,23 +48,23 @@ namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] /-- The source projection of a Murray–von Neumann equivalence is a star projection. -/ -theorem MvNEquiv.isStarProjection_left {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} +lemma MvNEquiv.isStarProjection_left {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} (h : p ∼[N] q) : IsStarProjection p := by obtain ⟨v, _, hpi, hvp, _⟩ := h; exact hvp ▸ hpi.isStarProjection_star_mul_self /-- The range projection of a Murray–von Neumann equivalence is a star projection. -/ -theorem MvNEquiv.isStarProjection_right {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} +lemma MvNEquiv.isStarProjection_right {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} (h : p ∼[N] q) : IsStarProjection q := by obtain ⟨v, _, hpi, _, hvq⟩ := h; exact hvq ▸ hpi.isStarProjection_mul_star_self /-- For projections, the subprojection relation `e * f = f` is left/right symmetric. -/ -theorem isStarProjection_subproj_comm {R : Type*} [Ring R] [StarRing R] {e f : R} +lemma isStarProjection_subproj_comm {R : Type*} [Ring R] [StarRing R] {e f : R} (he : IsStarProjection e) (hf : IsStarProjection f) (h : e * f = f) : f * e = f := by have := congrArg star h rwa [star_mul, he.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this /-- The source projection of a partial isometry acts as a right identity. -/ -theorem IsPartialIsometry.mul_source {R : Type*} [Monoid R] [StarMul R] {v : R} +lemma IsPartialIsometry.mul_source {R : Type*} [Monoid R] [StarMul R] {v : R} (h : IsPartialIsometry v) : v * (star v * v) = v := by rw [← mul_assoc]; exact h /-- `p ≼ q` in `N`: `p` is Murray–von Neumann equivalent to a subprojection of `q`. -/ @@ -76,7 +76,7 @@ equivalent to a subprojection of `q` inside `N`. -/ scoped notation:50 p:51 " ≼[" N "] " q:51 => MvNSub N p q /-- Subordination is reflexive on projections of `N`. -/ -theorem MvNSub.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} +lemma MvNSub.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} (hp : IsStarProjection p) (hpN : p ∈ N) : p ≼[N] p := ⟨p, hpN, hp.isIdempotentElem, MvNEquiv.refl hp hpN⟩ @@ -110,7 +110,7 @@ theorem MvNEquiv.exists_subproj_equiv {N : VonNeumannAlgebra H} {q r' q' : H → rw [← mul_assoc q' q' (star w), hq'.isIdempotentElem] /-- Subordination is transitive: `≼` is a preorder on the projections of `N`. -/ -theorem MvNSub.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} +lemma MvNSub.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} (hpq : p ≼[N] q) (hqr : q ≼[N] r) : p ≼[N] r := by obtain ⟨q', hq'N, hqsub, hpq'⟩ := hpq obtain ⟨r', hr'N, hrsub, hqr'⟩ := hqr @@ -155,7 +155,7 @@ theorem mvNSub_of_posCorner {N : VonNeumannAlgebra H} {e q a : H →L[ℂ] H} `q a e ≠ 0`, the corner element `(q a e)⋆ (q a e) = e (a⋆ q a) e` equals a *strictly positive real* scalar multiple of `e`. (Reality comes from self-adjointness; strict positivity from evaluating on a nonzero vector of `e H` on which `q a e` does not vanish.) -/ -theorem IsMinimalProjection.posCorner {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma IsMinimalProjection.posCorner {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : ∃ c : ℝ, 0 < c ∧ star (q * a * e) * (q * a * e) = (c : ℂ) • e := by @@ -202,7 +202,7 @@ theorem IsMinimalProjection.posCorner {N : VonNeumannAlgebra H} {e : H →L[ℂ] /-- A minimal projection is subordinate to any projection it "meets": if some `a ∈ N` has `q a e ≠ 0`, then `e ≼ q`. Combined with central supports (which guarantee `q a e ≠ 0` for every nonzero `q` in a factor) this yields the comparison theorem `minimal e ≼ q`. -/ -theorem IsMinimalProjection.mvNSub_of_ne {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma IsMinimalProjection.mvNSub_of_ne {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : e ≼[N] q := by obtain ⟨c, hcpos, hcorner⟩ := he.posCorner hq hqN haN hne diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean index 82440e2..a7eed32 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean @@ -36,7 +36,7 @@ namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] /-- The range projection of a Murray–von Neumann equivalence with nonzero source is nonzero. -/ -theorem MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} +lemma MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} (h : p ∼[N] q) (hp : p ≠ 0) : q ≠ 0 := by obtain ⟨v, _, hvpi, hvp, hvq⟩ := h intro hq0 @@ -50,7 +50,7 @@ theorem MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} /-- **Minimality transports along Murray–von Neumann equivalence.** If `e` is a minimal projection and `e ∼[N] p`, then `p` is minimal: with `v⋆v = e` and `vv⋆ = p`, the corner computes as `p a p = v (e (v⋆ a v) e) v⋆ = c • v e v⋆ = c • p`. -/ -theorem IsMinimalProjection.of_mvNEquiv {N : VonNeumannAlgebra H} {e p : H →L[ℂ] H} +lemma IsMinimalProjection.of_mvNEquiv {N : VonNeumannAlgebra H} {e p : H →L[ℂ] H} (he : IsMinimalProjection N e) (h : e ∼[N] p) : IsMinimalProjection N p := by have hpproj : IsStarProjection p := h.isStarProjection_right have hp0 : p ≠ 0 := h.ne_zero he.2.2.1 @@ -80,13 +80,13 @@ def OrthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ /-- When `e` is minimal, every member of an `OrthEquivFam` for `e` is itself a minimal projection, since minimality transports along `∼[N]` (`IsMinimalProjection.of_mvNEquiv`). -/ -theorem OrthEquivFam.isMinimalProjection_of_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma OrthEquivFam.isMinimalProjection_of_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) {p : H →L[ℂ] H} (hp : p ∈ F) : IsMinimalProjection N p := he.of_mvNEquiv (hF.1 p hp).2.2.2 /-- By Zorn's lemma, there is a maximal orthogonal family of `e`-equivalent projections. -/ -theorem exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : +lemma exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : ∃ F, OrthEquivFam N e F ∧ ∀ G, OrthEquivFam N e G → F ⊆ G → G ⊆ F := by obtain ⟨F, hFmax⟩ := zorn_subset {F | OrthEquivFam N e F} (by intro c hcsub hchain @@ -101,7 +101,7 @@ theorem exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H /-- The orthogonal projection onto the closed span of the ranges of an `OrthEquivFam` lies in `N`, because that subspace is invariant under the commutant `N'`: for `y ∈ N'` and `f ∈ F ⊆ N`, `y (f x) = (y f) x = (f y) x = f (y x)` lies in the range of `f`. -/ -theorem OrthEquivFam.starProjection_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma OrthEquivFam.starProjection_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure.starProjection ∈ N := by set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean index a2c4eba..28f7942 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean @@ -43,7 +43,7 @@ namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] /-- A von Neumann algebra is closed under scalar multiplication. -/ -theorem smul_mem {N : VonNeumannAlgebra H} (c : ℂ) {x : H →L[ℂ] H} (hx : x ∈ N) : c • x ∈ N := by +lemma smul_mem {N : VonNeumannAlgebra H} (c : ℂ) {x : H →L[ℂ] H} (hx : x ∈ N) : c • x ∈ N := by rw [Algebra.smul_def] exact mul_mem (algebraMap_mem N.toStarSubalgebra c) hx @@ -62,7 +62,7 @@ def IsMinimalProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := /-- A von Neumann algebra with a minimal projection acts on a nonzero space: the minimal projection is nonzero, so it sends some vector to a nonzero vector, witnessing `Nontrivial H`. -/ -theorem IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : Nontrivial H := let ⟨x, hx⟩ := ContinuousLinearMap.exists_ne_zero he.2.2.1 ⟨⟨e x, 0, hx⟩⟩ @@ -71,7 +71,7 @@ theorem IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ satisfies `f ≤ e` (the Loewner order on projections, equivalently the range inclusion `ran f ⊆ ran e`, written algebraically as `e * f = f`), then `f = 0` or `f = e`. This recovers the order-theoretic form of minimality from the corner definition `e N e = ℂ e`. -/ -theorem IsMinimalProjection.no_proper_subprojection {N : VonNeumannAlgebra H} +lemma IsMinimalProjection.no_proper_subprojection {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} (he : IsMinimalProjection N e) {f : H →L[ℂ] H} (hf : IsStarProjection f) (hfN : f ∈ N) (hsub : e * f = f) : f = 0 ∨ f = e := by @@ -101,7 +101,7 @@ def IsAbelianProjection (N : VonNeumannAlgebra H) (p : H →L[ℂ] H) : Prop := /-- A minimal projection is abelian: its corner `e N e = ℂ e` is one-dimensional, hence commutative. -/ -theorem IsMinimalProjection.isAbelianProjection {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma IsMinimalProjection.isAbelianProjection {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : IsAbelianProjection N e := by refine ⟨he.1, he.2.1, fun a haN b hbN => ?_⟩ obtain ⟨c, hc⟩ := he.2.2.2 a haN diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean index b084fb2..69ae639 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean @@ -50,7 +50,7 @@ variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteS variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} /-- The set of matrix units is contained in `N`. -/ -theorem OrthEquivFam.matrixUnit_subset (hF : OrthEquivFam N e F) : +lemma OrthEquivFam.matrixUnit_subset (hF : OrthEquivFam N e F) : Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) ⊆ (N : Set (H →L[ℂ] H)) := by rintro x ⟨pq, rfl⟩ exact hF.matrixUnit_mem pq.1 pq.2 @@ -143,7 +143,7 @@ theorem OrthEquivFam.commutes_of_mem_centralizer (hF : OrthEquivFam N e F) exact hL.unique hR /-- The centralizer of the matrix units is contained in the commutant of `N`. -/ -theorem OrthEquivFam.centralizer_subset_commutant (hF : OrthEquivFam N e F) +lemma OrthEquivFam.centralizer_subset_commutant (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean index 1dec276..1ad22cd 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean @@ -44,30 +44,30 @@ oriented with source projection `v_p⋆ v_p = e` (`pisom_source`) and range proj noncomputable def OrthEquivFam.pisom (hF : OrthEquivFam N e F) (p : F) : H →L[ℂ] H := (hF.1 p.1 p.2).2.2.2.choose -theorem OrthEquivFam.pisom_mem (hF : OrthEquivFam N e F) (p : F) : hF.pisom p ∈ N := +lemma OrthEquivFam.pisom_mem (hF : OrthEquivFam N e F) (p : F) : hF.pisom p ∈ N := (hF.1 p.1 p.2).2.2.2.choose_spec.1 -theorem OrthEquivFam.pisom_isPI (hF : OrthEquivFam N e F) (p : F) : +lemma OrthEquivFam.pisom_isPI (hF : OrthEquivFam N e F) (p : F) : IsPartialIsometry (hF.pisom p) := (hF.1 p.1 p.2).2.2.2.choose_spec.2.1 -theorem OrthEquivFam.pisom_source (hF : OrthEquivFam N e F) (p : F) : +lemma OrthEquivFam.pisom_source (hF : OrthEquivFam N e F) (p : F) : star (hF.pisom p) * hF.pisom p = e := (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.1 -theorem OrthEquivFam.pisom_range (hF : OrthEquivFam N e F) (p : F) : +lemma OrthEquivFam.pisom_range (hF : OrthEquivFam N e F) (p : F) : hF.pisom p * star (hF.pisom p) = (p : H →L[ℂ] H) := (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.2 /-- `v_p e = v_p`: the source projection acts as a right unit on `v_p`. -/ -theorem OrthEquivFam.pisom_mul_source (hF : OrthEquivFam N e F) (p : F) : +lemma OrthEquivFam.pisom_mul_source (hF : OrthEquivFam N e F) (p : F) : hF.pisom p * e = hF.pisom p := by have h : hF.pisom p * (star (hF.pisom p) * hF.pisom p) = hF.pisom p := by rw [← mul_assoc]; exact hF.pisom_isPI p rwa [hF.pisom_source p] at h /-- `e v_p⋆ = v_p⋆`: the source projection acts as a left unit on `v_p⋆`. -/ -theorem OrthEquivFam.e_mul_star_pisom (hF : OrthEquivFam N e F) (p : F) : +lemma OrthEquivFam.e_mul_star_pisom (hF : OrthEquivFam N e F) (p : F) : e * star (hF.pisom p) = star (hF.pisom p) := by have h : star (hF.pisom p) * hF.pisom p * star (hF.pisom p) = star (hF.pisom p) := by have h' : star (hF.pisom p) * star (star (hF.pisom p)) * star (hF.pisom p) @@ -76,7 +76,7 @@ theorem OrthEquivFam.e_mul_star_pisom (hF : OrthEquivFam N e F) (p : F) : rwa [hF.pisom_source p] at h /-- For distinct family members the partial isometries are orthogonal: `v_q⋆ v_r = 0`. -/ -theorem OrthEquivFam.star_pisom_mul_pisom_of_ne (hF : OrthEquivFam N e F) {q r : F} +lemma OrthEquivFam.star_pisom_mul_pisom_of_ne (hF : OrthEquivFam N e F) {q r : F} (hqr : q ≠ r) : star (hF.pisom q) * hF.pisom r = 0 := by have hq : (q : H →L[ℂ] H) * hF.pisom q = hF.pisom q := by have h : hF.pisom q * star (hF.pisom q) * hF.pisom q = hF.pisom q := hF.pisom_isPI q @@ -99,11 +99,11 @@ noncomputable def OrthEquivFam.matrixUnit (hF : OrthEquivFam N e F) (p q : F) : hF.pisom p * star (hF.pisom q) /-- Definitional unfolding of the matrix unit: `e_{pq} = v_p v_q⋆`. -/ -theorem OrthEquivFam.matrixUnit_def (hF : OrthEquivFam N e F) (p q : F) : +lemma OrthEquivFam.matrixUnit_def (hF : OrthEquivFam N e F) (p q : F) : hF.matrixUnit p q = hF.pisom p * star (hF.pisom q) := rfl /-- Matrix units lie in `N`. -/ -theorem OrthEquivFam.matrixUnit_mem (hF : OrthEquivFam N e F) (p q : F) : +lemma OrthEquivFam.matrixUnit_mem (hF : OrthEquivFam N e F) (p q : F) : hF.matrixUnit p q ∈ N := mul_mem (hF.pisom_mem p) (star_mem (hF.pisom_mem q)) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean index 5dc206e..77367b2 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean @@ -38,7 +38,7 @@ variable {α : Type*} {𝕜 : Type*} [RCLike 𝕜] {G G' : α → Type*} [∀ i, NormedAddCommGroup (G' i)] [∀ i, NormedSpace 𝕜 (G' i)] /-- A family of isometries preserves `Memℓp`: norms are pointwise unchanged. -/ -theorem memℓp_congr_linearIsometryEquiv (e : ∀ i, G i ≃ₗᵢ[𝕜] G' i) {f : ∀ i, G i} +lemma memℓp_congr_linearIsometryEquiv (e : ∀ i, G i ≃ₗᵢ[𝕜] G' i) {f : ∀ i, G i} (hf : Memℓp f 2) : Memℓp (fun i => e i (f i)) 2 := by apply Memℓp.of_norm have hnorm : (fun i => ‖e i (f i)‖) = fun i => ‖f i‖ := funext fun i => (e i).norm_map (f i) @@ -81,7 +81,7 @@ namespace IsPartialIsometry /-- For `x` in the source subspace (`p x = x` where `p = v⋆v`), the map preserves the norm: `‖v x‖ = ‖x‖`. -/ -theorem norm_apply {v : H →L[ℂ] H} {p : H →L[ℂ] H} +lemma norm_apply {v : H →L[ℂ] H} {p : H →L[ℂ] H} (hsource : star v * v = p) {x : H} (hx : (p : H →L[ℂ] H) x = x) : ‖v x‖ = ‖x‖ := by have hinner : (inner ℂ (v x) (v x) : ℂ) = inner ℂ x x := by rw [← ContinuousLinearMap.adjoint_inner_right, ← ContinuousLinearMap.star_eq_adjoint, @@ -94,7 +94,7 @@ theorem norm_apply {v : H →L[ℂ] H} {p : H →L[ℂ] H} /-- The image of any vector under a partial isometry lands in the range subspace: if `q = v v⋆` then `q (v x) = v x`. -/ -theorem apply_mem_range {v : H →L[ℂ] H} (hv : IsPartialIsometry v) {q : H →L[ℂ] H} +lemma apply_mem_range {v : H →L[ℂ] H} (hv : IsPartialIsometry v) {q : H →L[ℂ] H} (hrange : v * star v = q) (x : H) : (q : H →L[ℂ] H) (v x) = v x := by rw [← ContinuousLinearMap.mul_apply, ← hrange, hv] @@ -137,13 +137,13 @@ noncomputable def sourceRangeEquiv {v : H →L[ℂ] H} (hv : IsPartialIsometry v end IsPartialIsometry /-- A vector in the range of a star projection is fixed by it: `p x = x`. -/ -theorem IsStarProjection.apply_eq_self_of_mem_range {p : H →L[ℂ] H} (hp : IsStarProjection p) +lemma IsStarProjection.apply_eq_self_of_mem_range {p : H →L[ℂ] H} (hp : IsStarProjection p) {x : H} (hx : x ∈ LinearMap.range (p : H →ₗ[ℂ] H)) : (p : H →L[ℂ] H) x = x := by obtain ⟨z, rfl⟩ := hx rw [ContinuousLinearMap.coe_coe, ← ContinuousLinearMap.mul_apply, hp.isIdempotentElem] /-- The range of a star projection is closed: it equals the kernel of `1 - p`. -/ -theorem IsStarProjection.isClosed_range {p : H →L[ℂ] H} (hp : IsStarProjection p) : +lemma IsStarProjection.isClosed_range {p : H →L[ℂ] H} (hp : IsStarProjection p) : IsClosed (LinearMap.range (p : H →ₗ[ℂ] H) : Set H) := by have hker : LinearMap.range (p : H →ₗ[ℂ] H) = LinearMap.ker ((1 - p : H →L[ℂ] H) : H →ₗ[ℂ] H) := by @@ -159,13 +159,13 @@ theorem IsStarProjection.isClosed_range {p : H →L[ℂ] H} (hp : IsStarProjecti exact (1 - p).isClosed_ker /-- The range of a star projection, as a closed subspace, is complete. -/ -theorem IsStarProjection.completeSpace_range {p : H →L[ℂ] H} (hp : IsStarProjection p) : +lemma IsStarProjection.completeSpace_range {p : H →L[ℂ] H} (hp : IsStarProjection p) : CompleteSpace (LinearMap.range (p : H →ₗ[ℂ] H)) := completeSpace_coe_iff_isComplete.mpr hp.isClosed_range.isComplete /-- The inverse of the partial-isometry-induced equivalence acts as `v⋆`: for `η` in the range subspace, `(sourceRangeEquiv v).symm η = v⋆ η`. -/ -theorem IsPartialIsometry.coe_sourceRangeEquiv_symm {v : H →L[ℂ] H} (hv : IsPartialIsometry v) +lemma IsPartialIsometry.coe_sourceRangeEquiv_symm {v : H →L[ℂ] H} (hv : IsPartialIsometry v) {p q : H →L[ℂ] H} (hsource : star v * v = p) (hrange : v * star v = q) (η : LinearMap.range (q : H →ₗ[ℂ] H)) : ((hv.sourceRangeEquiv hsource hrange).symm η : H) = star v (η : H) := by @@ -190,7 +190,7 @@ namespace VonNeumannAlgebra /-- A covering orthogonal family of star projections (each in `OrthEquivFam`) realises `H` as the internal Hilbert sum of the ranges. -/ -theorem OrthEquivFam.isHilbertSum {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma OrthEquivFam.isHilbertSum {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : IsHilbertSum ℂ (fun i : F => LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) @@ -244,7 +244,7 @@ noncomputable def OrthEquivFam.multiplicityEquiv {N : VonNeumannAlgebra H} {e : /-- The `i`-th Hilbert-sum coordinate of `y`, embedded back into `H`, is the orthogonal projection `(↑i) y`. This identifies the abstract Hilbert-sum decomposition with the explicit family of range projections. -/ -theorem OrthEquivFam.coe_hilbertSumEquiv_apply {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} +lemma OrthEquivFam.coe_hilbertSumEquiv_apply {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) (y : H) (i : F) : diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index 7470416..cfaf968 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -76,7 +76,7 @@ theorem amplifyRight_mem_vnTensorRight (B : H₂ →L[ℂ] H₂) : /-- The commutant of `B(H₁) ⊗̄ 1` is the commutant of the range of `amplifyLeft` (bicommutant collapse). This reduces the tensor commutation theorem `vnTensorLeft.commutant = vnTensorRight` to the identity `(range amplifyLeft)' = 1 ⊗̄ B(H₂)`. -/ -theorem vnTensorLeft_commutant_eq_commutantSet : +lemma vnTensorLeft_commutant_eq_commutantSet : (vnTensorLeft (H₁ := H₁) (H₂ := H₂)).commutant = VonNeumannAlgebra.commutantSet (Set.range (amplifyLeft (H₂ := H₂))) := VonNeumannAlgebra.commutant_generated _ @@ -97,7 +97,7 @@ noncomputable def tmulRightL (f : H₁) : H₂ →L[ℂ] HilbertTensor H₁ H₂ (LinearMap.mkContinuous (TensorProduct.mk ℂ H₁ H₂ f) ‖f‖ fun z => by rw [TensorProduct.mk_apply, TensorProduct.norm_tmul]) -@[simp] theorem tmulRightL_apply (f : H₁) (z : H₂) : tmulRightL f z = tmul f z := rfl +@[simp] lemma tmulRightL_apply (f : H₁) (z : H₂) : tmulRightL f z = tmul f z := rfl /-- The left and right amplifications commute: `(A ⊗̂ 1)(1 ⊗̂ B) = A ⊗̂ B = (1 ⊗̂ B)(A ⊗̂ 1)`. -/ theorem amplifyLeft_comp_amplifyRight (A : H₁ →L[ℂ] H₁) (B : H₂ →L[ℂ] H₂) : @@ -119,7 +119,7 @@ variable [CompleteSpace H₂] /-- The adjoint of the inclusion `ι_e` acts on pure tensors as the `e`-slice `g ⊗ z ↦ ⟪e, g⟫ • z`. -/ -theorem adjoint_tmulRightL_tmul (e g : H₁) (z : H₂) : +lemma adjoint_tmulRightL_tmul (e g : H₁) (z : H₂) : ContinuousLinearMap.adjoint (tmulRightL (H₂ := H₂) e) (tmul g z) = (inner ℂ e g) • z := by refine ext_inner_right ℂ fun y => ?_ rw [ContinuousLinearMap.adjoint_inner_left, tmulRightL_apply, inner_tmul, inner_smul_left, @@ -128,7 +128,7 @@ theorem adjoint_tmulRightL_tmul (e g : H₁) (z : H₂) : /-- The amplification of a rank-one operator `|f⟩⟨e|` factors through the `e`-slice and the inclusion `ι_f`: `(|f⟩⟨e|) ⊗̂ 1 = ι_f ∘ ι_e*`. This is the algebraic heart of the slice argument. -/ -theorem amplifyLeft_rankOne_eq (e f : H₁) : +lemma amplifyLeft_rankOne_eq (e f : H₁) : amplifyLeft (H₂ := H₂) (InnerProductSpace.rankOne ℂ f e) = (tmulRightL f).comp (ContinuousLinearMap.adjoint (tmulRightL e)) := by refine ContinuousLinearMap.ext fun w => ?_ @@ -149,7 +149,7 @@ amplifications `(|f⟩⟨e|) ⊗̂ 1` for `f` ranging over a set `D` whose span fixed unit vector `e ∈ H₁`), then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e`. The relation `T (f ⊗̂ y) = f ⊗̂ (S y)` is first established for `f ∈ D` and then extended to all `f` by density, working at the level of the bounded inclusions `ι_y : f ↦ f ⊗̂ y`. -/ -theorem exists_amplifyRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) +lemma exists_amplifyRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) (hD : Dense (Submodule.span ℂ D : Set H₁)) (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) (hT : ∀ f ∈ D, T.comp (amplifyLeft (InnerProductSpace.rankOne ℂ f e)) @@ -193,7 +193,7 @@ theorem exists_amplifyRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : /-- **Slice lemma (dense form).** If `T` commutes with the rank-one amplifications `(|f⟩⟨e|) ⊗̂ 1` for `f` ranging over a set `D` whose span is dense in `H₁` (and a fixed unit vector `e ∈ H₁`), then `T = 1 ⊗̂ S`, hence `T ∈ 1 ⊗̄ B(H₂)`. -/ -theorem mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) +lemma mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : Set H₁) (hD : Dense (Submodule.span ℂ D : Set H₁)) (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) (hT : ∀ f ∈ D, T.comp (amplifyLeft (InnerProductSpace.rankOne ℂ f e)) @@ -204,7 +204,7 @@ theorem mem_vnTensorRight_of_commutes_dense (e : H₁) (he : ‖e‖ = 1) (D : S /-- **Slice lemma (explicit representation).** If `T` commutes with every left amplification `A ⊗̂ 1`, then `T = 1 ⊗̂ S` for `S = ι_e* ∘ T ∘ ι_e` (any unit vector `e ∈ H₁`). -/ -theorem exists_amplifyRight_of_commutes (e : H₁) (he : ‖e‖ = 1) +lemma exists_amplifyRight_of_commutes (e : H₁) (he : ‖e‖ = 1) (T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) (hT : ∀ A : H₁ →L[ℂ] H₁, T.comp (amplifyLeft A) = (amplifyLeft A).comp T) : ∃ S : H₂ →L[ℂ] H₂, T = amplifyRight S := @@ -266,7 +266,7 @@ theorem vnTensorRight_commutant [CompleteSpace H₁] [CompleteSpace H₂] [Nontr /-- The right amplification `B ↦ 1 ⊗̂ B` is injective (for nontrivial `H₁`): evaluating on pure tensors `f ⊗̂ y` with `f ≠ 0` recovers `B y` up to the norm factor `‖f‖`. -/ -theorem amplifyRight_injective [Nontrivial H₁] : +lemma amplifyRight_injective [Nontrivial H₁] : Function.Injective (amplifyRight (H₁ := H₁) (H₂ := H₂)) := by intro B₁ B₂ h obtain ⟨f, hf⟩ := exists_ne (0 : H₁) @@ -286,7 +286,7 @@ theorem amplifyRight_injective [Nontrivial H₁] : `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)` is a scalar: by the slice lemma it is `1 ⊗̂ S`, membership in `B(H₁) ⊗̄ 1 = (1 ⊗̄ B(H₂))'` makes `S` commute with all of `B(H₂)` — in particular with every rank-one operator — so `S` is scalar. -/ -theorem eq_smul_one_of_mem_vnTensorLeft_of_mem_vnTensorRight +lemma eq_smul_one_of_mem_vnTensorLeft_of_mem_vnTensorRight [CompleteSpace H₁] [CompleteSpace H₂] [Nontrivial H₁] {x : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂} (hL : x ∈ vnTensorLeft (H₁ := H₁) (H₂ := H₂)) (hR : x ∈ vnTensorRight) : @@ -339,7 +339,7 @@ is a `⋆`-isomorphism `B(H₁) ≃⋆ₐ B(H₁) ⊗̄ 1` (`amplifyLeftStarAlgE /-- The left amplification `A ↦ A ⊗̂ 1` is injective (for nontrivial `H₂`): evaluating on pure tensors `x ⊗̂ g` with `g ≠ 0` recovers `A x` up to the norm factor `‖g‖`. -/ -theorem amplifyLeft_injective [Nontrivial H₂] : +lemma amplifyLeft_injective [Nontrivial H₂] : Function.Injective (amplifyLeft (H₁ := H₁) (H₂ := H₂)) := by intro A₁ A₂ h obtain ⟨g, hg⟩ := exists_ne (0 : H₂) @@ -358,7 +358,7 @@ theorem amplifyLeft_injective [Nontrivial H₂] : /-- Every right amplification `1 ⊗̂ B` commutes with the factor `B(H₁) ⊗̄ 1`, i.e. lies in its commutant. This is the easy inclusion of the commutation theorem and needs no completeness or nontriviality hypotheses. -/ -theorem amplifyRight_mem_commutant_vnTensorLeft [CompleteSpace H₁] (B : H₂ →L[ℂ] H₂) : +lemma amplifyRight_mem_commutant_vnTensorLeft [CompleteSpace H₁] (B : H₂ →L[ℂ] H₂) : amplifyRight (H₁ := H₁) B ∈ (vnTensorLeft (H₁ := H₁) (H₂ := H₂)).commutant := by rw [vnTensorLeft_commutant_eq_commutantSet, VonNeumannAlgebra.mem_commutantSet_iff] rintro h ⟨A, rfl⟩ @@ -373,7 +373,7 @@ theorem amplifyRight_mem_commutant_vnTensorLeft [CompleteSpace H₁] (B : H₂ right amplification (`amplifyRight_mem_commutant_vnTensorLeft`); transporting through the swap equivalence `commEquiv` turns this into commutation with every left amplification on the swapped space, where the slice lemma `exists_amplifyRight_of_commutes` produces the operator. -/ -theorem exists_amplifyLeft_of_mem_vnTensorLeft [CompleteSpace H₁] [Nontrivial H₂] +lemma exists_amplifyLeft_of_mem_vnTensorLeft [CompleteSpace H₁] [Nontrivial H₂] {T : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂} (hT : T ∈ vnTensorLeft (H₁ := H₁) (H₂ := H₂)) : ∃ A : H₁ →L[ℂ] H₁, T = amplifyLeft A := by diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean index 3920930..dc92060 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean @@ -55,17 +55,17 @@ hypotheses throughout this file.) -/ local notation "δ" => lpDelta omit [CompleteSpace H] in -theorem lpDelta_apply [DecidableEq F] (i : F) : +lemma lpDelta_apply [DecidableEq F] (i : F) : lpDelta i = lp.single (E := fun _ : F => ℂ) 2 i (1 : ℂ) := rfl omit [CompleteSpace H] in /-- The basis vectors `δ_i` are unit vectors. -/ -theorem lpDelta_norm [DecidableEq F] (i : F) : ‖lpDelta i‖ = 1 := by +lemma lpDelta_norm [DecidableEq F] (i : F) : ‖lpDelta i‖ = 1 := by rw [lpDelta_apply, lp.norm_single (by norm_num), norm_one] omit [CompleteSpace H] in /-- The standard basis vectors `δ_i` span a dense subspace of `ℓ²(F)`. -/ -theorem dense_span_lpDelta [DecidableEq F] : +lemma dense_span_lpDelta [DecidableEq F] : Dense (Submodule.span ℂ (Set.range (lpDelta : F → lp (fun _ : F => ℂ) 2)) : Set (lp (fun _ : F => ℂ) 2)) := by intro g @@ -121,7 +121,7 @@ attribute [local irreducible] OrthEquivFam.spatialEquiv OrthEquivFam.multiplicit /-- The `p`-th coordinate of `U (e_{pq} y)` collapses to the single term `δ_p ⊗̂ (v_q⋆ y)`: every other coordinate vanishes because `v_i⋆ e_{pq} = 0` for `i ≠ p`. -/ -theorem OrthEquivFam.spatialEquiv_matrixUnit_apply (hF : OrthEquivFam N e F) +lemma OrthEquivFam.spatialEquiv_matrixUnit_apply (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) (y : H) : hF.spatialEquiv htop (hF.matrixUnit p q y) @@ -139,7 +139,7 @@ theorem OrthEquivFam.spatialEquiv_matrixUnit_apply (hF : OrthEquivFam N e F) Subtype.ext (by rw [hcoe]; rfl), ← tmulRightL_apply, map_zero] /-- The surviving coordinates agree: `v_p⋆ (e_{pq} y) = v_q⋆ y`. -/ -theorem OrthEquivFam.multiplicityEquiv_matrixUnit_coord (hF : OrthEquivFam N e F) +lemma OrthEquivFam.multiplicityEquiv_matrixUnit_coord (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) (p q : F) (y : H) : hF.multiplicityEquiv htop (hF.matrixUnit p q y) p = hF.multiplicityEquiv htop y q := by @@ -151,7 +151,7 @@ theorem OrthEquivFam.multiplicityEquiv_matrixUnit_coord (hF : OrthEquivFam N e F /-- The amplified rank-one operator on `U y` collapses to the single term `δ_p ⊗̂ (v_q⋆ y)`: the rank-one operator picks out the `q`-th coordinate. -/ -theorem OrthEquivFam.amplifyLeft_rankOne_spatialEquiv (hF : OrthEquivFam N e F) +lemma OrthEquivFam.amplifyLeft_rankOne_spatialEquiv (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) (y : H) : amplifyLeft (InnerProductSpace.rankOne ℂ (δ p) (δ q)) (hF.spatialEquiv htop y) @@ -180,7 +180,7 @@ theorem OrthEquivFam.amplifyLeft_rankOne_spatialEquiv (hF : OrthEquivFam N e F) /-- **Intertwining relation.** The spatial isomorphism intertwines the matrix unit `e_{pq}` with the amplified rank-one operator: `U (e_{pq} y) = (|δ_p⟩⟨δ_q| ⊗̂ 1) (U y)`. -/ -theorem OrthEquivFam.spatialEquiv_intertwine (hF : OrthEquivFam N e F) +lemma OrthEquivFam.spatialEquiv_intertwine (hF : OrthEquivFam N e F) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] [DecidableEq F] (p q : F) (y : H) : hF.spatialEquiv htop (hF.matrixUnit p q y) @@ -211,7 +211,7 @@ proof computes the commutant: an operator commuting with all the amplified rank- in `1 ⊗̄ B(eH)` (the dense slice lemma, using that `{δ_p}` spans densely), and conversely `1 ⊗̄ B(eH)` commutes with them; so the commutant is `vnTensorRight`, whose commutant is `vnTensorLeft`. -/ -theorem generated_amplifyLeft_rankOne_eq [Nonempty F] [DecidableEq F] +lemma generated_amplifyLeft_rankOne_eq [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] : VonNeumannAlgebra.generated (Set.range (fun pq : F × F => amplifyLeft (H₂ := LinearMap.range (e : H →ₗ[ℂ] H)) @@ -294,7 +294,7 @@ theorem OrthEquivFam.conj_spatialEquiv_commutant_eq_vnTensorRight (hF : OrthEqui /-- **Split inclusion (left factor).** Any von Neumann subalgebra `A₁ ≤ N` of the type I factor `N` is carried by the spatial isomorphism into the left tensor factor: `U A₁ U⋆ ≤ B(ℓ²(F)) ⊗̄ 1`. This is monotonicity of spatial conjugation composed with `U N U⋆ = vnTensorLeft`. -/ -theorem OrthEquivFam.conj_spatialEquiv_le_vnTensorLeft (hF : OrthEquivFam N e F) +lemma OrthEquivFam.conj_spatialEquiv_le_vnTensorLeft (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] @@ -306,7 +306,7 @@ theorem OrthEquivFam.conj_spatialEquiv_le_vnTensorLeft (hF : OrthEquivFam N e F) (equivalently `A₂ ⊆ N'`) is carried by the spatial isomorphism into the right tensor factor: `U A₂ U⋆ ≤ 1 ⊗̄ B(eH)`. The hypothesis `N ≤ A₂'` is the split-property condition; taking commutants turns it into `A₂ ≤ N'`, and monotonicity composed with `U N' U⋆ = vnTensorRight` finishes. -/ -theorem OrthEquivFam.conj_spatialEquiv_le_vnTensorRight (hF : OrthEquivFam N e F) +lemma OrthEquivFam.conj_spatialEquiv_le_vnTensorRight (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] @@ -321,7 +321,7 @@ theorem OrthEquivFam.conj_spatialEquiv_le_vnTensorRight (hF : OrthEquivFam N e F omit [CompleteSpace H] in /-- A covering orthogonal family of a nonzero Hilbert space is nonempty: its ranges span a dense subspace, which would be `{0}` were the family empty. -/ -theorem OrthEquivFam.nonempty_of_top [Nontrivial H] {F : Set (H →L[ℂ] H)} +lemma OrthEquivFam.nonempty_of_top [Nontrivial H] {F : Set (H →L[ℂ] H)} (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : Nonempty F := by rw [← not_isEmpty_iff] diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean index 2e55b51..2f2ec26 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -59,7 +59,7 @@ def IsTypeI (N : VonNeumannAlgebra H) : Prop := /-- A factor with a minimal projection is type I: the only nonzero central projection of a factor is `1` (`central_projection_eq`), and it dominates the minimal projection, which is abelian and nonzero. -/ -theorem IsFactor.isTypeI_of_exists_isMinimalProjection [Nontrivial H] {N : VonNeumannAlgebra H} +lemma IsFactor.isTypeI_of_exists_isMinimalProjection [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) (h : ∃ e : H →L[ℂ] H, IsMinimalProjection N e) : IsTypeI N := by obtain ⟨e, he⟩ := h intro z hz hz0 @@ -158,14 +158,14 @@ def cornerNonUnitalStarSubalgebra (N : VonNeumannAlgebra H) {p : H →L[ℂ] H} rwa [star_mul, hp.isSelfAdjoint.star_eq] at h /-- Membership in the corner subalgebra, unfolded. -/ -theorem mem_cornerNonUnitalStarSubalgebra_iff {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} +lemma mem_cornerNonUnitalStarSubalgebra_iff {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} {hp : IsStarProjection p} {y : H →L[ℂ] H} : y ∈ cornerNonUnitalStarSubalgebra N hp ↔ y ∈ N ∧ p * y = y ∧ y * p = y := Iff.rfl /-- The corner subalgebra is norm-closed: it is the intersection of the (double-centralizer, hence closed) carrier of `N` with the closed support conditions `p * y = y` and `y * p = y`. -/ -theorem isClosed_cornerNonUnitalStarSubalgebra (N : VonNeumannAlgebra H) {p : H →L[ℂ] H} +lemma isClosed_cornerNonUnitalStarSubalgebra (N : VonNeumannAlgebra H) {p : H →L[ℂ] H} (hp : IsStarProjection p) : IsClosed ((cornerNonUnitalStarSubalgebra N hp : Set (H →L[ℂ] H))) := by have hset : (cornerNonUnitalStarSubalgebra N hp : Set (H →L[ℂ] H)) @@ -178,7 +178,7 @@ theorem isClosed_cornerNonUnitalStarSubalgebra (N : VonNeumannAlgebra H) {p : H · exact isClosed_eq (continuous_id.mul continuous_const) continuous_id /-- The positive part of a corner element stays in the corner. -/ -theorem posPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} +lemma posPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} (hp : IsStarProjection p) {d : H →L[ℂ] H} (hd : d ∈ cornerNonUnitalStarSubalgebra N hp) : d⁺ ∈ cornerNonUnitalStarSubalgebra N hp := by @@ -189,7 +189,7 @@ theorem posPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : exact cfcₙ_mem _ hd /-- The negative part of a corner element stays in the corner. -/ -theorem negPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} +lemma negPart_mem_cornerNonUnitalStarSubalgebra {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} (hp : IsStarProjection p) {d : H →L[ℂ] H} (hd : d ∈ cornerNonUnitalStarSubalgebra N hp) : d⁻ ∈ cornerNonUnitalStarSubalgebra N hp := by @@ -207,7 +207,7 @@ range projections of two operators with `x₁ x₂ = 0`, `x₁` self-adjoint, ar /-- The orthogonal projection onto the closure of the range of `x ∈ N` lies in `N`, because that subspace is invariant under the commutant. -/ -theorem starProjection_range_mem {N : VonNeumannAlgebra H} {x : H →L[ℂ] H} (hx : x ∈ N) : +lemma starProjection_range_mem {N : VonNeumannAlgebra H} {x : H →L[ℂ] H} (hx : x ∈ N) : (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection ∈ N := by set M : Submodule ℂ H := (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure with hM have hpproj : IsStarProjection M.starProjection := isStarProjection_starProjection @@ -227,7 +227,7 @@ theorem starProjection_range_mem {N : VonNeumannAlgebra H} {x : H →L[ℂ] H} ( exact hle /-- The range projection of a nonzero operator is nonzero. -/ -theorem starProjection_range_ne_zero {x : H →L[ℂ] H} (hx0 : x ≠ 0) : +lemma starProjection_range_ne_zero {x : H →L[ℂ] H} (hx0 : x ≠ 0) : (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection ≠ 0 := by intro h0 apply hx0 @@ -239,7 +239,7 @@ theorem starProjection_range_ne_zero {x : H →L[ℂ] H} (hx0 : x ≠ 0) : simpa using hfix.symm /-- If `p * x = x`, then the range projection of `x` is a subprojection of `p`. -/ -theorem starProjection_range_subproj {p x : H →L[ℂ] H} (hpx : p * x = x) : +lemma starProjection_range_subproj {p x : H →L[ℂ] H} (hpx : p * x = x) : p * (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection = (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure.starProjection := by set M : Submodule ℂ H := (LinearMap.range (x : H →ₗ[ℂ] H)).topologicalClosure with hM @@ -258,7 +258,7 @@ theorem starProjection_range_subproj {p x : H →L[ℂ] H} (hpx : p * x = x) : /-- The range projections of `x₁` and `x₂` with `x₁` self-adjoint and `x₁ * x₂ = 0` are orthogonal. -/ -theorem starProjection_range_mul_eq_zero {x₁ x₂ : H →L[ℂ] H} (hsa : star x₁ = x₁) +lemma starProjection_range_mul_eq_zero {x₁ x₂ : H →L[ℂ] H} (hsa : star x₁ = x₁) (h12 : x₁ * x₂ = 0) : (LinearMap.range (x₁ : H →ₗ[ℂ] H)).topologicalClosure.starProjection * (LinearMap.range (x₂ : H →ₗ[ℂ] H)).topologicalClosure.starProjection = 0 := by @@ -294,7 +294,7 @@ orthogonal nonzero subprojections of `p`. A Dedekind-cut argument on /-- **Dichotomy.** If `p` has no proper nonzero subprojection in `N`, every self-adjoint corner element `d` satisfies `0 ≤ d` or `d ≤ 0`. -/ -theorem nonneg_or_nonpos_of_forall_subprojection {N : VonNeumannAlgebra H} +lemma nonneg_or_nonpos_of_forall_subprojection {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} (hp : IsStarProjection p) (hp0 : p ≠ 0) (hmin : ∀ q, IsStarProjection q → q ∈ N → p * q = q → q = 0 ∨ q = p) {d : H →L[ℂ] H} (hdsa : IsSelfAdjoint d) @@ -329,7 +329,7 @@ theorem nonneg_or_nonpos_of_forall_subprojection {N : VonNeumannAlgebra H} element is a real multiple of `p`: the supremum `c₀` of `{c : ℝ | 0 ≤ x - c • p}` (nonempty, bounded, closed) satisfies `x = c₀ • p`, since by the dichotomy `x - c • p ≤ 0` for every `c > c₀`. -/ -theorem exists_real_smul_eq_of_forall_subprojection {N : VonNeumannAlgebra H} +lemma exists_real_smul_eq_of_forall_subprojection {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} (hp : IsStarProjection p) (hpN : p ∈ N) (hp0 : p ≠ 0) (hmin : ∀ q, IsStarProjection q → q ∈ N → p * q = q → q = 0 ∨ q = p) {x : H →L[ℂ] H} (hxsa : IsSelfAdjoint x) diff --git a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean index 683b03a..5eed07a 100644 --- a/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean +++ b/QuantumSystem/Analysis/Entropy/KroneckerProduct.lean @@ -64,7 +64,7 @@ variable {n m : Type*} [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] omit [Fintype n] [Fintype m] [DecidableEq n] [DecidableEq m] in /-- The Kronecker product of two Hermitian matrices is Hermitian. -/ -theorem IsHermitian.kronecker {A : Matrix n n ℂ} {B : Matrix m m ℂ} +lemma IsHermitian.kronecker {A : Matrix n n ℂ} {B : Matrix m m ℂ} (hA : A.IsHermitian) (hB : B.IsHermitian) : (A ⊗ₖ B).IsHermitian := by unfold IsHermitian rw [conjTranspose_kronecker, hA.eq, hB.eq] @@ -95,7 +95,7 @@ exhibiting `U_A ⊗ U_B` as a valid unitary diagonaliser of `A ⊗ B`. -/ /-- **Kronecker spectral decomposition.** If `A = U_A * D_A * U_Aᴴ` and `B = U_B * D_B * U_Bᴴ` with `D_A = diagonal dA`, `D_B = diagonal dB`, then `A ⊗ₖ B = (U_A ⊗ U_B) * diagonal (fun (i,j) => dA i * dB j) * (U_A ⊗ U_B)ᴴ`. -/ -theorem kronecker_eq_unitary_conj_diagonal +lemma kronecker_eq_unitary_conj_diagonal {U_A : Matrix n n ℂ} {U_B : Matrix m m ℂ} {dA : n → ℂ} {dB : m → ℂ} {A : Matrix n n ℂ} {B : Matrix m m ℂ} @@ -262,7 +262,7 @@ omit [Fintype m] [DecidableEq n] [DecidableEq m] in omit [DecidableEq n] in /-- **Right-factor Heisenberg dual**: tracing `ρ` against the embedded observable `X ⊗ 1` reduces to the trace against the partial trace that retains the first factor. -/ -theorem trace_mul_kronecker_one_right +lemma trace_mul_kronecker_one_right (ρ : Matrix (n × m) (n × m) ℂ) (X : Matrix n n ℂ) : Tr (ρ * (X ⊗ₖ (1 : Matrix m m ℂ))) = Tr (partialTrace (A := n) (B := m) (Equiv.refl (n × m)) ρ * X) := by @@ -290,7 +290,7 @@ theorem trace_mul_kronecker_one_right omit [DecidableEq m] in /-- **Left-factor Heisenberg dual**: `Tr(ρ · (1 ⊗ Y))` reduces to the trace against the partial trace that retains the second factor. -/ -theorem trace_mul_kronecker_one_left +lemma trace_mul_kronecker_one_left (ρ : Matrix (n × m) (n × m) ℂ) (Y : Matrix m m ℂ) : Tr (ρ * ((1 : Matrix n n ℂ) ⊗ₖ Y)) = Tr (partialTrace (A := m) (B := n) (Equiv.prodComm n m) ρ * Y) := by diff --git a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean index 6f7048c..0e2861b 100644 --- a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean @@ -1711,7 +1711,7 @@ variable {m : Type*} [Fintype m] [DecidableEq m] /-- **Quantum relative entropy is invariant under trace-preserving `*-`algebra equivalence** (PosDef case). -/ -theorem relativeEntropy_map_starAlgEquiv_posDef +lemma relativeEntropy_map_starAlgEquiv_posDef (ρ σ : DensityMatrix m) (hρ : ρ.toMatrix.PosDef) (hσ : σ.toMatrix.PosDef) (φ : Matrix m m ℂ ≃⋆ₐ[ℂ] Matrix n n ℂ) (hφ : ∀ A, (φ A).trace = A.trace) : @@ -1752,7 +1752,7 @@ theorem relativeEntropy_map_starAlgEquiv_posDef rw [h_log_ρ, h_log_σ, DensityMatrix.map_toMatrix, ← map_sub, ← map_mul, hφ] /-- Specialisation of `relativeEntropy_map_starAlgEquiv_posDef` to reindexing. -/ -theorem relativeEntropy_mapEquiv_posDef +lemma relativeEntropy_mapEquiv_posDef (ρ σ : DensityMatrix m) (hρ : ρ.toMatrix.PosDef) (hσ : σ.toMatrix.PosDef) (e : n ≃ m) : D(ρ.mapEquiv e ∥ σ.mapEquiv e) = D(ρ ∥ σ) := relativeEntropy_map_starAlgEquiv_posDef ρ σ hρ hσ _ _ diff --git a/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean b/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean index d0a4fcb..18766ee 100644 --- a/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/VonNeumannEntropy.lean @@ -38,7 +38,7 @@ end QuantumInfo /-- Casting `S(ρ)` back to ℂ recovers −Tr(ρ log ρ) exactly, confirming the trace is real. -/ @[simp] -theorem vonNeumannEntropy_ofReal (ρ : DensityMatrix n) : +lemma vonNeumannEntropy_ofReal (ρ : DensityMatrix n) : (S(ρ) : ℂ) = -(Tr (ρ * log ρ)) := by unfold vonNeumannEntropy rw [Complex.ofReal_neg] @@ -60,7 +60,7 @@ theorem vonNeumannEntropy_eq_negMulLog_sum (ρ : DensityMatrix n) : /-- `vonNeumannEntropy` expressed via Mathlib's continuous functional calculus `cfc` applied to `Real.negMulLog`, enabling continuity arguments. -/ -theorem vonNeumannEntropy_eq_cfc_re (ρ : DensityMatrix n) : +lemma vonNeumannEntropy_eq_cfc_re (ρ : DensityMatrix n) : vonNeumannEntropy ρ = (Tr (cfc Real.negMulLog ρ.toMatrix)).re := by rw [trace_cfc ρ.isHermitian, vonNeumannEntropy_eq_negMulLog_sum] @@ -311,7 +311,7 @@ variable {m : Type*} [Fintype m] [DecidableEq m] /-- **Von Neumann entropy is invariant under trace-preserving `*-`algebra equivalence** (PosDef case). -/ -theorem vonNeumannEntropy_map_starAlgEquiv_posDef +lemma vonNeumannEntropy_map_starAlgEquiv_posDef (ρ : DensityMatrix m) (hρ : ρ.toMatrix.PosDef) (φ : Matrix m m ℂ ≃⋆ₐ[ℂ] Matrix n n ℂ) (hφ : ∀ A, (φ A).trace = A.trace) : @@ -331,7 +331,7 @@ theorem vonNeumannEntropy_map_starAlgEquiv_posDef rw [h_tr] /-- Specialisation of `vonNeumannEntropy_map_starAlgEquiv_posDef` to reindexing. -/ -theorem vonNeumannEntropy_mapEquiv_posDef +lemma vonNeumannEntropy_mapEquiv_posDef (ρ : DensityMatrix m) (hρ : ρ.toMatrix.PosDef) (e : n ≃ m) : S(ρ.mapEquiv e) = S(ρ) := vonNeumannEntropy_map_starAlgEquiv_posDef ρ hρ _ _ @@ -351,7 +351,7 @@ variable {m : Type*} [Fintype m] [DecidableEq m] /-- **Eigenvalue formula for the entropy of a regularization**: `S(regularize ρ ε) = ∑ᵢ Real.negMulLog ((1-ε) λᵢ + ε/d)` where `λᵢ = ρ.eigenvalues i`. -/ -theorem vonNeumannEntropy_regularize_eq_negMulLog_sum [Nonempty n] +lemma vonNeumannEntropy_regularize_eq_negMulLog_sum [Nonempty n] (ρ : DensityMatrix n) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : vonNeumannEntropy (DensityMatrix.regularize ρ hε hε') = ∑ i, Real.negMulLog ((1 - ε) * ρ.isHermitian.eigenvalues i + ε / Fintype.card n) := by @@ -369,7 +369,7 @@ theorem vonNeumannEntropy_regularize_eq_negMulLog_sum [Nonempty n] /-- The eigenvalue-formula function `ε ↦ ∑ᵢ Real.negMulLog ((1-ε) λᵢ + ε/d)` is continuous in `ε ∈ ℝ`. -/ -theorem continuous_negMulLog_regularize_sum (ρ : DensityMatrix n) : +lemma continuous_negMulLog_regularize_sum (ρ : DensityMatrix n) : Continuous (fun ε : ℝ => ∑ i, Real.negMulLog ((1 - ε) * ρ.isHermitian.eigenvalues i + ε / Fintype.card n)) := by refine continuous_finset_sum _ fun i _ => ?_ @@ -383,7 +383,7 @@ theorem continuous_negMulLog_regularize_sum (ρ : DensityMatrix n) : This is the key continuity result. Combined with `vonNeumannEntropy_regularize_eq_negMulLog_sum`, it gives `lim_{ε → 0+} S(regularize ρ ε) = S(ρ)`, the foundation for extending PosDef-only theorems to PosSemidef. -/ -theorem tendsto_negMulLog_regularize_sum_zero (ρ : DensityMatrix n) : +lemma tendsto_negMulLog_regularize_sum_zero (ρ : DensityMatrix n) : Filter.Tendsto (fun ε : ℝ => ∑ i, Real.negMulLog ((1 - ε) * ρ.isHermitian.eigenvalues i + ε / Fintype.card n)) @@ -401,7 +401,7 @@ theorem tendsto_negMulLog_regularize_sum_zero (ρ : DensityMatrix n) : For any density matrix `ρ` and equivalence `e`, the entropy is preserved: `S(ρ.mapEquiv e) = S(ρ)`. Proven via regularization + limit. -/ -theorem vonNeumannEntropy_mapEquiv [Nonempty n] [Nonempty m] +lemma vonNeumannEntropy_mapEquiv [Nonempty n] [Nonempty m] (ρ : DensityMatrix m) (e : n ≃ m) : vonNeumannEntropy (DensityMatrix.mapEquiv ρ e) = vonNeumannEntropy ρ := by have h_eq : ∀ ε : ℝ, ∀ (hε_pos : 0 < ε) (hε_le : ε ≤ 1), diff --git a/QuantumSystem/Analysis/Matrix/Effros.lean b/QuantumSystem/Analysis/Matrix/Effros.lean index d879051..3e4b070 100644 --- a/QuantumSystem/Analysis/Matrix/Effros.lean +++ b/QuantumSystem/Analysis/Matrix/Effros.lean @@ -95,7 +95,7 @@ lemma leftMulMatrix_rightMulMatrix_commute {m : Type*} [Fintype m] [DecidableEq simpa [hcomp_left, hcomp_right] using hcomm /-- leftMulMatrix is additive: leftMulMatrix (A + B) = leftMulMatrix A + leftMulMatrix B -/ -theorem leftMulMatrix_add {m : Type*} [Fintype m] [DecidableEq m] +lemma leftMulMatrix_add {m : Type*} [Fintype m] [DecidableEq m] (A B : Matrix m m ℂ) : 𝐋 (A + B) = 𝐋 A + 𝐋 B := by simp only [leftMulMatrix] @@ -115,7 +115,7 @@ lemma leftMulMatrix_smul {m : Type*} [Fintype m] [DecidableEq m] exact (LinearMap.toMatrix (matrixBasis m) (matrixBasis m)).map_smul c (leftMul A) /-- rightMulMatrix is additive: rightMulMatrix (A + B) = rightMulMatrix A + rightMulMatrix B -/ -theorem rightMulMatrix_add {m : Type*} [Fintype m] [DecidableEq m] +lemma rightMulMatrix_add {m : Type*} [Fintype m] [DecidableEq m] (A B : Matrix m m ℂ) : 𝐑 (A + B) = 𝐑 A + 𝐑 B := by simp only [rightMulMatrix] @@ -135,7 +135,7 @@ lemma rightMulMatrix_smul {m : Type*} [Fintype m] [DecidableEq m] exact (LinearMap.toMatrix (matrixBasis m) (matrixBasis m)).map_smul c (rightMul A) /-- leftMulMatrix is homogeneous for real scalars -/ -theorem leftMulMatrix_smul_real {m : Type*} [Fintype m] [DecidableEq m] +lemma leftMulMatrix_smul_real {m : Type*} [Fintype m] [DecidableEq m] (r : ℝ) (A : Matrix m m ℂ) : 𝐋 (r • A) = r • 𝐋 A := by have h : (r : ℂ) • A = r • A := by @@ -146,7 +146,7 @@ theorem leftMulMatrix_smul_real {m : Type*} [Fintype m] [DecidableEq m] simp [Complex.real_smul] /-- rightMulMatrix is homogeneous for real scalars -/ -theorem rightMulMatrix_smul_real {m : Type*} [Fintype m] [DecidableEq m] +lemma rightMulMatrix_smul_real {m : Type*} [Fintype m] [DecidableEq m] (r : ℝ) (A : Matrix m m ℂ) : 𝐑 (r • A) = r • 𝐑 A := by have h : (r : ℂ) • A = r • A := by @@ -226,7 +226,7 @@ lemma matrixBasis_repr_apply {m : Type*} [Fintype m] [DecidableEq m] _ = M i j := hsum' /-- Entry `(i, j), (k, l)` of `leftMulMatrix A` equals `A i k` if `j = l`, else `0`. -/ -theorem leftMulMatrix_apply {m : Type*} [Fintype m] [DecidableEq m] +lemma leftMulMatrix_apply {m : Type*} [Fintype m] [DecidableEq m] (A : Matrix m m ℂ) (i j k l : m) : 𝐋 A (i, j) (k, l) = if j = l then A i k else 0 := by classical @@ -240,7 +240,7 @@ theorem leftMulMatrix_apply {m : Type*} [Fintype m] [DecidableEq m] · simp [hjl] /-- Entry `(i, j), (k, l)` of `rightMulMatrix B` equals `B l j` if `i = k`, else `0`. -/ -theorem rightMulMatrix_apply {m : Type*} [Fintype m] [DecidableEq m] +lemma rightMulMatrix_apply {m : Type*} [Fintype m] [DecidableEq m] (B : Matrix m m ℂ) (i j k l : m) : 𝐑 B (i, j) (k, l) = if i = k then B l j else 0 := by classical @@ -279,7 +279,7 @@ lemma leftRightMul_mulVec_vecConjTranspose {m : Type*} [Fintype m] [DecidableEq /-- The quadratic form star(vec(K†)) ⬝ᵥ (leftMulMatrix X * rightMulMatrix Y) *ᵥ vec(K†) equals Tr(K * X * K† * Y). -/ -theorem quadForm_leftRightMul_eq_trace {m : Type*} [Fintype m] [DecidableEq m] +lemma quadForm_leftRightMul_eq_trace {m : Type*} [Fintype m] [DecidableEq m] (X Y K : Matrix m m ℂ) : let v : (m × m) → ℂ := fun x => Kᴴ x.1 x.2 star v ⬝ᵥ ((leftMulMatrix X * rightMulMatrix Y) *ᵥ v) = @@ -315,7 +315,7 @@ lemma rightMulMatrix_eq_one_kronecker_transpose {m : Type*} [Fintype m] [Decidab · simp [rightMulMatrix_apply, Matrix.kroneckerMap_apply, Matrix.transpose_apply, hik] /-- `leftMulMatrix` preserves positive semidefiniteness. -/ -theorem leftMulMatrix_posSemidef {m : Type*} [Fintype m] [DecidableEq m] +lemma leftMulMatrix_posSemidef {m : Type*} [Fintype m] [DecidableEq m] {A : Matrix m m ℂ} (hA : A.PosSemidef) : (𝐋 A).PosSemidef := by classical @@ -323,7 +323,7 @@ theorem leftMulMatrix_posSemidef {m : Type*} [Fintype m] [DecidableEq m] (Matrix.PosSemidef.kronecker (m := m) (x := A) (y := (1 : Matrix m m ℂ)) hA posSemidef_one) /-- `rightMulMatrix` preserves positive definiteness. -/ -theorem rightMulMatrix_posDef {m : Type*} [Fintype m] [DecidableEq m] +lemma rightMulMatrix_posDef {m : Type*} [Fintype m] [DecidableEq m] {B : Matrix m m ℂ} (hB : B.PosDef) : (𝐑 B).PosDef := by classical @@ -343,7 +343,7 @@ noncomputable def matrixPerspective {m : Type*} [Fintype m] [DecidableEq m] /-- Congruence lemma for matrixPerspective: equal matrices give equal results regardless of the proof terms. -/ -theorem matrixPerspective_congr {m : Type*} [Fintype m] [DecidableEq m] +lemma matrixPerspective_congr {m : Type*} [Fintype m] [DecidableEq m] (f : ℝ → ℝ) (L₁ L₂ R₁ R₂ : Matrix m m ℂ) (hL₁ : L₁.PosSemidef) (hL₂ : L₂.PosSemidef) (hR₁ : R₁.PosDef) (hR₂ : R₂.PosDef) (hL : L₁ = L₂) (hR : R₁ = R₂) : @@ -782,7 +782,7 @@ lemma perspective_inner_rpow_comm_sqrt_leftRight {m : Type*} [Fintype m] [Decida equals −(L_{Aᵖ} · R_{B¹⁻ᵖ}) for PD matrices A, B and p ≥ 0. Here L = L_A, R = R_B, S = R^(⁻¹⁄₂), T = R^(¹⁄₂), and the perspective is T · f(S* L S) · T. -/ -theorem matrixPerspective_neg_leftRight_eq {m : Type*} [Fintype m] [DecidableEq m] +lemma matrixPerspective_neg_leftRight_eq {m : Type*} [Fintype m] [DecidableEq m] (A B : Matrix m m ℂ) (hA : A.PosDef) (hB : B.PosDef) (p : ℝ) (hp : 0 ≤ p) (hL_psd : (𝐋 A).PosSemidef) (hR_pd : (𝐑 B).PosDef) : matrixPerspective (fun x => -(x ^ p)) (𝐋 A) (𝐑 B) hL_psd hR_pd = diff --git a/QuantumSystem/Channel.lean b/QuantumSystem/Channel.lean index 0cb66a6..afc81bc 100644 --- a/QuantumSystem/Channel.lean +++ b/QuantumSystem/Channel.lean @@ -79,7 +79,7 @@ abbrev QuantumChannel (n : Type*) (m : Type*) [Fintype n] [Fintype m] := { Φ : Matrix n n ℂ →ₗ[ℂ] Matrix m m ℂ // IsQuantumChannel Φ } /-- The identity map is a quantum channel. -/ -theorem isQuantumChannel_id : IsQuantumChannel (LinearMap.id : Matrix n n ℂ →ₗ[ℂ] Matrix n n ℂ) where +lemma isQuantumChannel_id : IsQuantumChannel (LinearMap.id : Matrix n n ℂ →ₗ[ℂ] Matrix n n ℂ) where completelyPositive := by classical -- id has Kraus representation with single operator K = I @@ -90,7 +90,7 @@ theorem isQuantumChannel_id : IsQuantumChannel (LinearMap.id : Matrix n n ℂ tracePreserving := fun _ => rfl /-- Composition of quantum channels is a quantum channel. -/ -theorem QuantumChannel.comp +lemma QuantumChannel.comp (Φ : QuantumChannel n m) (Ψ : QuantumChannel m k) : IsQuantumChannel (Ψ.val.comp Φ.val) where completelyPositive := by @@ -127,7 +127,7 @@ theorem QuantumChannel.comp omit [Fintype m] in /-- A completely positive map preserves Hermitianity of matrices. If Φ(A) = Σᵢ Kᵢ A Kᵢ† and A is Hermitian, then Φ(A) is Hermitian. -/ -theorem IsCompletelyPositive.map_isHermitian +lemma IsCompletelyPositive.map_isHermitian {Φ : Matrix n n ℂ →ₗ[ℂ] Matrix m m ℂ} (hΦ : IsCompletelyPositive Φ) {A : Matrix n n ℂ} (hA : A.IsHermitian) : (Φ A).IsHermitian := by classical @@ -169,7 +169,7 @@ private lemma matrix_eq_one_of_trace_mul [DecidableEq n] Matrix.ext_iff_trace_mul_right.mpr fun A => by rw [one_mul]; exact h A /-- Trace-preserving Kraus channels satisfy the completeness relation: ∑ₖ Kₖ† Kₖ = I. -/ -theorem QuantumChannel.kraus_sum_eq_one [DecidableEq n] +lemma QuantumChannel.kraus_sum_eq_one [DecidableEq n] (Φ : QuantumChannel n m) {r : ℕ} {K : Fin r → Matrix m n ℂ} (hK : ∀ A, Φ.val A = ∑ i, K i * A * (K i)ᴴ) : ∑ i, (K i)ᴴ * K i = 1 := by @@ -211,7 +211,7 @@ lemma stinespringIsometry_conjTranspose_mul {r : ℕ} [DecidableEq n] /-- The right partial trace preserves positive semidefiniteness (it is a sum of principal submatrices). -/ -theorem traceRight_posSemidef {l n : Type*} [Fintype n] +lemma traceRight_posSemidef {l n : Type*} [Fintype n] {M : Matrix (l × n) (l × n) ℂ} (hM : M.PosSemidef) : (Matrix.traceRight M).PosSemidef := by have hsum : Matrix.traceRight M = ∑ k : n, M.submatrix (fun i : l => (i, k)) (fun j : l => (j, k)) := by @@ -220,7 +220,7 @@ theorem traceRight_posSemidef {l n : Type*} [Fintype n] exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) /-- The left partial trace preserves positive semidefiniteness. -/ -theorem traceLeft_posSemidef {l n : Type*} [Fintype n] +lemma traceLeft_posSemidef {l n : Type*} [Fintype n] {M : Matrix (n × l) (n × l) ℂ} (hM : M.PosSemidef) : (Matrix.traceLeft M).PosSemidef := by have hsum : Matrix.traceLeft M = ∑ k : n, M.submatrix (fun i : l => (k, i)) (fun j : l => (k, j)) := by @@ -229,13 +229,13 @@ theorem traceLeft_posSemidef {l n : Type*} [Fintype n] exact Matrix.posSemidef_sum _ (fun k _ => hM.submatrix _) /-- Reindexing by an index equivalence preserves the trace. -/ -@[simp] theorem trace_reindex_self {n m : Type*} [Fintype n] [Fintype m] (e : n ≃ m) +@[simp] lemma trace_reindex_self {n m : Type*} [Fintype n] [Fintype m] (e : n ≃ m) (M : Matrix n n ℂ) : (M.reindex e e).trace = M.trace := by simp only [Matrix.trace, Matrix.diag_apply, Matrix.reindex_apply, Matrix.submatrix_apply] exact Equiv.sum_comp e.symm (fun i => M i i) /-- The right partial trace of the identity scales by the cardinality of the traced factor. -/ -theorem traceRight_one {X Y : Type*} [DecidableEq X] [Fintype Y] [DecidableEq Y] : +lemma traceRight_one {X Y : Type*} [DecidableEq X] [Fintype Y] [DecidableEq Y] : Matrix.traceRight (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card Y : ℂ) • (1 : Matrix X X ℂ) := by ext i j simp only [traceRight_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] @@ -244,7 +244,7 @@ theorem traceRight_one {X Y : Type*} [DecidableEq X] [Fintype Y] [DecidableEq Y] · simp [hij] /-- The left partial trace of the identity scales by the cardinality of the traced factor. -/ -theorem traceLeft_one {X Y : Type*} [Fintype X] [DecidableEq X] [DecidableEq Y] : +lemma traceLeft_one {X Y : Type*} [Fintype X] [DecidableEq X] [DecidableEq Y] : Matrix.traceLeft (1 : Matrix (X × Y) (X × Y) ℂ) = (Fintype.card X : ℂ) • (1 : Matrix Y Y ℂ) := by ext i j simp only [traceLeft_apply, Matrix.smul_apply, smul_eq_mul, Matrix.one_apply, Prod.mk.injEq] @@ -287,7 +287,7 @@ def traceRightKraus {X Y : Type*} [DecidableEq X] [DecidableEq Y] (y : Y) : Matrix X (X × Y) ℂ := Matrix.of fun x p => if p = (x, y) then (1 : ℂ) else 0 -theorem isCompletelyPositive_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : +lemma isCompletelyPositive_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : IsCompletelyPositive (partialTraceRightₗ (X := X) (Y := Y)) := by classical refine ⟨Fintype.card Y, fun i => traceRightKraus ((Fintype.equivFin Y).symm i), fun M => ?_⟩ @@ -312,7 +312,7 @@ theorem isCompletelyPositive_partialTraceRight {X Y : Type*} [Fintype X] [Fintyp rw [if_neg hq]; simp · simp -theorem isTracePreserving_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : +lemma isTracePreserving_partialTraceRight {X Y : Type*} [Fintype X] [Fintype Y] : IsTracePreserving (partialTraceRightₗ (X := X) (Y := Y)) := fun M => by rw [partialTraceRightₗ_apply]; exact trace_traceRight M @@ -337,7 +337,7 @@ noncomputable def reindexₗ {Z W : Type*} (e : Z ≃ W) : def reindexKraus {Z W : Type*} [DecidableEq Z] (e : Z ≃ W) : Matrix W Z ℂ := Matrix.of fun w z => if z = e.symm w then (1 : ℂ) else 0 -theorem isCompletelyPositive_reindexₗ {Z W : Type*} [Fintype Z] (e : Z ≃ W) : +lemma isCompletelyPositive_reindexₗ {Z W : Type*} [Fintype Z] (e : Z ≃ W) : IsCompletelyPositive (reindexₗ e) := by classical refine ⟨1, fun _ => reindexKraus e, fun M => ?_⟩ @@ -358,7 +358,7 @@ theorem isCompletelyPositive_reindexₗ {Z W : Type*} [Fintype Z] (e : Z ≃ W) rw [if_neg hz]; simp · simp -theorem isTracePreserving_reindexₗ {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : +lemma isTracePreserving_reindexₗ {Z W : Type*} [Fintype Z] [Fintype W] (e : Z ≃ W) : IsTracePreserving (reindexₗ e) := by intro M rw [reindexₗ_apply] diff --git a/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean b/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean index 569bc7d..b1d8f5d 100644 --- a/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean +++ b/QuantumSystem/ForMathlib/Algebra/Colimit/DirectLimitStar.lean @@ -33,7 +33,7 @@ noncomputable instance : Star (DirectLimit F f) where star := DirectLimit.map (F₁ := F) (F₂ := F) f f (fun _ => star) (fun _ _ h x => map_star (f _ _ h) x) -@[simp] theorem star_mk (i) (x : F i) : +@[simp] lemma star_mk (i) (x : F i) : star (⟦⟨i, x⟩⟧ : DirectLimit F f) = ⟦⟨i, star x⟩⟧ := rfl end Star diff --git a/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean b/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean index bf46e4f..15e2238 100644 --- a/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean +++ b/QuantumSystem/ForMathlib/Algebra/Star/PartialIsometry.lean @@ -41,7 +41,7 @@ orthogonal complement of its kernel. -/ def IsPartialIsometry (v : R) : Prop := v * star v * v = v /-- Every star projection is a partial isometry (with itself as source and range). -/ -theorem IsStarProjection.isPartialIsometry {p : R} (hp : IsStarProjection p) : +lemma IsStarProjection.isPartialIsometry {p : R} (hp : IsStarProjection p) : IsPartialIsometry p := by unfold IsPartialIsometry rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq, hp.isIdempotentElem.eq] diff --git a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean index a348531..3a7bb20 100644 --- a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean +++ b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/DirectLimit.lean @@ -38,7 +38,7 @@ noncomputable def cstarNorm : DirectLimit F f → ℝ := (fun i j h x => (NonUnitalStarAlgHom.norm_map (f i j h) (hf i j h) x).symm) omit [Nonempty ι] in -@[simp] theorem cstarNorm_mk (i) (x : F i) : +@[simp] lemma cstarNorm_mk (i) (x : F i) : cstarNorm hf (⟦⟨i, x⟩⟧ : DirectLimit F f) = ‖x‖ := rfl /-- The bundled ring norm on the direct limit. -/ diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean index 53490cd..0a71984 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/TensorProductCompletion.lean @@ -85,12 +85,12 @@ variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] noncomputable def completionCLM (f : E ≃ₗᵢ[𝕜] F) : Completion E →L[𝕜] Completion F := f.toLinearIsometry.toContinuousLinearMap.completion -@[simp] theorem completionCLM_coe (f : E ≃ₗᵢ[𝕜] F) (a : E) : +@[simp] lemma completionCLM_coe (f : E ≃ₗᵢ[𝕜] F) (a : E) : f.completionCLM (a : Completion E) = (f a : Completion F) := by rw [completionCLM, ContinuousLinearMap.completion_apply_coe, LinearIsometry.coe_toContinuousLinearMap, LinearIsometryEquiv.coe_toLinearIsometry] -theorem completionCLM_left (f : E ≃ₗᵢ[𝕜] F) (x : Completion E) : +lemma completionCLM_left (f : E ≃ₗᵢ[𝕜] F) (x : Completion E) : f.symm.completionCLM (f.completionCLM x) = x := by induction x using Completion.induction_on with | hp => exact isClosed_eq ((map_continuous _).comp (map_continuous _)) continuous_id @@ -114,7 +114,7 @@ noncomputable def completion (f : E ≃ₗᵢ[𝕜] F) : Completion E ≃ₗᵢ[ change ‖f.completionCLM (a : Completion E)‖ = ‖(a : Completion E)‖ rw [completionCLM_coe, Completion.norm_coe, Completion.norm_coe, f.norm_map] -@[simp] theorem completion_coe (f : E ≃ₗᵢ[𝕜] F) (a : E) : +@[simp] lemma completion_coe (f : E ≃ₗᵢ[𝕜] F) (a : E) : f.completion (a : Completion E) = (f a : Completion F) := by change f.completionCLM (a : Completion E) = _ exact f.completionCLM_coe a @@ -125,7 +125,7 @@ end LinearIsometryEquiv finite-dimensional. The coercion `toComplL : E → Completion E` is a linear map with dense range whose image is a finite-dimensional (hence closed) subspace, so it is surjective, and finite-dimensionality transfers along a surjection. -/ -theorem FiniteDimensional.completion {𝕜 E : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] +lemma FiniteDimensional.completion {𝕜 E : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] [FiniteDimensional 𝕜 E] : FiniteDimensional 𝕜 (Completion E) := by set f : E →L[𝕜] Completion E := Completion.toComplL with hf @@ -184,7 +184,7 @@ product of the inner products of the factors. -/ rw [tmul, tmul, UniformSpace.Completion.inner_coe, TensorProduct.inner_tmul] /-- The norm of a pure tensor factorises. -/ -@[simp] theorem norm_tmul (x : H₁) (y : H₂) : ‖x ⊗ₕ y‖ = ‖x‖ * ‖y‖ := by +@[simp] lemma norm_tmul (x : H₁) (y : H₂) : ‖x ⊗ₕ y‖ = ‖x‖ * ‖y‖ := by rw [tmul, UniformSpace.Completion.norm_coe, TensorProduct.norm_tmul] /-- The pure tensor is additive in its right argument. -/ @@ -204,11 +204,11 @@ theorem smul_tmul_right (c : ℂ) (x : H₁) (y : H₂) : x ⊗ₕ (c • y) = c rw [tmul, tmul, ← UniformSpace.Completion.coe_smul, TensorProduct.tmul_smul] /-- A pure tensor with a zero left argument vanishes. -/ -@[simp] theorem zero_tmul (y : H₂) : (0 : H₁) ⊗ₕ y = 0 := by +@[simp] lemma zero_tmul (y : H₂) : (0 : H₁) ⊗ₕ y = 0 := by rw [tmul, TensorProduct.zero_tmul, UniformSpace.Completion.coe_zero] /-- A pure tensor with a zero right argument vanishes. -/ -@[simp] theorem tmul_zero (x : H₁) : x ⊗ₕ (0 : H₂) = 0 := by +@[simp] lemma tmul_zero (x : H₁) : x ⊗ₕ (0 : H₂) = 0 := by rw [tmul, TensorProduct.tmul_zero, UniformSpace.Completion.coe_zero] /-- The bounded inclusion `H₁ → H₁ ⊗̂ H₂`, `x ↦ x ⊗ z`, for a fixed `z ∈ H₂`. Its operator norm is @@ -219,7 +219,7 @@ noncomputable def tmulLeftL (z : H₂) : H₁ →L[ℂ] HilbertTensor H₁ H₂ (LinearMap.mkContinuous ((TensorProduct.mk ℂ H₁ H₂).flip z) ‖z‖ fun x => by rw [LinearMap.flip_apply, TensorProduct.mk_apply, TensorProduct.norm_tmul, mul_comm]) -@[simp] theorem tmulLeftL_apply (z : H₂) (x : H₁) : tmulLeftL z x = tmul x z := by +@[simp] lemma tmulLeftL_apply (z : H₂) (x : H₁) : tmulLeftL z x = tmul x z := by rw [tmulLeftL, ContinuousLinearMap.comp_apply, LinearMap.mkContinuous_apply, LinearMap.flip_apply, TensorProduct.mk_apply] rfl @@ -232,7 +232,7 @@ namespace TensorProduct `∑ ξ i ⊗ₜ e i` where the second factors `e i` form an orthonormal family of `H₂`. This is the analytic normal form behind the cross-norm bound: choose a finite-dimensional submodule of `H₂` carrying the element and take an orthonormal basis of it. -/ -theorem exists_orthonormal_rep (z : H₁ ⊗[ℂ] H₂) : +lemma exists_orthonormal_rep (z : H₁ ⊗[ℂ] H₂) : ∃ (n : ℕ) (e : Fin n → H₂) (ξ : Fin n → H₁), Orthonormal ℂ e ∧ z = ∑ i, ξ i ⊗ₜ[ℂ] e i := by obtain ⟨N', hN'fin, hz⟩ := @@ -283,7 +283,7 @@ theorem norm_map_left_le (A : H₁ →L[ℂ] H₁) (z : H₁ ⊗[ℂ] H₂) : /-- The commutation isometry intertwines the two one-sided amplifications on the algebraic tensor product: swapping the factors turns `1 ⊗ B` into `B ⊗ 1`. -/ -theorem commIsometry_map_id (B : H₂ →L[ℂ] H₂) (z : H₁ ⊗[ℂ] H₂) : +lemma commIsometry_map_id (B : H₂ →L[ℂ] H₂) (z : H₁ ⊗[ℂ] H₂) : commIsometry ℂ H₁ H₂ (TensorProduct.map LinearMap.id B.toLinearMap z) = TensorProduct.map B.toLinearMap LinearMap.id (commIsometry ℂ H₁ H₂ z) := by induction z using TensorProduct.induction_on with @@ -316,11 +316,11 @@ noncomputable def algAmplifyRight (B : H₂ →L[ℂ] H₂) : (H₁ ⊗[ℂ] H LinearMap.mkContinuous (TensorProduct.map LinearMap.id B.toLinearMap) ‖B‖ (TensorProduct.norm_map_right_le B) -@[simp] theorem algAmplifyLeft_tmul (A : H₁ →L[ℂ] H₁) (x : H₁) (y : H₂) : +@[simp] lemma algAmplifyLeft_tmul (A : H₁ →L[ℂ] H₁) (x : H₁) (y : H₂) : algAmplifyLeft (H₂ := H₂) A (x ⊗ₜ[ℂ] y) = (A x) ⊗ₜ[ℂ] y := by simp [algAmplifyLeft] -@[simp] theorem algAmplifyRight_tmul (B : H₂ →L[ℂ] H₂) (x : H₁) (y : H₂) : +@[simp] lemma algAmplifyRight_tmul (B : H₂ →L[ℂ] H₂) (x : H₁) (y : H₂) : algAmplifyRight (H₁ := H₁) B (x ⊗ₜ[ℂ] y) = x ⊗ₜ[ℂ] (B y) := by simp [algAmplifyRight] @@ -387,13 +387,13 @@ noncomputable def amplifyRight (B : H₂ →L[ℂ] H₂) : rw [Completion.map_coe (algAmplifyRight B).uniformContinuous, algAmplifyRight_tmul, tmul] /-- The defining action of the left amplification on the image of the algebraic tensor product. -/ -@[simp] theorem amplifyLeft_coe (A : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : +@[simp] lemma amplifyLeft_coe (A : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : amplifyLeft A (a : HilbertTensor H₁ H₂) = ((algAmplifyLeft A a : H₁ ⊗[ℂ] H₂) : HilbertTensor H₁ H₂) := Completion.map_coe (algAmplifyLeft A).uniformContinuous a /-- The defining action of the right amplification on the image of the algebraic tensor product. -/ -@[simp] theorem amplifyRight_coe (B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : +@[simp] lemma amplifyRight_coe (B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : amplifyRight B (a : HilbertTensor H₁ H₂) = ((algAmplifyRight B a : H₁ ⊗[ℂ] H₂) : HilbertTensor H₁ H₂) := Completion.map_coe (algAmplifyRight B).uniformContinuous a @@ -404,28 +404,28 @@ The amplifications are unital algebra homomorphisms onto their images: they send the identity and turn composition in `B(H₁)` (resp. `B(H₂)`) into composition in `B(HilbertTensor H₁ H₂)`. -/ -theorem algAmplifyLeft_one_apply (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyLeft_one_apply (a : H₁ ⊗[ℂ] H₂) : algAmplifyLeft (H₂ := H₂) (1 : H₁ →L[ℂ] H₁) a = a := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp | add p q hp hq => simp [map_add, hp, hq] -theorem algAmplifyLeft_mul_apply (A B : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyLeft_mul_apply (A B : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : algAmplifyLeft (A * B) a = algAmplifyLeft A (algAmplifyLeft B a) := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp [ContinuousLinearMap.mul_apply] | add p q hp hq => simp [map_add, hp, hq] -theorem algAmplifyRight_one_apply (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyRight_one_apply (a : H₁ ⊗[ℂ] H₂) : algAmplifyRight (H₁ := H₁) (1 : H₂ →L[ℂ] H₂) a = a := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp | add p q hp hq => simp [map_add, hp, hq] -theorem algAmplifyRight_mul_apply (A B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyRight_mul_apply (A B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : algAmplifyRight (A * B) a = algAmplifyRight A (algAmplifyRight B a) := by induction a using TensorProduct.induction_on with | zero => simp @@ -467,49 +467,49 @@ theorem amplifyRight_mul (A B : H₂ →L[ℂ] H₂) : The amplifications `A ↦ A ⊗̂ 1` and `B ↦ 1 ⊗̂ B` are themselves `ℂ`-linear in the operator being amplified: they preserve `0`, addition, and scalar multiplication. -/ -theorem algAmplifyLeft_zero_apply (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyLeft_zero_apply (a : H₁ ⊗[ℂ] H₂) : algAmplifyLeft (H₂ := H₂) (0 : H₁ →L[ℂ] H₁) a = 0 := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp | add p q hp hq => simp [map_add, hp, hq] -theorem algAmplifyLeft_add_apply (A B : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyLeft_add_apply (A B : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : algAmplifyLeft (A + B) a = algAmplifyLeft A a + algAmplifyLeft B a := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp [ContinuousLinearMap.add_apply, TensorProduct.add_tmul] | add p q hp hq => simp only [map_add, hp, hq]; abel -theorem algAmplifyLeft_smul_apply (c : ℂ) (A : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyLeft_smul_apply (c : ℂ) (A : H₁ →L[ℂ] H₁) (a : H₁ ⊗[ℂ] H₂) : algAmplifyLeft (c • A) a = c • algAmplifyLeft A a := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp [ContinuousLinearMap.smul_apply, TensorProduct.smul_tmul'] | add p q hp hq => simp only [map_add, hp, hq, smul_add] -theorem algAmplifyRight_zero_apply (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyRight_zero_apply (a : H₁ ⊗[ℂ] H₂) : algAmplifyRight (H₁ := H₁) (0 : H₂ →L[ℂ] H₂) a = 0 := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp | add p q hp hq => simp [map_add, hp, hq] -theorem algAmplifyRight_add_apply (A B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyRight_add_apply (A B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : algAmplifyRight (A + B) a = algAmplifyRight A a + algAmplifyRight B a := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp [ContinuousLinearMap.add_apply, TensorProduct.tmul_add] | add p q hp hq => simp only [map_add, hp, hq]; abel -theorem algAmplifyRight_smul_apply (c : ℂ) (B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyRight_smul_apply (c : ℂ) (B : H₂ →L[ℂ] H₂) (a : H₁ ⊗[ℂ] H₂) : algAmplifyRight (c • B) a = c • algAmplifyRight B a := by induction a using TensorProduct.induction_on with | zero => simp | tmul x y => simp [ContinuousLinearMap.smul_apply, TensorProduct.tmul_smul] | add p q hp hq => simp only [map_add, hp, hq, smul_add] -@[simp] theorem amplifyLeft_zero : +@[simp] lemma amplifyLeft_zero : amplifyLeft (0 : H₁ →L[ℂ] H₁) = (0 : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) := by ext z refine Completion.induction_on z @@ -535,7 +535,7 @@ theorem amplifyLeft_smul (c : ℂ) (A : H₁ →L[ℂ] H₁) : rw [amplifyLeft_coe, algAmplifyLeft_smul_apply, UniformSpace.Completion.coe_smul, ContinuousLinearMap.smul_apply, amplifyLeft_coe] -@[simp] theorem amplifyRight_zero : +@[simp] lemma amplifyRight_zero : amplifyRight (0 : H₂ →L[ℂ] H₂) = (0 : HilbertTensor H₁ H₂ →L[ℂ] HilbertTensor H₁ H₂) := by ext z refine Completion.induction_on z @@ -574,17 +574,17 @@ reused verbatim on the left. -/ noncomputable def commEquiv : HilbertTensor H₁ H₂ ≃ₗᵢ[ℂ] HilbertTensor H₂ H₁ := (TensorProduct.commIsometry ℂ H₁ H₂).completion -@[simp] theorem commEquiv_tmul (x : H₁) (y : H₂) : commEquiv (x ⊗ₕ y) = y ⊗ₕ x := by +@[simp] lemma commEquiv_tmul (x : H₁) (y : H₂) : commEquiv (x ⊗ₕ y) = y ⊗ₕ x := by rw [commEquiv, tmul, LinearIsometryEquiv.completion_coe, TensorProduct.commIsometry_apply, TensorProduct.comm_tmul, tmul] -@[simp] theorem commEquiv_symm_tmul (y : H₂) (x : H₁) : +@[simp] lemma commEquiv_symm_tmul (y : H₂) (x : H₁) : commEquiv.symm (y ⊗ₕ x) = x ⊗ₕ y := by rw [← commEquiv_tmul x y, LinearIsometryEquiv.symm_apply_apply] /-- Conjugating a right amplification `1 ⊗̂ B` by the swap equivalence yields the left amplification `B ⊗̂ 1` on the swapped space. -/ -theorem conjStarAlgEquiv_commEquiv_amplifyRight (B : H₂ →L[ℂ] H₂) : +lemma conjStarAlgEquiv_commEquiv_amplifyRight (B : H₂ →L[ℂ] H₂) : commEquiv.conjStarAlgEquiv (amplifyRight (H₁ := H₁) B) = amplifyLeft (H₂ := H₁) B := by refine ContinuousLinearMap.ext fun w => ?_ rw [LinearIsometryEquiv.conjStarAlgEquiv_apply_apply] @@ -602,7 +602,7 @@ theorem conjStarAlgEquiv_commEquiv_amplifyRight (B : H₂ →L[ℂ] H₂) : amplification `S ⊗̂ 1`. This is the back-transport companion of `conjStarAlgEquiv_commEquiv_amplifyRight`, used to carry the right-hand slice lemma back to the original space. -/ -theorem conjStarAlgEquiv_symm_commEquiv_amplifyRight (S : H₁ →L[ℂ] H₁) : +lemma conjStarAlgEquiv_symm_commEquiv_amplifyRight (S : H₁ →L[ℂ] H₁) : commEquiv.conjStarAlgEquiv.symm (amplifyRight (H₁ := H₂) S) = amplifyLeft (H₂ := H₂) S := by refine ContinuousLinearMap.ext fun w => ?_ rw [LinearIsometryEquiv.symm_conjStarAlgEquiv_apply_apply] @@ -630,7 +630,7 @@ section Adjoint variable [CompleteSpace H₁] [CompleteSpace H₂] omit [CompleteSpace H₂] in -theorem algAmplifyLeft_inner_adjoint (A : H₁ →L[ℂ] H₁) (a b : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyLeft_inner_adjoint (A : H₁ →L[ℂ] H₁) (a b : H₁ ⊗[ℂ] H₂) : inner ℂ (algAmplifyLeft (ContinuousLinearMap.adjoint A) a) b = inner ℂ a (algAmplifyLeft A b) := by simp only [algAmplifyLeft, LinearMap.mkContinuous_apply] @@ -647,7 +647,7 @@ theorem algAmplifyLeft_inner_adjoint (A : H₁ →L[ℂ] H₁) (a b : H₁ ⊗[ | add p q hp hq => simp only [inner_add_left, map_add, hp, hq] omit [CompleteSpace H₁] in -theorem algAmplifyRight_inner_adjoint (B : H₂ →L[ℂ] H₂) (a b : H₁ ⊗[ℂ] H₂) : +lemma algAmplifyRight_inner_adjoint (B : H₂ →L[ℂ] H₂) (a b : H₁ ⊗[ℂ] H₂) : inner ℂ (algAmplifyRight (ContinuousLinearMap.adjoint B) a) b = inner ℂ a (algAmplifyRight B b) := by simp only [algAmplifyRight, LinearMap.mkContinuous_apply] @@ -665,7 +665,7 @@ theorem algAmplifyRight_inner_adjoint (B : H₂ →L[ℂ] H₂) (a b : H₁ ⊗[ omit [CompleteSpace H₂] in /-- The adjoint of the left amplification of `A` is the left amplification of the adjoint of `A`. -/ -theorem amplifyLeft_adjoint (A : H₁ →L[ℂ] H₁) : +lemma amplifyLeft_adjoint (A : H₁ →L[ℂ] H₁) : ContinuousLinearMap.adjoint (amplifyLeft (H₂ := H₂) A) = amplifyLeft (ContinuousLinearMap.adjoint A) := by symm @@ -678,7 +678,7 @@ theorem amplifyLeft_adjoint (A : H₁ →L[ℂ] H₁) : omit [CompleteSpace H₁] in /-- The adjoint of the right amplification of `B` is the right amplification of the adjoint of `B`. -/ -theorem amplifyRight_adjoint (B : H₂ →L[ℂ] H₂) : +lemma amplifyRight_adjoint (B : H₂ →L[ℂ] H₂) : ContinuousLinearMap.adjoint (amplifyRight (H₁ := H₁) B) = amplifyRight (ContinuousLinearMap.adjoint B) := by symm @@ -690,13 +690,13 @@ theorem amplifyRight_adjoint (B : H₂ →L[ℂ] H₂) : omit [CompleteSpace H₂] in /-- The left amplification preserves the `star` (adjoint) operation. -/ -@[simp] theorem amplifyLeft_star (A : H₁ →L[ℂ] H₁) : +@[simp] lemma amplifyLeft_star (A : H₁ →L[ℂ] H₁) : star (amplifyLeft (H₂ := H₂) A) = amplifyLeft (star A) := amplifyLeft_adjoint A omit [CompleteSpace H₁] in /-- The right amplification preserves the `star` (adjoint) operation. -/ -@[simp] theorem amplifyRight_star (B : H₂ →L[ℂ] H₂) : +@[simp] lemma amplifyRight_star (B : H₂ →L[ℂ] H₂) : star (amplifyRight (H₁ := H₁) B) = amplifyRight (star B) := amplifyRight_adjoint B @@ -717,7 +717,7 @@ noncomputable def amplifyLeftₐ : map_star' A := (amplifyLeft_star A).symm omit [CompleteSpace H₂] in -@[simp] theorem amplifyLeftₐ_apply (A : H₁ →L[ℂ] H₁) : +@[simp] lemma amplifyLeftₐ_apply (A : H₁ →L[ℂ] H₁) : amplifyLeftₐ (H₂ := H₂) A = amplifyLeft A := rfl omit [CompleteSpace H₁] in @@ -736,7 +736,7 @@ noncomputable def amplifyRightₐ : map_star' B := (amplifyRight_star B).symm omit [CompleteSpace H₁] in -@[simp] theorem amplifyRightₐ_apply (B : H₂ →L[ℂ] H₂) : +@[simp] lemma amplifyRightₐ_apply (B : H₂ →L[ℂ] H₂) : amplifyRightₐ (H₁ := H₁) B = amplifyRight B := rfl end Adjoint @@ -770,12 +770,12 @@ noncomputable def tmulSingleₗᵢ (i : ι) : simp only [LinearMap.coe_mk, AddHom.coe_mk, norm_tmul] rw [lp.norm_single (p := 2) (by norm_num), norm_one, one_mul] -@[simp] theorem tmulSingleₗᵢ_apply (i : ι) (k : K) : +@[simp] lemma tmulSingleₗᵢ_apply (i : ι) (k : K) : tmulSingleₗᵢ i k = tmul (lp.single 2 i (1 : ℂ)) k := by rfl /-- Distinct standard basis vectors of `ℓ²(ι)` are orthogonal, so the inclusions `tmulSingleₗᵢ` form an orthogonal family. -/ -theorem orthogonalFamily_tmulSingleₗᵢ : +lemma orthogonalFamily_tmulSingleₗᵢ : OrthogonalFamily ℂ (fun _ : ι => K) (fun i => tmulSingleₗᵢ (K := K) i) := by intro i j hij k k' have hδ : inner ℂ (lp.single 2 i (1 : ℂ) : lp (fun _ : ι => ℂ) 2) (lp.single 2 j (1 : ℂ)) = 0 := by @@ -786,7 +786,7 @@ theorem orthogonalFamily_tmulSingleₗᵢ : Hilbert sum of `ι`-many copies of `K`. Density is proved by approximating a pure tensor `a ⊗ k` (`a ∈ ℓ²(ι)`) by the convergent series `∑ᵢ (a i) • (δᵢ ⊗ k)`, each term of which lies in the range of `tmulSingleₗᵢ i`. -/ -theorem isHilbertSum_tmulSingleₗᵢ [CompleteSpace K] : +lemma isHilbertSum_tmulSingleₗᵢ [CompleteSpace K] : IsHilbertSum ℂ (fun _ : ι => K) (fun i => tmulSingleₗᵢ (K := K) i) := by haveI : ∀ _ : ι, CompleteSpace K := fun _ => inferInstance refine IsHilbertSum.mk orthogonalFamily_tmulSingleₗᵢ ?_ @@ -843,7 +843,7 @@ noncomputable def lpTensorEquiv [CompleteSpace K] : lp (fun _ : ι => K) 2 ≃ₗᵢ[ℂ] (lp (fun _ : ι => ℂ) 2) ⊗̂ K := isHilbertSum_tmulSingleₗᵢ.linearIsometryEquiv.symm -@[simp] theorem lpTensorEquiv_single [CompleteSpace K] (i : ι) (k : K) : +@[simp] lemma lpTensorEquiv_single [CompleteSpace K] (i : ι) (k : K) : lpTensorEquiv (lp.single 2 i k) = (lp.single 2 i (1 : ℂ)) ⊗ₕ k := by rw [lpTensorEquiv, IsHilbertSum.linearIsometryEquiv_symm_apply_single isHilbertSum_tmulSingleₗᵢ, diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean index 4429c1c..1af10e0 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -44,7 +44,7 @@ scope; activate it with `open scoped VonNeumannAlgebra`. /-- A multiplicative bijection carries the centralizer of a set onto the centralizer of the image: `φ '' s' = (φ '' s)'`. This is the algebraic core of the fact that a spatial isomorphism of von Neumann algebras commutes with taking commutants. -/ -theorem Set.image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] +lemma Set.image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] [EquivLike F M₁ M₂] [MulEquivClass F M₁ M₂] (φ : F) (s : Set M₁) : ⇑φ '' Set.centralizer s = Set.centralizer (⇑φ '' s) := by ext y @@ -79,11 +79,11 @@ noncomputable def commutantSet (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H w toStarSubalgebra := StarSubalgebra.centralizer ℂ s centralizer_centralizer' := by simp -@[simp] theorem coe_commutantSet (s : Set (H →L[ℂ] H)) : +@[simp] lemma coe_commutantSet (s : Set (H →L[ℂ] H)) : (commutantSet s : Set (H →L[ℂ] H)) = (s ∪ star s).centralizer := StarSubalgebra.coe_centralizer ℂ s -theorem mem_commutantSet_iff {s : Set (H →L[ℂ] H)} {z : H →L[ℂ] H} : +lemma mem_commutantSet_iff {s : Set (H →L[ℂ] H)} {z : H →L[ℂ] H} : z ∈ commutantSet s ↔ ∀ g ∈ s, g * z = z * g ∧ star g * z = z * star g := StarSubalgebra.mem_centralizer_iff ℂ @@ -95,7 +95,7 @@ noncomputable def generated (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H := /-- The carrier of a von Neumann algebra is norm-closed: it is a double centralizer, and centralizers are closed. (Von Neumann algebras are even weakly closed, but the norm-closedness is what the subalgebra-membership lemmas of the continuous functional calculus consume.) -/ -theorem isClosed_coe (N : VonNeumannAlgebra H) : IsClosed (N : Set (H →L[ℂ] H)) := by +lemma isClosed_coe (N : VonNeumannAlgebra H) : IsClosed (N : Set (H →L[ℂ] H)) := by rw [show (N : Set (H →L[ℂ] H)) = Set.centralizer (Set.centralizer (N : Set (H →L[ℂ] H))) from N.centralizer_centralizer.symm] exact Set.isClosed_centralizer _ @@ -110,12 +110,12 @@ it is `(s ∪ s⋆)''`, the smallest von Neumann algebra containing `s` (see `ge scoped postfix:max "″" => VonNeumannAlgebra.generated /-- The commutant of the generated von Neumann algebra `s''` is the commutant `s'`. -/ -@[simp] theorem commutant_generated (s : Set (H →L[ℂ] H)) : +@[simp] lemma commutant_generated (s : Set (H →L[ℂ] H)) : (generated s).commutant = commutantSet s := VonNeumannAlgebra.commutant_commutant (commutantSet s) /-- A set is contained in the von Neumann algebra it generates. -/ -theorem mem_generated_of_mem {s : Set (H →L[ℂ] H)} {x : H →L[ℂ] H} (hx : x ∈ s) : +lemma mem_generated_of_mem {s : Set (H →L[ℂ] H)} {x : H →L[ℂ] H} (hx : x ∈ s) : x ∈ generated s := by have h1 : x ∈ (commutantSet s : Set (H →L[ℂ] H)).centralizer := by rw [coe_commutantSet] @@ -124,7 +124,7 @@ theorem mem_generated_of_mem {s : Set (H →L[ℂ] H)} {x : H →L[ℂ] H} (hx : /-- Taking the commutant of von Neumann algebras is antitone. Named to match the Mathlib `centralizer_le` family (`Subalgebra.centralizer_le`, `Subring.centralizer_le`, …). -/ -theorem commutant_le {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : +lemma commutant_le {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : Q.commutant ≤ P.commutant := by intro x hx rw [← SetLike.mem_coe, VonNeumannAlgebra.coe_commutant] at hx ⊢ @@ -132,7 +132,7 @@ theorem commutant_le {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : /-- The von Neumann algebra generated by `s` is the smallest von Neumann algebra containing `s`: if a von Neumann algebra `M` contains `s`, then it contains `generated s`. -/ -theorem generated_le {s : Set (H →L[ℂ] H)} {M : VonNeumannAlgebra H} +lemma generated_le {s : Set (H →L[ℂ] H)} {M : VonNeumannAlgebra H} (hsM : s ⊆ (M : Set (H →L[ℂ] H))) : generated s ≤ M := by have hstar : s ∪ star s ⊆ (M : Set (H →L[ℂ] H)) := by refine Set.union_subset hsM fun x hx => ?_ @@ -167,27 +167,27 @@ noncomputable def conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : Von StarSubalgebra.coe_map _ _ rw [hcoe, ← Set.image_centralizer, ← Set.image_centralizer, N.centralizer_centralizer] -@[simp] theorem coe_conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : +@[simp] lemma coe_conj (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : (conj U N : Set (H' →L[ℂ] H')) = ⇑U.conjStarAlgEquiv '' (N : Set (H →L[ℂ] H)) := StarSubalgebra.coe_map _ _ /-- **Spatial conjugation is monotone.** If `P ≤ Q` then `U P U⋆ ≤ U Q U⋆`: conjugation transports inclusions, since its carrier is the image of the carrier under `U.conjStarAlgEquiv`. -/ -theorem conj_mono (U : H ≃ₗᵢ[ℂ] H') {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : +lemma conj_mono (U : H ≃ₗᵢ[ℂ] H') {P Q : VonNeumannAlgebra H} (h : P ≤ Q) : conj U P ≤ conj U Q := by intro x hx rw [← SetLike.mem_coe, coe_conj] at hx ⊢ exact Set.image_mono (SetLike.coe_subset_coe.2 h) hx /-- **Conjugation commutes with the commutant.** `(U N U⋆)' = U N' U⋆`. -/ -theorem conj_commutant (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : +lemma conj_commutant (U : H ≃ₗᵢ[ℂ] H') (N : VonNeumannAlgebra H) : (conj U N).commutant = conj U N.commutant := by apply SetLike.coe_injective rw [VonNeumannAlgebra.coe_commutant, coe_conj, coe_conj, VonNeumannAlgebra.coe_commutant, Set.image_centralizer] /-- **Conjugation commutes with the commutant of a set.** `U s' U⋆ = (U s U⋆)'`. -/ -theorem conj_commutantSet (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : +lemma conj_commutantSet (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : conj U (commutantSet s) = commutantSet (⇑U.conjStarAlgEquiv '' s) := by have hstar : ⇑U.conjStarAlgEquiv '' star s = star (⇑U.conjStarAlgEquiv '' s) := by ext z @@ -202,7 +202,7 @@ theorem conj_commutantSet (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : /-- **Conjugation commutes with the generated von Neumann algebra.** A spatial isomorphism carries `s''` to `(U s U⋆)''`: `U ⟨s⟩'' U⋆ = ⟨U s U⋆⟩''`. -/ -theorem conj_generated (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : +lemma conj_generated (U : H ≃ₗᵢ[ℂ] H') (s : Set (H →L[ℂ] H)) : conj U (generated s) = generated (⇑U.conjStarAlgEquiv '' s) := by rw [generated, ← conj_commutant, conj_commutantSet, generated] diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean index c1f1c9b..c5a4779 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean @@ -38,9 +38,9 @@ noncomputable instance : Top (VonNeumannAlgebra H) where centralizer_centralizer' := Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } -@[simp] theorem coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl +@[simp] lemma coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl /-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ -@[simp] theorem mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x +@[simp] lemma mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x end VonNeumannAlgebra diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean index 2843e63..2708daa 100644 --- a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/PartialTrace.lean @@ -81,14 +81,14 @@ theorem traceLeft_eq_traceRight_prodComm {l c n : Type*} [Fintype n] simp [Matrix.reindex_apply] /-- The right partial trace preserves the full trace: `Tr (traceRight M) = Tr M`. -/ -@[simp] theorem trace_traceRight {l n : Type*} [Fintype l] [Fintype n] +@[simp] lemma trace_traceRight {l n : Type*} [Fintype l] [Fintype n] (M : Matrix (l × n) (l × n) R) : (traceRight M).trace = M.trace := by simp only [Matrix.trace, Matrix.diag_apply, traceRight_apply] exact (Fintype.sum_prod_type fun p : l × n => M p p).symm /-- The left partial trace preserves the full trace: `Tr (traceLeft M) = Tr M`. -/ -@[simp] theorem trace_traceLeft {l n : Type*} [Fintype l] [Fintype n] +@[simp] lemma trace_traceLeft {l n : Type*} [Fintype l] [Fintype n] (M : Matrix (n × l) (n × l) R) : (traceLeft M).trace = M.trace := by simp only [Matrix.trace, Matrix.diag_apply, traceLeft_apply] diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean index 3718418..74cf195 100644 --- a/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Matrix/StarAlgEquiv.lean @@ -76,7 +76,7 @@ private lemma trace_reindex {α : Type*} [AddCommMonoid α] (e : m ≃ n) (M : M omit [DecidableEq m] [DecidableEq n] in /-- Trace is preserved when reindexing the matrix indices via a bijection. This is the `submatrix _ e e` form (vs. `reindex` form in `trace_reindex`). -/ -theorem trace_submatrix_eq {α : Type*} [AddCommMonoid α] (M : Matrix m m α) (e : n ≃ m) : +lemma trace_submatrix_eq {α : Type*} [AddCommMonoid α] (M : Matrix m m α) (e : n ≃ m) : (M.submatrix e e).trace = M.trace := by rw [show (M.submatrix e e) = reindex e.symm e.symm M from rfl] exact trace_reindex e.symm M @@ -89,7 +89,7 @@ theorem trace_reindexStarAlgEquiv [CommSemiring R] [Semiring A] [StarRing A] [Al exact trace_reindex e M /-- Trace is preserved under unitary conjugation `Unitary.conjStarAlgAut`. -/ -theorem trace_conjStarAlgAut [CommSemiring R] [CommSemiring A] [StarRing A] [Algebra R A] +lemma trace_conjStarAlgAut [CommSemiring R] [CommSemiring A] [StarRing A] [Algebra R A] (u : unitary (Matrix n n A)) (M : Matrix n n A) : (Unitary.conjStarAlgAut R (Matrix n n A) u M).trace = M.trace := by rw [Unitary.conjStarAlgAut_apply, trace_mul_cycle, @@ -157,7 +157,7 @@ is naturally available (e.g. from region index-set equivalences). -/ omit [Fintype m] [Fintype n] [DecidableEq m] [DecidableEq n] in /-- `Matrix.PosSemidef` is preserved by reindexing the index set via a bijection. Specialisation of `PosSemidef.map_starAlgEquiv` to `reindexStarAlgEquiv`. -/ -theorem PosSemidef.mapEquiv [Finite m] {M : Matrix m m ℂ} (hM : M.PosSemidef) (e : n ≃ m) : +lemma PosSemidef.mapEquiv [Finite m] {M : Matrix m m ℂ} (hM : M.PosSemidef) (e : n ≃ m) : (M.submatrix e e).PosSemidef := by classical letI := Fintype.ofFinite m @@ -168,7 +168,7 @@ theorem PosSemidef.mapEquiv [Finite m] {M : Matrix m m ℂ} (hM : M.PosSemidef) omit [Fintype m] [Fintype n] [DecidableEq m] [DecidableEq n] in /-- `Matrix.PosDef` is preserved by reindexing the index set via a bijection. Specialisation of `PosDef.map_starAlgEquiv` to `reindexStarAlgEquiv`. -/ -theorem PosDef.mapEquiv [Finite m] {M : Matrix m m ℂ} (hM : M.PosDef) (e : n ≃ m) : +lemma PosDef.mapEquiv [Finite m] {M : Matrix m m ℂ} (hM : M.PosDef) (e : n ≃ m) : (M.submatrix e e).PosDef := by classical letI := Fintype.ofFinite m diff --git a/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean b/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean index ae3588f..9de355c 100644 --- a/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean +++ b/QuantumSystem/ForMathlib/LinearAlgebra/Trace.lean @@ -122,7 +122,7 @@ noncomputable def partialTrace (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) : (TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm.toLinearMap ∘ₗ (e.conjAlgEquiv 𝕜).toLinearMap -theorem partialTrace_apply (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (ρ : Module.End 𝕜 ℋ) : +lemma partialTrace_apply (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (ρ : Module.End 𝕜 ℋ) : partialTrace e ρ = TensorProduct.partialTraceRight ((TensorProduct.endTensorEndAlgEquiv (R := 𝕜) (M := A) (N := B)).symm (e.conjAlgEquiv 𝕜 ρ)) := rfl @@ -145,7 +145,7 @@ private theorem endTensorEndAlgEquiv_symm_map_one (M : Module.End 𝕜 A) : /-- **`Tr_B((M⊗1)·ρ) = M·Tr_B(ρ)`**: the partial trace along `e` is a left module map over the ampliation, with `B` (the traced-out subspace) named explicitly by `e`. -/ -theorem partialTrace_ampliate_mul (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Module.End 𝕜 A) +lemma partialTrace_ampliate_mul (e : ℋ ≃ₗ[𝕜] A ⊗[𝕜] B) (M : Module.End 𝕜 A) (ρ : Module.End 𝕜 ℋ) : partialTrace e (ampliate e M * ρ) = M * partialTrace e ρ := by rw [partialTrace_apply, partialTrace_apply, ampliate, map_mul (e.conjAlgEquiv 𝕜), @@ -207,7 +207,7 @@ theorem exists_includeRight_of_commute_includeLeft omit [Module.Finite ℂ A] [Module.Free ℂ A] [Module.Finite ℂ B] [Module.Free ℂ B] in /-- **Commutant of `1 ⊗ End B`, algebra form.** An element of `End ℂ A ⊗ End ℂ B` that commutes with every `includeRight g = 1 ⊗ g` is of the form `includeLeft f = f ⊗ 1`. -/ -theorem exists_includeLeft_of_commute_includeRight +lemma exists_includeLeft_of_commute_includeRight (S : Module.End ℂ A ⊗[ℂ] Module.End ℂ B) (hS : ∀ g : Module.End ℂ B, (Algebra.TensorProduct.includeRight (R := ℂ) (A := Module.End ℂ A) @@ -288,7 +288,7 @@ theorem exists_map_one_of_commute_map_id /-- **Commutant of `1 ⊗ End B`, operator form.** An operator `T : End (A ⊗ B)` commuting with every `1 ⊗ g = TensorProduct.map 1 g` is an ampliation `f ⊗ 1 = TensorProduct.map f 1` of the first factor. -/ -theorem exists_map_id_of_commute_map_one +lemma exists_map_id_of_commute_map_one (T : Module.End ℂ (A ⊗[ℂ] B)) (hT : ∀ g : Module.End ℂ B, T ∘ₗ TensorProduct.map LinearMap.id g = TensorProduct.map LinearMap.id g ∘ₗ T) : diff --git a/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean b/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean index f04d988..c0bc9c2 100644 --- a/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean +++ b/QuantumSystem/ForMathlib/Topology/Algebra/CStarCompletion.lean @@ -28,7 +28,7 @@ section StarRing variable [NormedRing A] [StarRing A] [NormedStarGroup A] -theorem uniformContinuous_star : UniformContinuous (star : A → A) := by +lemma uniformContinuous_star : UniformContinuous (star : A → A) := by have h : Isometry (star : A → A) := AddMonoidHomClass.isometry_of_norm (starAddEquiv (R := A)) fun x => norm_star x exact h.uniformContinuous @@ -36,7 +36,7 @@ theorem uniformContinuous_star : UniformContinuous (star : A → A) := by /-- Involution on a completion, the continuous extension of the involution on the dense image. -/ noncomputable instance : Star (Completion A) := ⟨Completion.map star⟩ -@[simp] theorem star_coe (a : A) : star (↑a : Completion A) = (↑(star a) : Completion A) := +@[simp] lemma star_coe (a : A) : star (↑a : Completion A) = (↑(star a) : Completion A) := map_coe uniformContinuous_star a instance : ContinuousStar (Completion A) := ⟨continuous_map⟩ @@ -164,12 +164,12 @@ noncomputable def mapStarAlgEquiv (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinu intro a rw [star_coe, map_coe he, map_coe he, star_coe, map_star] -@[simp] theorem mapStarAlgEquiv_coe (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) +@[simp] lemma mapStarAlgEquiv_coe (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) (he' : UniformContinuous e.symm) (a : A) : mapStarAlgEquiv e he he' (↑a : Completion A) = (↑(e a) : Completion B) := map_coe he a -theorem coe_mapStarAlgEquiv (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) +lemma coe_mapStarAlgEquiv (e : A ≃⋆ₐ[𝕜] B) (he : UniformContinuous e) (he' : UniformContinuous e.symm) : ⇑(mapStarAlgEquiv e he he') = Completion.map e := rfl diff --git a/QuantumSystem/State.lean b/QuantumSystem/State.lean index 0aa175c..289359e 100644 --- a/QuantumSystem/State.lean +++ b/QuantumSystem/State.lean @@ -58,14 +58,14 @@ namespace DensityMatrix variable {n : Type*} [Fintype n] [DecidableEq n] /-- Two density matrices are equal iff their underlying matrices are equal. -/ -@[ext] theorem ext {ρ σ : DensityMatrix n} (h : ρ.toMatrix = σ.toMatrix) : ρ = σ := by +@[ext] lemma ext {ρ σ : DensityMatrix n} (h : ρ.toMatrix = σ.toMatrix) : ρ = σ := by cases ρ; cases σ; congr /-- A density matrix is Hermitian. -/ -theorem isHermitian (ρ : DensityMatrix n) : ρ.toMatrix.IsHermitian := ρ.posSemidef.1 +lemma isHermitian (ρ : DensityMatrix n) : ρ.toMatrix.IsHermitian := ρ.posSemidef.1 /-- All eigenvalues of a density matrix are non-negative. -/ -theorem eigenvalues_nonneg (ρ : DensityMatrix n) (i : n) : +lemma eigenvalues_nonneg (ρ : DensityMatrix n) (i : n) : 0 ≤ ρ.isHermitian.eigenvalues i := (ρ.isHermitian.posSemidef_iff_eigenvalues_nonneg.mp ρ.posSemidef) i @@ -96,20 +96,20 @@ lemma eigenvalue_le_one (ρ : DensityMatrix n) (i : n) : instance : Coe (DensityMatrix n) (Matrix n n ℂ) where coe := DensityMatrix.toMatrix -@[simp] theorem coe_eq_toMatrix (ρ : DensityMatrix n) : (↑ρ : Matrix n n ℂ) = ρ.toMatrix := rfl +@[simp] lemma coe_eq_toMatrix (ρ : DensityMatrix n) : (↑ρ : Matrix n n ℂ) = ρ.toMatrix := rfl /-- Density matrix times a complex matrix (coercion on the left). -/ noncomputable instance : HMul (DensityMatrix n) (Matrix n n ℂ) (Matrix n n ℂ) where hMul ρ A := ρ.toMatrix * A -@[simp] theorem densityMatrix_hmul_eq (ρ : DensityMatrix n) (A : Matrix n n ℂ) : +@[simp] lemma densityMatrix_hmul_eq (ρ : DensityMatrix n) (A : Matrix n n ℂ) : ρ * A = ρ.toMatrix * A := rfl /-- Real-power of a density matrix, delegated to matrix rpow. -/ noncomputable instance : HPow (DensityMatrix n) ℝ (Matrix n n ℂ) where hPow ρ s := ρ.toMatrix ^ s -theorem densityMatrix_hpow_eq (ρ : DensityMatrix n) (s : ℝ) : +lemma densityMatrix_hpow_eq (ρ : DensityMatrix n) (s : ℝ) : ρ ^ s = ρ.toMatrix ^ s := rfl /-- Matrix logarithm of a density matrix: `log ρ = U diag(log λᵢ) U*`, @@ -152,7 +152,7 @@ noncomputable def mix (ρ₁ ρ₂ : DensityMatrix n) push_cast ring -@[simp] theorem mix_toMatrix (ρ₁ ρ₂ : DensityMatrix n) +@[simp] lemma mix_toMatrix (ρ₁ ρ₂ : DensityMatrix n) (p : ℝ) (hp : 0 ≤ p) (hp1 : p ≤ 1) : ↑(mix ρ₁ ρ₂ p hp hp1) = p • (↑ρ₁ : Matrix n n ℂ) + (1 - p) • ↑ρ₂ := rfl @@ -326,7 +326,7 @@ theorem regularize_eq_cfc (ρ : DensityMatrix n) {ε : ℝ} The regularization commutes with `mapEquiv`. -/ /-- For an `Equiv e : n ≃ m`, the regularization commutes with `mapEquiv`. -/ -theorem regularize_mapEquiv {m : Type*} [Fintype m] [DecidableEq m] [Nonempty m] +lemma regularize_mapEquiv {m : Type*} [Fintype m] [DecidableEq m] [Nonempty m] (ρ : DensityMatrix m) (e : n ≃ m) {ε : ℝ} (hε : 0 ≤ ε) (hε' : ε ≤ 1) : regularize (mapEquiv ρ e) hε hε' = mapEquiv (regularize ρ hε hε') e := by apply DensityMatrix.ext From 795b00e047dc2197065b49115db1b3561125317d Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 22:12:23 +0000 Subject: [PATCH 055/113] =?UTF-8?q?feat:=20add=20IsTypeIInfinite=20predica?= =?UTF-8?q?te=20for=20type=20I=5F=E2=88=9E=20factors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the intrinsic predicate `IsTypeIInfinite` (a type I factor with an infinite orthogonal family of minimal projections) and make `isTypeIInfinite_boundedLinearOperators` return it. Preserve the ⋆-iso to an infinite-dimensional B(K) as `exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .../BoundedLinearOperators.lean | 57 ++++++++++++++++--- .../Algebra/VonNeumannAlgebra/Factor.lean | 35 ++++++++++++ 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean index b8477d3..28e273f 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean @@ -22,8 +22,10 @@ when `H` is infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor** * `VonNeumannAlgebra.isTypeIFactor_boundedLinearOperators` — `B(H)` is a type I factor. * `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(K)` for some Hilbert space `K`. -* `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, the - space `K` is infinite-dimensional (`B(H)` is type I_∞). +* `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, `B(H)` + is a type I_∞ factor, packaged as the intrinsic predicate `IsTypeIInfinite ⊤`. +* `VonNeumannAlgebra.exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators` — for + infinite-dimensional `H`, `B(H) ≃⋆ₐ B(K)` with `K` itself infinite-dimensional. -/ @[expose] public section @@ -88,18 +90,24 @@ theorem exists_starAlgEquiv_boundedLinearOperators {H : Type u} [NormedAddCommGr Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := isTypeIFactor_boundedLinearOperators.exists_starAlgEquiv -/-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** The full algebra is -`⋆`-isomorphic to `B(K)` for a complex Hilbert space `K` that is itself infinite-dimensional. Here -`K = ℓ²(F)` for `F` an orthonormal basis of `H`; a finite `F` would, through the spatial -decomposition `H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` with one-dimensional multiplicity `eH` (the range of the -rank-one minimal projection), force `H` finite-dimensional. Expressing type I_∞ as +/-- **`B(H) ≃⋆ₐ B(K)` with `K` infinite-dimensional, when `H` is infinite-dimensional.** The full +algebra is `⋆`-isomorphic to `B(K)` for a complex Hilbert space `K` that is itself +infinite-dimensional. Here `K = ℓ²(F)` for `F` an orthonormal basis of `H`; a finite `F` would, +through the spatial decomposition `H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` with one-dimensional multiplicity `eH` (the +range of the rank-one minimal projection), force `H` finite-dimensional. Expressing type I_∞ as `¬FiniteDimensional ℂ K` is the standard reading: a type I_n factor is `B(K)` with `dim K = n`, so I_∞ is exactly the infinite-dimensional `K`. -/ -theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] - [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] (hinf : ¬FiniteDimensional ℂ H) : +theorem exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators {H : Type u} + [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + (hinf : ¬FiniteDimensional ℂ H) : ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), ¬FiniteDimensional ℂ K ∧ Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by + haveI : Nontrivial H := by + rcases subsingleton_or_nontrivial H with h | h + · haveI := h + exact absurd (inferInstance : FiniteDimensional ℂ H) hinf + · exact h obtain ⟨u, hu⟩ := exists_unit_vector (H := H) have he : IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := isMinimalProjection_rankOne_boundedLinearOperators hu @@ -118,4 +126,35 @@ theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup haveI := hK exact hinf U.symm.toLinearEquiv.finiteDimensional +/-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** Packaged as the intrinsic +predicate `IsTypeIInfinite`: `⊤ = B(H)` is a type I factor (`isTypeIFactor_boundedLinearOperators`) +carrying an infinite orthogonal family of minimal projections — the rank-one projections +`|uₙ⟩⟨uₙ|` onto a countable orthonormal sequence `(uₙ)` extracted from a Hilbert basis of the +infinite-dimensional `H`. The `⋆`-isomorphism to an infinite-dimensional `B(K)` is +`exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators`. -/ +theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] (hinf : ¬FiniteDimensional ℂ H) : + IsTypeIInfinite (⊤ : VonNeumannAlgebra H) := by + obtain ⟨w, b, -⟩ := exists_hilbertBasis ℂ H + have hwinf : Infinite w := by + rw [← not_finite_iff_infinite] + intro hfin + haveI : Finite w := hfin + haveI : Fintype w := Fintype.ofFinite w + exact hinf b.toOrthonormalBasis.toBasis.finiteDimensional_of_finite + haveI := hwinf + let g : ℕ ↪ w := Infinite.natEmbedding w + set u : ℕ → H := fun n => b (g n) with hu_def + have hon : Orthonormal ℂ u := by + rw [hu_def]; exact b.orthonormal.comp g g.injective + have hnorm : ∀ n, ‖u n‖ = 1 := fun n => hon.1 n + have hmin : ∀ n, IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ (u n) (u n)) := + fun n => isMinimalProjection_rankOne_boundedLinearOperators (hnorm n) + have horth : ∀ m n, m ≠ n → rankOne ℂ (u m) (u m) * rankOne ℂ (u n) (u n) = 0 := by + intro m n hmn + rw [ContinuousLinearMap.mul_def, rankOne_comp_rankOne, hon.2 hmn, zero_smul] + haveI : Nontrivial H := + nontrivial_of_ne (u 0) 0 (by rw [← norm_ne_zero_iff, hnorm 0]; norm_num) + exact ⟨isTypeIFactor_boundedLinearOperators, fun n => rankOne ℂ (u n) (u n), hmin, horth⟩ + end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean index 28f7942..98f955a 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean @@ -115,6 +115,41 @@ not part of the definition. The equivalence with the general abelian-projection def IsTypeIFactor (N : VonNeumannAlgebra H) : Prop := IsFactor N ∧ ∃ e : H →L[ℂ] H, IsMinimalProjection N e +/-- A **type I_∞ factor**: a type I factor carrying an infinite sequence of pairwise orthogonal +minimal projections. This is the intrinsic form of *infinite multiplicity*: through the structure +theorem `N ≃⋆ₐ B(K)` the minimal projections are the rank-one projections, and an infinite +orthogonal family of them exists exactly when `K` is infinite-dimensional — a type `I_n` factor +`B(ℂⁿ)` has at most `n` pairwise orthogonal nonzero projections. As with `IsTypeIFactor`, the +spatial identification with an infinite-dimensional `B(K)` is then a theorem, not part of the +definition. -/ +def IsTypeIInfinite (N : VonNeumannAlgebra H) : Prop := + IsTypeIFactor N ∧ + ∃ e : ℕ → (H →L[ℂ] H), + (∀ n, IsMinimalProjection N (e n)) ∧ + (∀ m n, m ≠ n → e m * e n = 0) + +/-- An orthogonal sequence of minimal projections is injective. -/ +lemma injective_of_isMinimalProjection_orthogonal {N : VonNeumannAlgebra H} + {e : ℕ → (H →L[ℂ] H)} (hmin : ∀ n, IsMinimalProjection N (e n)) + (horth : ∀ m n, m ≠ n → e m * e n = 0) : Function.Injective e := by + intro m n hmn + by_contra hne + have h0 := horth m n hne + rw [hmn, (hmin n).1.isIdempotentElem] at h0 + exact (hmin n).2.2.1 h0 + +/-- The witnessing minimal projections of a type I_∞ factor may be chosen injectively. -/ +lemma IsTypeIInfinite.exists_injective {N : VonNeumannAlgebra H} (hN : IsTypeIInfinite N) : + ∃ e : ℕ → (H →L[ℂ] H), Function.Injective e ∧ + (∀ n, IsMinimalProjection N (e n)) ∧ + (∀ m n, m ≠ n → e m * e n = 0) := by + obtain ⟨-, e, hmin, horth⟩ := hN + exact ⟨e, injective_of_isMinimalProjection_orthogonal hmin horth, hmin, horth⟩ + +/-- A type I_∞ factor is in particular a type I factor. -/ +lemma IsTypeIInfinite.isTypeIFactor {N : VonNeumannAlgebra H} (hN : IsTypeIInfinite N) : + IsTypeIFactor N := hN.1 + /-- **Murray–von Neumann equivalence** of projections inside `N`: there is a partial isometry `v ∈ N` with source projection `v⋆v = p` and range projection `vv⋆ = q`. -/ def MvNEquiv (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := From 7bcd0c2ae9ef0c9180c5c23e728eddf4237c7b67 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 19 Jul 2026 22:36:00 +0000 Subject: [PATCH 056/113] chore: remove mattpocock/skills skills Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .agents/skills/codebase-design/DEEPENING.md | 37 ---- .../skills/codebase-design/DESIGN-IT-TWICE.md | 44 ---- .agents/skills/codebase-design/SKILL.md | 114 ---------- .agents/skills/diagnosing-bugs/SKILL.md | 134 ------------ .../scripts/hitl-loop.template.sh | 41 ---- .agents/skills/domain-modeling/ADR-FORMAT.md | 47 ----- .../skills/domain-modeling/CONTEXT-FORMAT.md | 60 ------ .agents/skills/domain-modeling/SKILL.md | 74 ------- .agents/skills/grill-me/SKILL.md | 7 - .agents/skills/grill-with-docs/SKILL.md | 7 - .agents/skills/grilling/SKILL.md | 10 - .agents/skills/handoff/SKILL.md | 16 -- .../HTML-REPORT.md | 123 ----------- .../improve-codebase-architecture/SKILL.md | 66 ------ .../skills/writing-great-skills/GLOSSARY.md | 195 ------------------ .agents/skills/writing-great-skills/SKILL.md | 82 -------- .claude/skills/codebase-design | 1 - .claude/skills/diagnosing-bugs | 1 - .claude/skills/domain-modeling | 1 - .claude/skills/grill-me | 1 - .claude/skills/grill-with-docs | 1 - .claude/skills/grilling | 1 - .claude/skills/handoff | 1 - .claude/skills/improve-codebase-architecture | 1 - .claude/skills/writing-great-skills | 1 - skills-lock.json | 59 ------ 26 files changed, 1125 deletions(-) delete mode 100644 .agents/skills/codebase-design/DEEPENING.md delete mode 100644 .agents/skills/codebase-design/DESIGN-IT-TWICE.md delete mode 100644 .agents/skills/codebase-design/SKILL.md delete mode 100644 .agents/skills/diagnosing-bugs/SKILL.md delete mode 100644 .agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh delete mode 100644 .agents/skills/domain-modeling/ADR-FORMAT.md delete mode 100644 .agents/skills/domain-modeling/CONTEXT-FORMAT.md delete mode 100644 .agents/skills/domain-modeling/SKILL.md delete mode 100644 .agents/skills/grill-me/SKILL.md delete mode 100644 .agents/skills/grill-with-docs/SKILL.md delete mode 100644 .agents/skills/grilling/SKILL.md delete mode 100644 .agents/skills/handoff/SKILL.md delete mode 100644 .agents/skills/improve-codebase-architecture/HTML-REPORT.md delete mode 100644 .agents/skills/improve-codebase-architecture/SKILL.md delete mode 100644 .agents/skills/writing-great-skills/GLOSSARY.md delete mode 100644 .agents/skills/writing-great-skills/SKILL.md delete mode 120000 .claude/skills/codebase-design delete mode 120000 .claude/skills/diagnosing-bugs delete mode 120000 .claude/skills/domain-modeling delete mode 120000 .claude/skills/grill-me delete mode 120000 .claude/skills/grill-with-docs delete mode 120000 .claude/skills/grilling delete mode 120000 .claude/skills/handoff delete mode 120000 .claude/skills/improve-codebase-architecture delete mode 120000 .claude/skills/writing-great-skills delete mode 100644 skills-lock.json diff --git a/.agents/skills/codebase-design/DEEPENING.md b/.agents/skills/codebase-design/DEEPENING.md deleted file mode 100644 index 3938457..0000000 --- a/.agents/skills/codebase-design/DEEPENING.md +++ /dev/null @@ -1,37 +0,0 @@ -# Deepening - -How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**. - -## Dependency categories - -When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam. - -### 1. In-process - -Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed. - -### 2. Local-substitutable - -Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface. - -### 3. Remote but owned (Ports & Adapters) - -Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter. - -Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."* - -### 4. True external (Mock) - -Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter. - -## Seam discipline - -- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection. -- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them. - -## Testing strategy: replace, don't layer - -- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them. -- Write new tests at the deepened module's interface. The **interface is the test surface**. -- Tests assert on observable outcomes through the interface, not internal state. -- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface. diff --git a/.agents/skills/codebase-design/DESIGN-IT-TWICE.md b/.agents/skills/codebase-design/DESIGN-IT-TWICE.md deleted file mode 100644 index 49a7c42..0000000 --- a/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +++ /dev/null @@ -1,44 +0,0 @@ -# Design It Twice - -When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best. - -Uses the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**, **leverage**. - -## Process - -### 1. Frame the problem space - -Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate: - -- The constraints any new interface would need to satisfy -- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md)) -- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete - -Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel. - -### 2. Spawn sub-agents - -Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module. - -Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint: - -- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point." -- Agent 2: "Maximise flexibility — support many use cases and extension." -- Agent 3: "Optimise for the most common caller — make the default case trivial." -- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies." - -Include both [SKILL.md](SKILL.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language. - -Each sub-agent outputs: - -1. Interface (types, methods, params — plus invariants, ordering, error modes) -2. Usage example showing how callers use it -3. What the implementation hides behind the seam -4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md)) -5. Trade-offs — where leverage is high, where it's thin - -### 3. Present and compare - -Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**. - -After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu. diff --git a/.agents/skills/codebase-design/SKILL.md b/.agents/skills/codebase-design/SKILL.md deleted file mode 100644 index 16620c2..0000000 --- a/.agents/skills/codebase-design/SKILL.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -name: codebase-design -description: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary. ---- - -# Codebase Design - -Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone. - -## Glossary - -Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point. - -**Module** — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service. - -**Interface** — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow — they refer only to the type-level surface). - -**Implementation** — what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise. - -**Depth** — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation. - -**Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context). - -**Adapter** — a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside). - -**Leverage** — what callers get from depth: more capability per unit of interface they learn. One implementation pays back across N call sites and M tests. - -**Locality** — what maintainers get from depth: change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere. - -## Deep vs shallow - -**Deep module** = small interface + lots of implementation: - -``` -┌─────────────────────┐ -│ Small Interface │ ← Few methods, simple params -├─────────────────────┤ -│ │ -│ Deep Implementation│ ← Complex logic hidden -│ │ -└─────────────────────┘ -``` - -**Shallow module** = large interface + little implementation (avoid): - -``` -┌─────────────────────────────────┐ -│ Large Interface │ ← Many methods, complex params -├─────────────────────────────────┤ -│ Thin Implementation │ ← Just passes through -└─────────────────────────────────┘ -``` - -When designing an interface, ask: - -- Can I reduce the number of methods? -- Can I simplify the parameters? -- Can I hide more complexity inside? - -## Principles - -- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface. -- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep. -- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape. -- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it. - -## Designing for testability - -Good interfaces make testing natural: - -1. **Accept dependencies, don't create them.** - - ```typescript - // Testable - function processOrder(order, paymentGateway) {} - - // Hard to test - function processOrder(order) { - const gateway = new StripeGateway(); - } - ``` - -2. **Return results, don't produce side effects.** - - ```typescript - // Testable - function calculateDiscount(cart): Discount {} - - // Hard to test - function applyDiscount(cart): void { - cart.total -= discount; - } - ``` - -3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup. - -## Relationships - -- A **Module** has exactly one **Interface** (the surface it presents to callers and tests). -- **Depth** is a property of a **Module**, measured against its **Interface**. -- A **Seam** is where a **Module**'s **Interface** lives. -- An **Adapter** sits at a **Seam** and satisfies the **Interface**. -- **Depth** produces **Leverage** for callers and **Locality** for maintainers. - -## Rejected framings - -- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead. -- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know. -- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**. - -## Going deeper - -- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing. -- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement. diff --git a/.agents/skills/diagnosing-bugs/SKILL.md b/.agents/skills/diagnosing-bugs/SKILL.md deleted file mode 100644 index f400de7..0000000 --- a/.agents/skills/diagnosing-bugs/SKILL.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -name: diagnosing-bugs -description: Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow. ---- - -# Diagnosing Bugs - -A discipline for hard bugs. Skip phases only when explicitly justified. - -When exploring the codebase, read `CONTEXT.md` (if it exists) to get a clear mental model of the relevant modules, and check ADRs in the area you're touching. - -## Phase 1 — Build a feedback loop - -**This is the skill.** Everything else is mechanical. If you have a **tight** pass/fail signal for the bug — one that goes red on _this_ bug — you will find the cause; bisection, hypothesis-testing, and instrumentation all just consume it. If you don't have one, no amount of staring at code will save you. - -Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.** - -### Ways to construct one — try them in roughly this order - -1. **Failing test** at whatever seam reaches the bug — unit, integration, e2e. -2. **Curl / HTTP script** against a running dev server. -3. **CLI invocation** with a fixture input, diffing stdout against a known-good snapshot. -4. **Headless browser script** (Playwright / Puppeteer) — drives the UI, asserts on DOM/console/network. -5. **Replay a captured trace.** Save a real network request / payload / event log to disk; replay it through the code path in isolation. -6. **Throwaway harness.** Spin up a minimal subset of the system (one service, mocked deps) that exercises the bug code path with a single function call. -7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode. -8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it. -9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs. -10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `scripts/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you. - -Build the right feedback loop, and the bug is 90% fixed. - -### Tighten the loop - -Treat the loop as a product. Once you have _a_ loop, **tighten** it: - -- Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.) -- Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".) -- Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.) - -A 30-second flaky loop is barely better than no loop; a 2-second deterministic one is tight — a debugging superpower. - -### Non-deterministic bugs - -The goal is not a clean repro but a **higher reproduction rate**. Loop the trigger 100×, parallelise, add stress, narrow timing windows, inject sleeps. A 50%-flake bug is debuggable; 1% is not — keep raising the rate until it's debuggable. - -### When you genuinely cannot build a loop - -Stop and say so explicitly. List what you tried. Ask the user for: (a) access to whatever environment reproduces it, (b) a captured artifact (HAR file, log dump, core dump, screen recording with timestamps), or (c) permission to add temporary production instrumentation. Do **not** proceed to hypothesise without a loop. - -### Completion criterion — a tight loop that goes red - -Phase 1 is done when the loop is **tight** and **red-capable**: you can name **one command** — a script path, a test invocation, a curl — that you have **already run at least once** (paste the invocation and its output), and that is: - -- [ ] **Red-capable** — it drives the actual bug code path and asserts the **user's exact symptom**, so it can go red on this bug and green once fixed. Not "runs without erroring" — it must be able to _catch this specific bug_. -- [ ] **Deterministic** — same verdict every run (flaky bugs: a pinned, high reproduction rate, per above). -- [ ] **Fast** — seconds, not minutes. -- [ ] **Agent-runnable** — you can run it unattended; a human in the loop only via `scripts/hitl-loop.template.sh`. - -If you catch yourself reading code to build a theory before this command exists, **stop — jumping straight to a hypothesis is the exact failure this skill prevents.** No red-capable command, no Phase 2. - -## Phase 2 — Reproduce + minimise - -Run the loop. Watch it go red — the bug appears. - -Confirm: - -- [ ] The loop produces the failure mode the **user** described — not a different failure that happens to be nearby. Wrong bug = wrong fix. -- [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against). -- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it. - -### Minimise - -Once it's red, shrink the repro to the **smallest scenario that still goes red**. Cut inputs, callers, config, data, and steps **one at a time**, re-running the loop after each cut — keep only what's load-bearing for the failure. - -Why bother: a minimal repro shrinks the hypothesis space in Phase 3 (fewer moving parts left to suspect) and becomes the clean regression test in Phase 5. - -Done when **every remaining element is load-bearing** — removing any one of them makes the loop go green. - -Do not proceed until you have reproduced **and** minimised. - -## Phase 3 — Hypothesise - -Generate **3–5 ranked hypotheses** before testing any of them. Single-hypothesis generation anchors on the first plausible idea. - -Each hypothesis must be **falsifiable**: state the prediction it makes. - -> Format: "If <X> is the cause, then <changing Y> will make the bug disappear / <changing Z> will make it worse." - -If you cannot state the prediction, the hypothesis is a vibe — discard or sharpen it. - -**Show the ranked list to the user before testing.** They often have domain knowledge that re-ranks instantly ("we just deployed a change to #3"), or know hypotheses they've already ruled out. Cheap checkpoint, big time saver. Don't block on it — proceed with your ranking if the user is AFK. - -## Phase 4 — Instrument - -Each probe must map to a specific prediction from Phase 3. **Change one variable at a time.** - -Tool preference: - -1. **Debugger / REPL inspection** if the env supports it. One breakpoint beats ten logs. -2. **Targeted logs** at the boundaries that distinguish hypotheses. -3. Never "log everything and grep". - -**Tag every debug log** with a unique prefix, e.g. `[DEBUG-a4f2]`. Cleanup at the end becomes a single grep. Untagged logs survive; tagged logs die. - -**Perf branch.** For performance regressions, logs are usually wrong. Instead: establish a baseline measurement (timing harness, `performance.now()`, profiler, query plan), then bisect. Measure first, fix second. - -## Phase 5 — Fix + regression test - -Write the regression test **before the fix** — but only if there is a **correct seam** for it. - -A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence. - -**If no correct seam exists, that itself is the finding.** Note it. The codebase architecture is preventing the bug from being locked down. Flag this for the next phase. - -If a correct seam exists: - -1. Turn the minimised repro into a failing test at that seam. -2. Watch it fail. -3. Apply the fix. -4. Watch it pass. -5. Re-run the Phase 1 feedback loop against the original (un-minimised) scenario. - -## Phase 6 — Cleanup + post-mortem - -Required before declaring done: - -- [ ] Original repro no longer reproduces (re-run the Phase 1 loop) -- [ ] Regression test passes (or absence of seam is documented) -- [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix) -- [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location) -- [ ] The hypothesis that turned out correct is stated in the commit / PR message — so the next debugger learns - -**Then ask: what would have prevented this bug?** If the answer involves architectural change (no good test seam, tangled callers, hidden coupling) hand off to the `/improve-codebase-architecture` skill with the specifics. Make the recommendation **after** the fix is in, not before — you have more information now than when you started. diff --git a/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh b/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh deleted file mode 100644 index 40afc46..0000000 --- a/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# Human-in-the-loop reproduction loop. -# Copy this file, edit the steps below, and run it. -# The agent runs the script; the user follows prompts in their terminal. -# -# Usage: -# bash hitl-loop.template.sh -# -# Two helpers: -# step "<instruction>" → show instruction, wait for Enter -# capture VAR "<question>" → show question, read response into VAR -# -# At the end, captured values are printed as KEY=VALUE for the agent to parse. - -set -euo pipefail - -step() { - printf '\n>>> %s\n' "$1" - read -r -p " [Enter when done] " _ -} - -capture() { - local var="$1" question="$2" answer - printf '\n>>> %s\n' "$question" - read -r -p " > " answer - printf -v "$var" '%s' "$answer" -} - -# --- edit below --------------------------------------------------------- - -step "Open the app at http://localhost:3000 and sign in." - -capture ERRORED "Click the 'Export' button. Did it throw an error? (y/n)" - -capture ERROR_MSG "Paste the error message (or 'none'):" - -# --- edit above --------------------------------------------------------- - -printf '\n--- Captured ---\n' -printf 'ERRORED=%s\n' "$ERRORED" -printf 'ERROR_MSG=%s\n' "$ERROR_MSG" diff --git a/.agents/skills/domain-modeling/ADR-FORMAT.md b/.agents/skills/domain-modeling/ADR-FORMAT.md deleted file mode 100644 index da7e78e..0000000 --- a/.agents/skills/domain-modeling/ADR-FORMAT.md +++ /dev/null @@ -1,47 +0,0 @@ -# ADR Format - -ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc. - -Create the `docs/adr/` directory lazily — only when the first ADR is needed. - -## Template - -```md -# {Short title of the decision} - -{1-3 sentences: what's the context, what did we decide, and why.} -``` - -That's it. An ADR can be a single paragraph. The value is in recording *that* a decision was made and *why* — not in filling out sections. - -## Optional sections - -Only include these when they add genuine value. Most ADRs won't need them. - -- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited -- **Considered Options** — only when the rejected alternatives are worth remembering -- **Consequences** — only when non-obvious downstream effects need to be called out - -## Numbering - -Scan `docs/adr/` for the highest existing number and increment by one. - -## When to offer an ADR - -All three of these must be true: - -1. **Hard to reverse** — the cost of changing your mind later is meaningful -2. **Surprising without context** — a future reader will look at the code and wonder "why on earth did they do it this way?" -3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons - -If a decision is easy to reverse, skip it — you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing." - -### What qualifies - -- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres." -- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP." -- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out. -- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s. -- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate. -- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract." -- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months. diff --git a/.agents/skills/domain-modeling/CONTEXT-FORMAT.md b/.agents/skills/domain-modeling/CONTEXT-FORMAT.md deleted file mode 100644 index eaf2a18..0000000 --- a/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +++ /dev/null @@ -1,60 +0,0 @@ -# CONTEXT.md Format - -## Structure - -```md -# {Context Name} - -{One or two sentence description of what this context is and why it exists.} - -## Language - -**Order**: -{A one or two sentence description of the term} -_Avoid_: Purchase, transaction - -**Invoice**: -A request for payment sent to a customer after delivery. -_Avoid_: Bill, payment request - -**Customer**: -A person or organization that places orders. -_Avoid_: Client, buyer, account -``` - -## Rules - -- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others under `_Avoid_`. -- **Keep definitions tight.** One or two sentences max. Define what it IS, not what it does. -- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs. -- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine. - -## Single vs multi-context repos - -**Single context (most repos):** One `CONTEXT.md` at the repo root. - -**Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other: - -```md -# Context Map - -## Contexts - -- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders -- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments -- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping - -## Relationships - -- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking -- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices -- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money` -``` - -The skill infers which structure applies: - -- If `CONTEXT-MAP.md` exists, read it to find contexts -- If only a root `CONTEXT.md` exists, single context -- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved - -When multiple contexts exist, infer which one the current topic relates to. If unclear, ask. diff --git a/.agents/skills/domain-modeling/SKILL.md b/.agents/skills/domain-modeling/SKILL.md deleted file mode 100644 index d0f7e1a..0000000 --- a/.agents/skills/domain-modeling/SKILL.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -name: domain-modeling -description: Build and sharpen a project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to maintain the domain model. ---- - -# Domain Modeling - -Actively build and sharpen the project's domain model as you design. This is the *active* discipline — challenging terms, inventing edge-case scenarios, and writing the glossary and decisions down the moment they crystallise. (Merely *reading* `CONTEXT.md` for vocabulary is not this skill — that's a one-line habit any skill can do. This skill is for when you're changing the model, not just consuming it.) - -## File structure - -Most repos have a single context: - -``` -/ -├── CONTEXT.md -├── docs/ -│ └── adr/ -│ ├── 0001-event-sourced-orders.md -│ └── 0002-postgres-for-write-model.md -└── src/ -``` - -If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives: - -``` -/ -├── CONTEXT-MAP.md -├── docs/ -│ └── adr/ ← system-wide decisions -├── src/ -│ ├── ordering/ -│ │ ├── CONTEXT.md -│ │ └── docs/adr/ ← context-specific decisions -│ └── billing/ -│ ├── CONTEXT.md -│ └── docs/adr/ -``` - -Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed. - -## During the session - -### Challenge against the glossary - -When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?" - -### Sharpen fuzzy language - -When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things." - -### Discuss concrete scenarios - -When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts. - -### Cross-reference with code - -When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?" - -### Update CONTEXT.md inline - -When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md). - -`CONTEXT.md` should be totally devoid of implementation details. Do not treat `CONTEXT.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else. - -### Offer ADRs sparingly - -Only offer to create an ADR when all three are true: - -1. **Hard to reverse** — the cost of changing your mind later is meaningful -2. **Surprising without context** — a future reader will wonder "why did they do it this way?" -3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons - -If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md). diff --git a/.agents/skills/grill-me/SKILL.md b/.agents/skills/grill-me/SKILL.md deleted file mode 100644 index 9470cfc..0000000 --- a/.agents/skills/grill-me/SKILL.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: grill-me -description: A relentless interview to sharpen a plan or design. -disable-model-invocation: true ---- - -Run a `/grilling` session. diff --git a/.agents/skills/grill-with-docs/SKILL.md b/.agents/skills/grill-with-docs/SKILL.md deleted file mode 100644 index bed05d2..0000000 --- a/.agents/skills/grill-with-docs/SKILL.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: grill-with-docs -description: A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go. -disable-model-invocation: true ---- - -Run a `/grilling` session, using the `/domain-modeling` skill. diff --git a/.agents/skills/grilling/SKILL.md b/.agents/skills/grilling/SKILL.md deleted file mode 100644 index fe3569d..0000000 --- a/.agents/skills/grilling/SKILL.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: grilling -description: Interview the user relentlessly about a plan or design. Use when the user wants to stress-test a plan before building, or uses any 'grill' trigger phrases. ---- - -Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. - -Ask the questions one at a time, waiting for feedback on each question before continuing. Asking multiple questions at once is bewildering. - -If a question can be answered by exploring the codebase, explore the codebase instead. diff --git a/.agents/skills/handoff/SKILL.md b/.agents/skills/handoff/SKILL.md deleted file mode 100644 index ec762d9..0000000 --- a/.agents/skills/handoff/SKILL.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: handoff -description: Compact the current conversation into a handoff document for another agent to pick up. -argument-hint: "What will the next session be used for?" -disable-model-invocation: true ---- - -Write a handoff document summarising the current conversation so a fresh agent can continue the work. Save to the temporary directory of the user's OS - not the current workspace. - -Include a "suggested skills" section in the document, which suggests skills that the agent should invoke. - -Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead. - -Redact any sensitive information, such as API keys, passwords, or personally identifiable information. - -If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly. diff --git a/.agents/skills/improve-codebase-architecture/HTML-REPORT.md b/.agents/skills/improve-codebase-architecture/HTML-REPORT.md deleted file mode 100644 index 17f6d2c..0000000 --- a/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +++ /dev/null @@ -1,123 +0,0 @@ -# HTML Report Format - -The architectural review is rendered as a single self-contained HTML file in the OS temp directory. Tailwind and Mermaid both come from CDNs. Mermaid handles graph-shaped diagrams reliably; hand-built divs and inline SVG handle the more editorial visuals (mass diagrams, cross-sections). Mix the two — don't lean on Mermaid for everything, it'll start to look generic. - -## Scaffold - -```html -<!doctype html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <title>Architecture review — {{repo name}} - - - - - -
-
...
-
...
-
...
-
- - -``` - -## Header - -Repo name, date, and a compact legend: solid box = module, dashed line = seam, red arrow = leakage, thick dark box = deep module. No introduction paragraph — straight into the candidates. - -## Candidate card - -The diagrams carry the weight. Prose is sparse, plain, and uses the glossary terms (from the `/codebase-design` skill) without ceremony. - -Each candidate is one `
`: - -- **Title** — short, names the deepening (e.g. "Collapse the Order intake pipeline"). -- **Badge row** — recommendation strength (`Strong` = emerald, `Worth exploring` = amber, `Speculative` = slate), plus a tag for the dependency category (`in-process`, `local-substitutable`, `ports & adapters`, `mock`). -- **Files** — monospaced list, `font-mono text-sm`. -- **Before / After diagram** — the centrepiece. Two columns, side by side. See patterns below. -- **Problem** — one sentence. What hurts. -- **Solution** — one sentence. What changes. -- **Wins** — bullets, ≤6 words each. e.g. "Tests hit one interface", "Pricing logic stops leaking", "Delete 4 shallow wrappers". -- **ADR callout** (if applicable) — one line in an amber-tinted box. - -No paragraphs of explanation. If the diagram needs a paragraph to be understood, redraw the diagram. - -## Diagram patterns - -Pick the pattern that fits the candidate. Mix them. Don't make every diagram look the same — variety is part of the point. - -### Mermaid graph (the workhorse for dependencies / call flow) - -Use a Mermaid `flowchart` or `graph` when the point is "X calls Y calls Z, and look at the mess." Wrap it in a Tailwind-styled card so it doesn't feel parachuted in. Style with classDef to colour leakage edges red and the deep module dark. Sequence diagrams work well for "before: 6 round-trips; after: 1." - -```html -
-
-    flowchart LR
-      A[OrderHandler] --> B[OrderValidator]
-      B --> C[OrderRepo]
-      C -.leak.-> D[PricingClient]
-      classDef leak stroke:#dc2626,stroke-width:2px;
-      class C,D leak
-  
-
-``` - -### Hand-built boxes-and-arrows (when Mermaid's layout fights you) - -Modules as `
`s with borders and labels. Arrows as inline SVG `` or `` elements positioned absolutely over a relative container. Reach for this when you want the "after" diagram to feel like one thick-bordered deep module with greyed-out internals — Mermaid won't render that with the right weight. - -### Cross-section (good for layered shallowness) - -Stack horizontal bands (`h-12 border-l-4`) to show layers a call passes through. Before: 6 thin layers each doing nothing. After: 1 thick band labelled with the consolidated responsibility. - -### Mass diagram (good for "interface as wide as implementation") - -Two rectangles per module — one for interface surface area, one for implementation. Before: interface rectangle is nearly as tall as the implementation rectangle (shallow). After: interface rectangle is short, implementation rectangle is tall (deep). - -### Call-graph collapse - -Before: a tree of function calls rendered as nested boxes. After: the same tree collapsed into one box, with the now-internal calls shown faded inside it. - -## Style guidance - -- Lean editorial, not corporate-dashboard. Generous whitespace. Serif optional for headings (`font-serif` works well with stone/slate). -- Colour sparingly: one accent (emerald or indigo) plus red for leakage and amber for warnings. -- Keep diagrams ~320px tall so before/after sits comfortably side by side without scrolling. -- Use `text-xs uppercase tracking-wider` for module labels inside diagrams — they should read as schematic, not as UI. -- The only scripts are the Tailwind CDN and the Mermaid ESM import. The report is otherwise static — no app code, no interactivity beyond Mermaid's own rendering. - -## Top recommendation section - -One larger card. Candidate name, one sentence on why, anchor link to its card. That's it. - -## Tone - -Plain English, concise — but the architectural nouns and verbs come straight from the `/codebase-design` skill. Concision is not an excuse to drift. - -**Use exactly:** module, interface, implementation, depth, deep, shallow, seam, adapter, leverage, locality. - -**Never substitute:** component, service, unit (for module) · API, signature (for interface) · boundary (for seam) · layer, wrapper (for module, when you mean module). - -**Phrasings that fit the style:** - -- "Order intake module is shallow — interface nearly matches the implementation." -- "Pricing leaks across the seam." -- "Deepen: one interface, one place to test." -- "Two adapters justify the seam: HTTP in prod, in-memory in tests." - -**Wins bullets** name the gain in glossary terms: *"locality: bugs concentrate in one module"*, *"leverage: one interface, N call sites"*, *"interface shrinks; implementation absorbs the wrappers"*. Don't write *"easier to maintain"* or *"cleaner code"* — those terms aren't in the glossary and don't earn their place. - -No hedging, no throat-clearing, no "it's worth noting that…". If a sentence could be a bullet, make it a bullet. If a bullet could be cut, cut it. If a term isn't in the `/codebase-design` glossary, reach for one that is before inventing a new one. diff --git a/.agents/skills/improve-codebase-architecture/SKILL.md b/.agents/skills/improve-codebase-architecture/SKILL.md deleted file mode 100644 index a79b493..0000000 --- a/.agents/skills/improve-codebase-architecture/SKILL.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: improve-codebase-architecture -description: Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick. -disable-model-invocation: true ---- - -# Improve Codebase Architecture - -Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability. - -This command is _informed_ by the project's domain model and built on a shared design vocabulary: - -- Run the `/codebase-design` skill for the architecture vocabulary (**module**, **interface**, **depth**, **seam**, **adapter**, **leverage**, **locality**) and its principles (the deletion test, "the interface is the test surface", "one adapter = hypothetical seam, two = real"). Use these terms exactly in every suggestion — don't drift into "component," "service," "API," or "boundary." -- The domain language in `CONTEXT.md` gives names to good seams; ADRs in `docs/adr/` record decisions this command should not re-litigate. - -## Process - -### 1. Explore - -Read the project's domain glossary (`CONTEXT.md`) and any ADRs in the area you're touching first. - -Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction: - -- Where does understanding one concept require bouncing between many small modules? -- Where are modules **shallow** — interface nearly as complex as the implementation? -- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)? -- Where do tightly-coupled modules leak across their seams? -- Which parts of the codebase are untested, or hard to test through their current interface? - -Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want. - -### 2. Present candidates as an HTML report - -Write a self-contained HTML file to the OS temp directory so nothing lands in the repo. Resolve the temp dir from `$TMPDIR`, falling back to `/tmp` (or `%TEMP%` on Windows), and write to `/architecture-review-.html` so each run gets a fresh file. Open it for the user — `xdg-open ` on Linux, `open ` on macOS, `start ` on Windows — and tell them the absolute path. - -The report uses **Tailwind via CDN** for layout and styling, and **Mermaid via CDN** for diagrams where a graph/flow/sequence reliably communicates the structure. Mix Mermaid with hand-crafted CSS/SVG visuals — use Mermaid when relationships are graph-shaped (call graphs, dependencies, sequences), and hand-built divs/SVG when you want something more editorial (mass diagrams, cross-sections, collapse animations). Each candidate gets a **before/after visualisation**. Be visual. - -For each candidate, render a card with: - -- **Files** — which files/modules are involved -- **Problem** — why the current architecture is causing friction -- **Solution** — plain English description of what would change -- **Benefits** — explained in terms of locality and leverage, and how tests would improve -- **Before / After diagram** — side-by-side, custom-drawn, illustrating the shallowness and the deepening -- **Recommendation strength** — one of `Strong`, `Worth exploring`, `Speculative`, rendered as a badge - -End the report with a **Top recommendation** section: which candidate you'd tackle first and why. - -**Use CONTEXT.md vocabulary for the domain, and the `/codebase-design` vocabulary for the architecture.** If `CONTEXT.md` defines "Order," talk about "the Order intake module" — not "the FooBarHandler," and not "the Order service." - -**ADR conflicts**: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly in the card (e.g. a warning callout: _"contradicts ADR-0007 — but worth reopening because…"_). Don't list every theoretical refactor an ADR forbids. - -See [HTML-REPORT.md](HTML-REPORT.md) for the full HTML scaffold, diagram patterns, and styling guidance. - -Do NOT propose interfaces yet. After the file is written, ask the user: "Which of these would you like to explore?" - -### 3. Grilling loop - -Once the user picks a candidate, run the `/grilling` skill to walk the design tree with them — constraints, dependencies, the shape of the deepened module, what sits behind the seam, what tests survive. - -Side effects happen inline as decisions crystallize — run the `/domain-modeling` skill to keep the domain model current as you go: - -- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md`. Create the file lazily if it doesn't exist. -- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there. -- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. -- **Want to explore alternative interfaces for the deepened module?** Run the `/codebase-design` skill and use its design-it-twice parallel sub-agent pattern. diff --git a/.agents/skills/writing-great-skills/GLOSSARY.md b/.agents/skills/writing-great-skills/GLOSSARY.md deleted file mode 100644 index 969c699..0000000 --- a/.agents/skills/writing-great-skills/GLOSSARY.md +++ /dev/null @@ -1,195 +0,0 @@ -# Glossary — Building Great Skills - -The domain model for what makes a skill great. A skill exists to wrangle determinism out of a stochastic system; the root virtue is **Predictability**, and every term below is a lever on it. This is the disclosed reference for [`writing-great-skills`](SKILL.md). - -The terms are grouped by axis: **Invocation** (how a skill is reached), **Information Hierarchy** (how its content is arranged), **Steering** (how the agent's runtime behaviour is shaped), and **Pruning** (how it is kept lean). Each **failure mode** lives beside the lever that cures it, tagged _failure mode_. - -**Bold terms** in any definition are themselves defined in this glossary; find them by their heading. - -## Predictability - -The degree to which a skill makes the agent behave the same _way_ on every run — the same process, not the same output (a brainstorming skill should _predictably_ diverge; its tokens vary, its behaviour doesn't). The root virtue every other term serves — cost and maintainability are symptoms of it, not rivals. - -_Avoid_: consistency, reliability, robustness, output-determinism - -## Invocation - -How a skill is reached — and the two loads you pay for the choice. - -### Model-Invoked - -A skill that keeps its **description** field, so the agent can see it and fire it autonomously — and the human can still type its name, so model-invocation always _includes_ user reach. There is no model-only state: a description only ever _adds_ agent discovery, never removes the human's. Pays a permanent **context load** on every turn in exchange for that discoverability. Reachable by other skills, because the description that makes it agent-discoverable makes it invocable. A model-invoked skill whose content is all **reference** is also one home for shared reference: another skill can invoke it, so reference needed by several skills lives in one place. Pick model-invocation only when the agent must reach the skill on its own; if it never fires except by hand, drop the description and pay no context load. - -_Avoid_: ability, tool, capability - -### User-Invoked - -A skill with its **description** stripped — invisible to the agent and reachable only by the human typing its name (user-_only_, where **model-invoked** is user-_and-agent_). Trades agent-discoverability for zero **context load**. Because it has no description, nothing but the human can reach it: no other skill can fire it. - -_Avoid_: procedure, workflow, command - -### Description - -The skill's machine-readable trigger, and the one **context pointer** a **model-invoked** skill is forced to keep loaded at all times. Its mere presence _is_ the invocation axis: keep it and the skill is model-invoked (and reachable by other skills); delete it and the skill is **user-invoked**, reachable only by the human. The source of a model-invoked skill's **context load**. - -_Avoid_: frontmatter, summary - -### Context Pointer - -A reference held in the agent's context that names some out-of-context material and encodes the condition for reaching it. The **description** is the top-level context pointer (context window → skill); pointers to disclosed files are the same object one level down. Its wording, not the target, decides _when_ the agent reaches — and _how reliably_. A must-have target behind a weakly worded pointer is a variance bug: fix the wording first, and inline the material only if sharpening fails. - -_Avoid_: link, reference, import - -### Context Load - -The cost a **model-invoked** skill imposes on the agent's context window — its **description**, always loaded, spending both tokens and attention. What **user-invoked** skills escape by having no description, and the brake on splitting into more model-invoked skills. - -_Avoid_: token cost, context bloat - -### Cognitive Load - -The cost a **user-invoked** skill imposes on the human — what they must hold in their head: which skills exist and when to reach for each (the human is the index). What **model-invocation** removes by being agent-discoverable, and the brake on splitting into more user-invoked skills. Not a cost to minimise: it is the price of human agency, the reason some skills stay user-invoked. Spend it where human judgement matters; remove it where it does not. - -_Avoid_: human index, burden, overhead - -### Router Skill - -A **user-invoked** skill whose job is to point at your other user-invoked skills — naming each and when to reach for it — so the human has one skill to remember instead of many. It can only hint, never fire them: user-invoked skills have no **description**, so nothing but the human can reach them. The cure for **cognitive load** when user-invoked skills multiply. - -_Avoid_: dispatcher, menu, registry, index, router procedure - -### Granularity - -How finely you divide skills. Finer division spends one of the two loads: more **model-invoked** skills spend **context load** (more descriptions crowding the window and competing for attention); more **user-invoked** skills spend **cognitive load** (more for the human to remember and reach for). Two cuts guide the division. By **invocation**, split off a model-invoked skill where you have a distinct **leading word** to trigger it — a trigger word you actually use in your prompts. By **sequence**, split a run of **steps** where a step's **post-completion steps** need hiding, since isolating it in its own context clears what follows. Beware the reverse: merging sequences exposes each step's post-completion steps to what follows, inviting premature completion. - -_Avoid_: chunking, modularity - -## Information Hierarchy - -How a skill's content is arranged, and how far down the ladder each piece sits. - -### Information Hierarchy - -A skill's content ranked by how immediately the agent needs it — a single ladder, produced by two cuts: in-file or behind a pointer, and step or reference. The rungs: - -- **Steps** — in-file, primary -- **Reference**, in-file — secondary -- **Reference**, disclosed — behind a **context pointer** - -A skill with no **steps** uses just the bottom two rungs — often a legitimately flat peer-set (e.g. every rule of a review on one rung), which is a fine arrangement, not a smell. The hierarchy is independent of invocation: a skill can be model- or user-invoked whether it is all steps, all reference, or both. When a skill has steps, in-file reference that should be disclosed buries them and turns attending to them into a coin-flip — a variance lever, not just a legibility one. Keep the top of the ladder legible; push down it whatever you can. - -_Avoid_: structure, organization, layout - -### Steps - -The ordered actions the agent performs — when a skill has them, the primary tier of its content, and the part that earns its place in SKILL.md. Not every skill has steps: a skill can be all steps (`tdd`), all **reference** (a review), or both, independent of invocation. Every step ends on a **completion criterion**, clear or vague. - -_Avoid_: workflow, instructions, choreography - -### Reference - -Material the agent refers to on demand — definitions, facts, parameters, examples, conditional instructions. When a skill has **steps** it is secondary to them; when a skill has none it is the entire content; or it lives outside any skill entirely — see **External Reference**. Reached via **context pointers**, and the prime candidate for **progressive disclosure**. - -_Avoid_: supporting material, docs, background - -### External Reference - -**Reference** that lives outside the skill system — a plain file, no **description**, no **steps**, not invocable — that any skill can point at. The home for shared reference that needn't fire on its own, and the only shared home two **user-invoked** skills can use, since neither has a description and so neither can fire the other. - -_Avoid_: doc, resource, knowledge base - -### Progressive Disclosure - -Moving **reference** down the ladder — out of SKILL.md and behind a **context pointer** — so the top stays legible. Not primarily a token optimisation; it is how the **information hierarchy** is protected. Licensed by **branching**: disclose what only some branches need, inline what every path needs, and if a pointer fires unreliably on must-have material, sharpen its wording, and pull it back inline only if that fails. - -_Avoid_: lazy loading, chunking - -### Co-location - -Keeping the material an agent needs at once in one place — a concept's definition, rules, and caveats under a single heading, not scattered across the file — so reading one part brings its neighbours with it. The within-file companion to the **Information Hierarchy**: the hierarchy ranks _how far down_ a piece sits; co-location decides _what sits beside it_ once there. There is no formula for the right format of a body of **reference**; the test is that a skill should read like documentation written for the agent, and grouped material reads that way where scattered material does not. Distinct from **Duplication**: that repeats one meaning in two places, where scattering fragments a single meaning across many. - -_Avoid_: grouping, clustering, cohesion - -### Sprawl - -_Failure mode._ A skill that is simply too long — too many lines in SKILL.md — independent of whether they are stale or repeated. Even an all-live, all-unique skill can sprawl. It costs readability (the agent wades through more before it can act, and attention thins across the excess), maintainability (every extra line is one more to keep **relevant**), and tokens. The cure is the **information hierarchy**: push **reference** down behind **context pointers**, and split by **branch** or sequence so each path carries only what it needs. Distinct from **sediment** (length from stale accumulation) and **duplication** (length from repeated meaning) — sprawl is length itself, whatever its cause. - -_Avoid_: bloat, length, size, verbosity - -## Steering - -The levers that shape the agent's runtime behaviour toward **Predictability**. - -### Branch - -A distinct way a skill can be invoked — a case the skill handles — so different runs take different paths through it. A skill with many steps may carry many branches; a linear one has none. - -_Avoid_: path, case, fork - -### Leading Word - -A compact concept — also called a _Leitwort_ — already living in the model's pretraining, that the agent thinks with while running the skill. It encodes a behavioural principle in the fewest possible tokens by invoking priors the model already holds (e.g. _lesson_, _proximal zone of development_, _fog of war_, _tracer bullets_). Repeated as a token, never as a sentence, it accumulates a distributed definition across the skill and anchors a whole region of behaviour. Coining your own works if you define it clearly, but a made-up word recruits no priors — you pay in definition tokens what a pretrained word gives free. Reach for an existing word first. - -A leading word serves **predictability** twice. In the body it anchors **execution** — the agent reaches for the same behaviour every time the concept appears, and inside flat reference it focuses attention on a class of thing to look for, recruiting the right checks each run. In the **description** it anchors **invocation** — and not only within the skill: when the same word lives in your prompts, your docs, and your codebase, the agent links that shared language to the skill and fires it more reliably. Word a description with the leading words you actually use when you want the skill. - -_Avoid_: keyword, term, motif - -### Completion Criterion - -The condition that tells the agent a unit of work is done — the target it judges against. Two properties make it a lever, not just a quality. Its **clarity** (can the agent tell done from not-done?) resists **premature completion** — a vague bound ("understanding reached") lets the agent declare done and slip to the next step; this axis needs _steps_ to bite, since premature completion is a between-steps failure. Its **demand** (how much it requires) sets **legwork** — "every modified model accounted for" forces thorough work where "produce a change list" does not — and this axis is _not_ step-bound: it can bind a body of flat reference too, which is how a skill with no steps still carries an exhaustiveness bar ("every rule applied"). The strongest criteria are both checkable and exhaustive. - -_Avoid_: done condition, exit condition, stopping rule - -### Legwork - -The work an agent does behind the scenes within a single step — reading files, exploring the codebase, making changes, digging up what it needs rather than offloading to the user. It lives below the step structure: never written as its own step, latent in the wording, controlled by the agent rather than the skill. The within-step counterpart to **post-completion steps**' across-step pull. Raised by a **leading word** (_comprehensive_, _thorough_) or a **completion criterion** that demands the work be exhaustive — including the demand axis applied to flat reference, which is what drives a skill of flat reference to cover all its rungs. Goes thin either when that demand is missing or when **premature completion** cuts the step short. - -_Avoid_: scope, effort, diligence, coverage - -### Post-Completion Steps - -The **steps** that follow the current step. Visible, they pull the agent forward into **premature completion** — the more it sees, the stronger the tug; the defence is to hide them by splitting the sequence of steps into two. - -_Avoid_: horizon, fog of war, lookahead - -### Premature Completion - -_Failure mode._ Ending the current step before it is genuinely done, because the agent's attention slips to being done rather than to the work. A between-steps failure: it needs **steps** to occur — a skill with no steps that quits early isn't premature completion but thin **legwork** under an unmet demand. A tug-of-war between two forces: visible **post-completion steps** (the pull forward) and the **completion criterion**'s clarity (the resistance — a sharp, checkable bar holds; a vague one gives way). Fuzziness is the necessary condition: a sharp bound resists the pull no matter how many later steps are visible, so a step that never rushes needs no defending. Two levers hold a step that does, but reach for them in order: **sharpen the bound first** — it is local and cheap. Only when the criterion is irreducibly fuzzy _and_ you actually observe the rush do you **hide the later steps** — and hiding only works across a real context boundary (a user-invoked hand-off or a subagent dispatch; an inline model-invoked call leaves the later steps in context and clears nothing). One cause of thin legwork, but distinct from it: legwork can be thin even when a step runs to full completion. - -_Avoid_: premature closure, the rush, rushing, shortcutting - -## Pruning - -Keeping a skill lean — each remedy paired with the failure it cures. - -### Single Source of Truth - -The desired state where each meaning lives in exactly one authoritative place, so a change to the skill's behaviour is a change in one place. **Duplication** is its violation. - -_Avoid_: home, canonical location - -### Duplication - -_Failure mode._ The same meaning given more than one **single source of truth**. It costs maintenance (change one place, you must change the others), costs tokens, and inflates prominence — repeating a meaning weights it on the ladder past its real rank. The accidental inverse of a **leading word**, which raises attention on purpose by repeating a token, never the meaning. - -_Avoid_: repetition, redundancy - -### Relevance - -Whether a line still bears on what the skill does — the lens for what to keep. A line loses relevance either by never bearing on the task (mere exposition, or a **branch** that should be disclosed) or by going stale: drifting out of date as the behaviour or world it describes changes. Shorter skills are easier to keep relevant, because each line is cheaper to check. Distinct from **no-op**: relevance asks whether a line bears on the task, not whether it changes behaviour. - -_Avoid_: load-bearing, staleness, freshness - -### Sediment - -_Failure mode._ Layers of old content that settle in a skill and are never cleared, because adding feels safe and removing feels risky — so stale and irrelevant lines accumulate and you must core down through them to find what is still live. The default fate of any skill without a pruning discipline; the slow erosion of **relevance**, as opposed to **duplication**'s repeated meaning. - -_Avoid_: accretion, bloat, cruft, rot - -### No-Op - -_Failure mode._ An instruction that changes nothing because the model already does it by default — you pay load to tell the agent what it would do anyway. The test: does a line change behaviour versus the default? A line can be perfectly **relevant** and still be a no-op. The same priors that make a **leading word** free make a no-op worthless. - -A leading word is a _technique_; No-Op is a _verdict_ on a line — and they cross. A leading word too weak to beat the default is a no-op (_be thorough_ when the agent is already thorough-ish), and the fix is a stronger word that passes the verdict (_relentless_), not a different technique. So the No-Op test — does it change behaviour versus the default? — is also how you grade whether a leading word is earning its repetitions. This is model-relative, not reader-relative: two people disagreeing over whether a line is a no-op disagree about the default, and settle it by running the skill, not by debate. - -_Avoid_: redundant instruction, restating the obvious, belaboring diff --git a/.agents/skills/writing-great-skills/SKILL.md b/.agents/skills/writing-great-skills/SKILL.md deleted file mode 100644 index 61abad4..0000000 --- a/.agents/skills/writing-great-skills/SKILL.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -name: writing-great-skills -description: Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable. -disable-model-invocation: true ---- - -A skill exists to wrangle determinism out of a stochastic system. **Predictability** — the agent taking the same _process_ every run, not producing the same output — is the root virtue; every lever below serves it. - -**Bold terms** are defined in [`GLOSSARY.md`](GLOSSARY.md); look them up there for the full meaning. - -## Invocation - -Two choices, trading different costs: - -- A **model-invoked** skill keeps a **description**, so the agent can fire it autonomously _and_ other skills can reach it (you can still type its name too). It contributes to **context load** — the description sits in the window every turn. Mechanics: omit `disable-model-invocation`, and write a model-facing description with rich trigger phrasing ("Use when the user wants…, mentions…"). -- A **user-invoked** skill strips the description from the agent's reach: only you, typing its name, can invoke it — and no other skill can. Zero context load, but it spends **cognitive load**: _you_ are the index that must remember it exists. Mechanics: set `disable-model-invocation: true`; the `description` becomes human-facing — a one-line summary, trigger lists stripped. - -Pick model-invocation only when the agent must reach the skill on its own, or another skill must. If it only ever fires by hand, make it user-invoked and pay no context load. - -When user-invoked skills multiply past what you can remember, that piled-up cognitive load is cured by a **router skill**: one user-invoked skill that names the others and when to reach for each. - -## Writing the description - -A model-invoked **description** does two jobs — state what the skill is, and list the **branches** that should trigger it. Every word increases **context load**, so a description earns even harder pruning than the body: - -- **Front-load the skill's leading word** — the description is where it does its invocation work. -- **One trigger per branch.** Synonyms that rename a single branch are **duplication** — "build features using TDD … asks for test-first development" is one branch written twice. Collapse them; keep only genuinely distinct branches. -- **Cut identity that's already in the body.** Keep the description to triggers, plus any "when another skill needs…" reach clause. - -## Information hierarchy - -A skill is built from two content types — **steps** and **reference** — that mix freely: a skill can be all steps, all reference, or both. The core decision is which to use and where each sits on the **information hierarchy**, a ladder ranked by how immediately the agent needs the material: - -1. **In-skill step** — an ordered action in `SKILL.md`, the primary tier: what the agent does, in order. Each step ends on a **completion criterion**, the condition that tells the agent the work is done. Make it _checkable_ (can the agent tell done from not-done?) and, where it matters, _exhaustive_ ("every modified model accounted for", not "produce a change list") — a vague criterion invites **premature completion**. -2. **In-skill reference** — a definition, rule, or fact in `SKILL.md`, consulted on demand. Often a legitimately flat peer-set (every rule of a review on one rung) — a fine arrangement, not a smell. _This skill is all reference._ -3. **External reference** — reference pushed out of `SKILL.md` into a separate file, reached by a **context pointer**, loaded only when the pointer fires. (Spans _disclosed_ reference — a sibling file like `GLOSSARY.md`, still part of the skill — through fully **external reference** that lives outside the skill system and any skill can point at.) - -A demanding completion criterion drives thorough **legwork** — the digging the agent does within the work — whether the skill has steps or not, since "every rule applied" binds flat reference just as "every step done" binds a sequence. - -Push too little down and the top bloats; push too much and you hide material the agent actually needs. That tension is the whole decision. - -**Progressive disclosure** is the move down the ladder — out of `SKILL.md` into a linked file — so the top stays legible. Mechanics: a linked `.md` file in the skill folder, named for what it holds (this skill discloses its full definitions to `GLOSSARY.md`). Some skills are used in more than one way, and each distinct way is a **branch** — different runs taking different paths through the skill. Branching is the cleanest disclosure test: inline what every branch needs, and push behind a pointer what only some branches reach. A **context pointer**'s _wording_, not its target, decides when and how reliably the agent reaches the material. - -Where the ladder decides _how far down_ a piece sits, **co-location** decides _what sits beside it_ once there: keep a concept's definition, rules, and caveats under one heading rather than scattered, so reading one part brings its neighbours with it. - -## When to split - -**Granularity** is how finely you divide skills, and each cut spends one of the two loads, so split only when the cut earns it. Two cuts: - -- **By invocation** — split off a **model-invoked** skill when you have a distinct **leading word** that should trigger it on its own, or another skill must reach it. You pay **context load** for the new always-loaded **description**, so that independent reach has to be worth it. -- **By sequence** — split a run of **steps** when the steps still ahead (a step's **post-completion steps**) tempt the agent to rush the one in front of it (**premature completion**). Keeping them out of view encourages the agent to do more **legwork** on the current task. - -## Pruning - -Keep each meaning in a **single source of truth**: one authoritative place, so changing the behaviour is a one-place edit. - -Check every line for **relevance**: does it still bear on what the skill does? - -Then hunt **no-ops** sentence by sentence, not just line by line: run the no-op test on each sentence in isolation, and when one fails, delete the whole sentence rather than trim words from it. Be aggressive — most prose that fails should go, not be rewritten. - -## Leading words - -A **leading word** is a compact concept already living in the model's pretraining that the agent thinks with while running the skill (e.g. _lesson_, _fog of war_, _tracer bullets_). Repeated throughout the text (though not necessarily - a strong leading word might only be needed once), it accumulates a distributed definition and anchors a whole region of behaviour in the fewest tokens, by recruiting priors the model already holds. - -It serves predictability twice. In the body it anchors _execution_: the agent reaches for the same behaviour every time the word appears. In the description it anchors _invocation_: when the same word lives in your prompts, docs, and code, the agent links that shared language to the skill and fires it more reliably. - -Hunt for opportunities to refactor skills to use leading words. A triad spelled out at three sites (**duplication**), a description spending a sentence to gesture at one idea — each is a passage begging to **collapse** into a single token. Examples include: - -- "fast, deterministic, low-overhead" -> _tight_ — one quality restated across a phase — into a single pretrained word (a _tight_ loop). -- "a loop you believe in" -> _red_ — converts a fuzzy gate into a binary observable state (the loop goes _red_ on the bug, or it doesn't). - -You win twice over: fewer tokens, _and_ a sharper hook for the agent to hang its thinking on. Assume every skill is carrying restatements that leading words retire — go find them. - -## Failure modes - -Use these to diagnose issues the user may be having with the skill. - -- **Premature completion** — ending a step before it's genuinely done, attention slipping to _being done_. Defence, in order: sharpen the completion criterion first (cheap, local); only if it is irreducibly fuzzy _and_ you observe the rush, hide the post-completion steps by splitting (the sequence cut). -- **Duplication** — the same meaning in more than one place. Costs maintenance and tokens, and inflates a meaning's prominence on the ladder past its real rank. -- **Sediment** — stale layers that settle because adding feels safe and removing feels risky. The default fate of any skill without a pruning discipline. -- **Sprawl** — a skill simply too long, even when every line is live and unique. Hurts readability and maintainability and wastes tokens. The cure is the ladder: disclose **reference** behind pointers, and split by **branch** or sequence so each path carries only what it needs. -- **No-op** — a line the model already obeys by default, so you pay load to say nothing. The test: does it change behaviour versus the default? A weak leading word (_be thorough_ when the agent is already thorough-ish) is a no-op; the fix is a stronger word (_relentless_), not a different technique. diff --git a/.claude/skills/codebase-design b/.claude/skills/codebase-design deleted file mode 120000 index 08b466e..0000000 --- a/.claude/skills/codebase-design +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/codebase-design \ No newline at end of file diff --git a/.claude/skills/diagnosing-bugs b/.claude/skills/diagnosing-bugs deleted file mode 120000 index b2134ff..0000000 --- a/.claude/skills/diagnosing-bugs +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/diagnosing-bugs \ No newline at end of file diff --git a/.claude/skills/domain-modeling b/.claude/skills/domain-modeling deleted file mode 120000 index e672a60..0000000 --- a/.claude/skills/domain-modeling +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/domain-modeling \ No newline at end of file diff --git a/.claude/skills/grill-me b/.claude/skills/grill-me deleted file mode 120000 index eea91a8..0000000 --- a/.claude/skills/grill-me +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/grill-me \ No newline at end of file diff --git a/.claude/skills/grill-with-docs b/.claude/skills/grill-with-docs deleted file mode 120000 index f6cbb9c..0000000 --- a/.claude/skills/grill-with-docs +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/grill-with-docs \ No newline at end of file diff --git a/.claude/skills/grilling b/.claude/skills/grilling deleted file mode 120000 index e712452..0000000 --- a/.claude/skills/grilling +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/grilling \ No newline at end of file diff --git a/.claude/skills/handoff b/.claude/skills/handoff deleted file mode 120000 index a34a6b2..0000000 --- a/.claude/skills/handoff +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/handoff \ No newline at end of file diff --git a/.claude/skills/improve-codebase-architecture b/.claude/skills/improve-codebase-architecture deleted file mode 120000 index be3dac9..0000000 --- a/.claude/skills/improve-codebase-architecture +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/improve-codebase-architecture \ No newline at end of file diff --git a/.claude/skills/writing-great-skills b/.claude/skills/writing-great-skills deleted file mode 120000 index 07320a2..0000000 --- a/.claude/skills/writing-great-skills +++ /dev/null @@ -1 +0,0 @@ -../../.agents/skills/writing-great-skills \ No newline at end of file diff --git a/skills-lock.json b/skills-lock.json deleted file mode 100644 index 6040479..0000000 --- a/skills-lock.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "version": 1, - "skills": { - "codebase-design": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/engineering/codebase-design/SKILL.md", - "computedHash": "2426dc4accf1a85dedfb560edb3a877ec8828b7375ea08c970df2b6c900a2a22" - }, - "diagnosing-bugs": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/engineering/diagnosing-bugs/SKILL.md", - "computedHash": "1a993ce9b2aaa653ee441c8d7efb7f27de03493c722be6dfb8137bcb8db1bc72" - }, - "domain-modeling": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/engineering/domain-modeling/SKILL.md", - "computedHash": "67343881f5def98487d56243155716110afbcbf22ec92421c882d532b941cb17" - }, - "grill-me": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/productivity/grill-me/SKILL.md", - "computedHash": "f321507f77702a54af1db66549ec1685fc625390d06c57d7949cdcda8eb1b5c7" - }, - "grill-with-docs": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/engineering/grill-with-docs/SKILL.md", - "computedHash": "e7ef25bbee50cda2eb7b3a8ef541db0a0396dad7d369f7d14fb610671dd1864b" - }, - "grilling": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/productivity/grilling/SKILL.md", - "computedHash": "ef685a6fa0bbe73b05bbd8dc1ec97258191587f07c6aa7dbc9006675ceb8f90f" - }, - "handoff": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/productivity/handoff/SKILL.md", - "computedHash": "5d0f81e38abe6b984e1feaa731927de5291d040982106ac513cf54ec240e00ec" - }, - "improve-codebase-architecture": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/engineering/improve-codebase-architecture/SKILL.md", - "computedHash": "8bf292143ca93b00276a0de0fc5f84f2381f4690c5b0d32e99fa283a072f392f" - }, - "writing-great-skills": { - "source": "mattpocock/skills", - "sourceType": "github", - "skillPath": "skills/productivity/writing-great-skills/SKILL.md", - "computedHash": "dd555ce552f82784c3d2b8d13a8e26a6677a07ddc00032e142dec33bfd5438c6" - } - } -} From 8033f2b701f53de39775e9d652437f3b57cb5776 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 03:56:46 +0000 Subject: [PATCH 057/113] refactor: merge Lattice.lean into BoundedLinearOperators Move the `Top (VonNeumannAlgebra H)` instance and its `coe_top` / `mem_top` lemmas from ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean into Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean, replacing the local import with Mathlib.Analysis.VonNeumannAlgebra.Basic, and drop the now-empty Lattice.lean from the aggregate root. Co-Authored-By: Claude Opus 4.8 (1M context) --- QuantumSystem.lean | 1 - .../BoundedLinearOperators.lean | 29 ++++++++++-- .../Analysis/VonNeumannAlgebra/Lattice.lean | 46 ------------------- 3 files changed, 26 insertions(+), 50 deletions(-) delete mode 100644 QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index b79ebde..6328498 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -68,7 +68,6 @@ public import QuantumSystem.ForMathlib.Analysis.Matrix.Basic public import QuantumSystem.ForMathlib.Analysis.Matrix.Hermitian public import QuantumSystem.ForMathlib.Analysis.Matrix.Order public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant -public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Lattice public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PosDef diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean index 28e273f..475b89e 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean @@ -1,13 +1,19 @@ module public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification -public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Lattice +public import Mathlib.Analysis.VonNeumannAlgebra.Basic /-! # The algebra of all bounded operators is a type I factor -The algebra `B(H) = H →L[ℂ] H` of *all* bounded operators — realised as the greatest von Neumann -algebra `⊤ : VonNeumannAlgebra H` — is a factor: its centre is the scalars, by the elementary fact +The algebra `B(H) = H →L[ℂ] H` of *all* bounded operators is realised as the greatest von Neumann +algebra `⊤ : VonNeumannAlgebra H`. The von Neumann subalgebras of `B(H)` form a bounded lattice +under inclusion, whose greatest element is `B(H)` itself; Mathlib's `VonNeumannAlgebra H` carries no +`Top` instance, so this file first supplies one (carrier `Set.univ`, double-commutant law from +`Set.subset_centralizer_centralizer` together with `Set.subset_univ`) before developing the factor +theory. + +This `⊤` is a factor: its centre is the scalars, by the elementary fact that an operator commuting with every rank-one operator is scalar. It possesses a minimal projection, namely any rank-one orthogonal projection `|u⟩⟨u|` with `‖u‖ = 1`. Hence `B(H)` is a **type I factor**, and by the abstract structure theorem `IsTypeIFactor.exists_starAlgEquiv` it is @@ -16,6 +22,8 @@ when `H` is infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor** ## Main results +* `Top (VonNeumannAlgebra H)` — the greatest element `⊤`, the algebra of all bounded operators, with + carrier `Set.univ` (`VonNeumannAlgebra.coe_top` / `VonNeumannAlgebra.mem_top`). * `VonNeumannAlgebra.isFactor_boundedLinearOperators` — `B(H)` is a factor. * `VonNeumannAlgebra.exists_isMinimalProjection_boundedLinearOperators` — `B(H)` has a minimal projection (rank-one). @@ -38,6 +46,21 @@ universe u variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] +/-- The **algebra of all bounded operators** `B(H) = H →L[ℂ] H`, as the greatest element `⊤` of the +inclusion order on `VonNeumannAlgebra H`. Its carrier is `Set.univ`; the double-commutant property is +the bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest +set. -/ +noncomputable instance : Top (VonNeumannAlgebra H) where + top := + { toStarSubalgebra := ⊤ + centralizer_centralizer' := + Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } + +@[simp] lemma coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl + +/-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ +@[simp] lemma mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x + /-- **`B(H)` is a factor.** The centre of the full algebra is trivial: an operator lying in the commutant of `⊤` commutes with every operator, in particular with every rank-one operator, hence is a scalar (`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean deleted file mode 100644 index c5a4779..0000000 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Lattice.lean +++ /dev/null @@ -1,46 +0,0 @@ -module - -public import Mathlib.Analysis.VonNeumannAlgebra.Basic - -/-! -# The greatest von Neumann algebra: the algebra of all bounded operators - -The von Neumann subalgebras of `B(H) = H →L[ℂ] H` form a bounded lattice under inclusion, whose -greatest element is `B(H)` itself — the algebra of *all* bounded linear operators (the operator- -algebra literature's name for it; "top element" is the order-theoretic name for the same object). -Mathlib's `VonNeumannAlgebra H` carries only a `PartialOrder` (via `SetLike`) and no `Top` instance, -so `(⊤ : VonNeumannAlgebra H)` does not yet elaborate. This file supplies that `Top` instance: the -carrier is all of `H →L[ℂ] H`, and the double-commutant law holds because the bicommutant of the -whole set is itself (`Set.subset_centralizer_centralizer` together with `Set.subset_univ`). - -This is the natural home for further lattice structure on `VonNeumannAlgebra H` (meets as -intersections, joins as generated algebras) should it be added; only the top element is needed here. - -## Main declarations - -* `Top (VonNeumannAlgebra H)` — the greatest element `⊤`, the algebra of all bounded operators. -* `VonNeumannAlgebra.coe_top` / `VonNeumannAlgebra.mem_top` — its carrier is everything. --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- The **algebra of all bounded operators** `B(H) = H →L[ℂ] H`, as the greatest element `⊤` of the -inclusion order on `VonNeumannAlgebra H`. Its carrier is `Set.univ`; the double-commutant property is -the bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest -set. -/ -noncomputable instance : Top (VonNeumannAlgebra H) where - top := - { toStarSubalgebra := ⊤ - centralizer_centralizer' := - Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } - -@[simp] lemma coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl - -/-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ -@[simp] lemma mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x - -end VonNeumannAlgebra From c603918ff081bd37aa65aa4ba6dbf7a5f6682579 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 03:58:05 +0000 Subject: [PATCH 058/113] docs: reword grill/ingest skill descriptions Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/grill-formalization/SKILL.md | 4 ++-- .claude/skills/ingest-paper/SKILL.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude/skills/grill-formalization/SKILL.md b/.claude/skills/grill-formalization/SKILL.md index 373a25e..1f47f20 100644 --- a/.claude/skills/grill-formalization/SKILL.md +++ b/.claude/skills/grill-formalization/SKILL.md @@ -8,8 +8,8 @@ disable-model-invocation: true Interview the user relentlessly about a formalization plan until every decision that would become permanent sediment in the Lean development is settled — -*before* any tactic is typed. This is `grilling` aimed at one target: the plan to -formalize an ingested paper. +*before* any tactic is typed. This is a relentless interview aimed at one target: +the plan to formalize an ingested paper. Run this after `ingest-paper` has left a navigable `references//INDEX.md`. Read that substrate and `AGENTS.md` first; every recommendation you make is diff --git a/.claude/skills/ingest-paper/SKILL.md b/.claude/skills/ingest-paper/SKILL.md index 11d5a15..d90321e 100644 --- a/.claude/skills/ingest-paper/SKILL.md +++ b/.claude/skills/ingest-paper/SKILL.md @@ -1,6 +1,6 @@ --- name: ingest-paper -description: Convert a paper or lecture-note PDF into agent-navigable Markdown under references//, as the groundwork for grilling its formalization plan. +description: Convert a paper or lecture-note PDF into agent-navigable Markdown under references//, as the groundwork for interrogating its formalization plan. disable-model-invocation: true --- From 15a2df1383885e05cebd8fa5655418a2d3cb6cd5 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 04:21:19 +0000 Subject: [PATCH 059/113] refactor: move type I predicates and structure theorem into TypeI Co-Authored-By: Claude Fable 5 --- .../BoundedLinearOperators.lean | 1 + .../Algebra/VonNeumannAlgebra/Factor.lean | 42 --------- .../TensorIdentification.lean | 25 ----- .../Algebra/VonNeumannAlgebra/TypeI.lean | 92 +++++++++++++++++++ 4 files changed, 93 insertions(+), 67 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean index 475b89e..184f9db 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification +public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI public import Mathlib.Analysis.VonNeumannAlgebra.Basic /-! diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean index 98f955a..d138082 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean @@ -108,48 +108,6 @@ lemma IsMinimalProjection.isAbelianProjection {N : VonNeumannAlgebra H} {e : H obtain ⟨d, hd⟩ := he.2.2.2 b hbN rw [hc, hd, smul_mul_smul_comm, smul_mul_smul_comm, mul_comm c d] -/-- A **type I factor**: a factor possessing a minimal projection. This is the mathematically -conventional, intrinsic definition; the spatial decomposition `N ≅ B(H₁) ⊗̄ 1` is then a theorem, -not part of the definition. The equivalence with the general abelian-projection definition -`IsTypeI` is `isTypeIFactor_iff_isFactor_and_isTypeI`. -/ -def IsTypeIFactor (N : VonNeumannAlgebra H) : Prop := - IsFactor N ∧ ∃ e : H →L[ℂ] H, IsMinimalProjection N e - -/-- A **type I_∞ factor**: a type I factor carrying an infinite sequence of pairwise orthogonal -minimal projections. This is the intrinsic form of *infinite multiplicity*: through the structure -theorem `N ≃⋆ₐ B(K)` the minimal projections are the rank-one projections, and an infinite -orthogonal family of them exists exactly when `K` is infinite-dimensional — a type `I_n` factor -`B(ℂⁿ)` has at most `n` pairwise orthogonal nonzero projections. As with `IsTypeIFactor`, the -spatial identification with an infinite-dimensional `B(K)` is then a theorem, not part of the -definition. -/ -def IsTypeIInfinite (N : VonNeumannAlgebra H) : Prop := - IsTypeIFactor N ∧ - ∃ e : ℕ → (H →L[ℂ] H), - (∀ n, IsMinimalProjection N (e n)) ∧ - (∀ m n, m ≠ n → e m * e n = 0) - -/-- An orthogonal sequence of minimal projections is injective. -/ -lemma injective_of_isMinimalProjection_orthogonal {N : VonNeumannAlgebra H} - {e : ℕ → (H →L[ℂ] H)} (hmin : ∀ n, IsMinimalProjection N (e n)) - (horth : ∀ m n, m ≠ n → e m * e n = 0) : Function.Injective e := by - intro m n hmn - by_contra hne - have h0 := horth m n hne - rw [hmn, (hmin n).1.isIdempotentElem] at h0 - exact (hmin n).2.2.1 h0 - -/-- The witnessing minimal projections of a type I_∞ factor may be chosen injectively. -/ -lemma IsTypeIInfinite.exists_injective {N : VonNeumannAlgebra H} (hN : IsTypeIInfinite N) : - ∃ e : ℕ → (H →L[ℂ] H), Function.Injective e ∧ - (∀ n, IsMinimalProjection N (e n)) ∧ - (∀ m n, m ≠ n → e m * e n = 0) := by - obtain ⟨-, e, hmin, horth⟩ := hN - exact ⟨e, injective_of_isMinimalProjection_orthogonal hmin horth, hmin, horth⟩ - -/-- A type I_∞ factor is in particular a type I factor. -/ -lemma IsTypeIInfinite.isTypeIFactor {N : VonNeumannAlgebra H} (hN : IsTypeIInfinite N) : - IsTypeIFactor N := hN.1 - /-- **Murray–von Neumann equivalence** of projections inside `N`: there is a partial isometry `v ∈ N` with source projection `v⋆v = p` and range projection `vv⋆ = q`. -/ def MvNEquiv (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean index dc92060..6e8edf2 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean @@ -383,29 +383,4 @@ theorem IsFactor.exists_split_tensorDecomposition {N : VonNeumannAlgebra H} hF.conj_spatialEquiv_le_vnTensorLeft he htop h₁, hF.conj_spatialEquiv_le_vnTensorRight he htop h₂⟩ -universe u - -/-- **Type I factor abstract structure theorem.** A type I factor `N` (a factor with a minimal -projection, acting on a nonzero Hilbert space) is `⋆`-isomorphic to the algebra `B(K)` of all -bounded operators on *some* complex Hilbert space `K`. This is the model-independent form of the -classification of type I factors: `B(K)` for `K = ℓ²(F)` is exactly the type `I_{|F|}` factor, and -`K = H` recovers the full algebra `B(H)` as the type `I` factor `⊤`. The spatial content — that the -isomorphism is implemented by a unitary and that `K` is the multiplicity space of the minimal -projection — is `IsFactor.exists_spatial_tensorDecomposition`; here it is packaged as an abstract -`⋆`-isomorphism, hiding the specific model `K = ℓ²(F)` behind an existential. -/ -theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] - [InnerProductSpace ℂ H] [CompleteSpace H] {N : VonNeumannAlgebra H} - (hN : IsTypeIFactor N) : - ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), - Nonempty (N ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by - obtain ⟨hFactor, e, he⟩ := hN - obtain ⟨F, U, hU, -⟩ := hFactor.exists_spatial_tensorDecomposition he - haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range - haveI : Nontrivial (LinearMap.range (e : H →ₗ[ℂ] H)) := by - rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] - exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective - (h.trans ContinuousLinearMap.coe_zero.symm)) - exact ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, - ⟨(conjEquiv U N).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ - end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean index 2f2ec26..4b1fb50 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison +public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant public import Mathlib.Analysis.InnerProductSpace.Projection.Basic public import Mathlib.Analysis.InnerProductSpace.StarOrder @@ -22,10 +23,18 @@ continuous functional calculus inside the norm-closed corner subalgebra) yield a dichotomy, and a Dedekind-cut argument on `{c : ℝ | 0 ≤ x - c • p}` pins each self-adjoint corner element to a real multiple of `p`. +This file is also the home of the factor-level type I predicates `IsTypeIFactor` and +`IsTypeIInfinite`, and of the abstract structure theorem `IsTypeIFactor.exists_starAlgEquiv` +identifying a type I factor with `B(K)` for some Hilbert space `K` (whose spatial content lives in +`Algebra.VonNeumannAlgebra.TensorIdentification`). + ## Main definitions * `VonNeumannAlgebra.IsTypeI N` — every nonzero central projection of `N` dominates a nonzero abelian projection. +* `VonNeumannAlgebra.IsTypeIFactor N` — a factor possessing a minimal projection. +* `VonNeumannAlgebra.IsTypeIInfinite N` — a type I factor carrying an infinite orthogonal family + of minimal projections (infinite multiplicity). * `VonNeumannAlgebra.cornerNonUnitalStarSubalgebra N hp` — the norm-closed corner `{y ∈ N | p y = y = y p}`. @@ -41,6 +50,10 @@ corner element to a real multiple of `p`. it has a minimal projection. * `VonNeumannAlgebra.isTypeIFactor_iff_isFactor_and_isTypeI` — `IsTypeIFactor N ↔ IsFactor N ∧ IsTypeI N`. +* `VonNeumannAlgebra.IsTypeIInfinite.exists_injective` — the witnessing minimal projections of a + type I_∞ factor may be chosen injectively. +* `VonNeumannAlgebra.IsTypeIFactor.exists_starAlgEquiv` — a type I factor is `⋆`-isomorphic to + `B(K)` for some complex Hilbert space `K`. -/ @[expose] public section @@ -56,6 +69,13 @@ def IsTypeI (N : VonNeumannAlgebra H) : Prop := ∀ z : H →L[ℂ] H, IsCentralProjection N z → z ≠ 0 → ∃ p : H →L[ℂ] H, IsAbelianProjection N p ∧ p ≠ 0 ∧ z * p = p +/-- A **type I factor**: a factor possessing a minimal projection. This is the mathematically +conventional, intrinsic definition; the spatial decomposition `N ≅ B(H₁) ⊗̄ 1` is then a theorem, +not part of the definition. The equivalence with the general abelian-projection definition +`IsTypeI` is `isTypeIFactor_iff_isFactor_and_isTypeI`. -/ +def IsTypeIFactor (N : VonNeumannAlgebra H) : Prop := + IsFactor N ∧ ∃ e : H →L[ℂ] H, IsMinimalProjection N e + /-- A factor with a minimal projection is type I: the only nonzero central projection of a factor is `1` (`central_projection_eq`), and it dominates the minimal projection, which is abelian and nonzero. -/ @@ -569,4 +589,76 @@ theorem isTypeIFactor_iff_isFactor_and_isTypeI [Nontrivial H] {N : VonNeumannAlg · rintro ⟨hf, ht⟩ exact ⟨hf, hf.isTypeI_iff_exists_isMinimalProjection.mp ht⟩ +/-! ### Type I_∞ factors + +A **type I_∞ factor** is a type I factor of infinite multiplicity, recorded intrinsically as the +existence of an infinite orthogonal family of minimal projections. -/ + +/-- A **type I_∞ factor**: a type I factor carrying an infinite sequence of pairwise orthogonal +minimal projections. This is the intrinsic form of *infinite multiplicity*: through the structure +theorem `N ≃⋆ₐ B(K)` the minimal projections are the rank-one projections, and an infinite +orthogonal family of them exists exactly when `K` is infinite-dimensional — a type `I_n` factor +`B(ℂⁿ)` has at most `n` pairwise orthogonal nonzero projections. As with `IsTypeIFactor`, the +spatial identification with an infinite-dimensional `B(K)` is then a theorem, not part of the +definition. -/ +def IsTypeIInfinite (N : VonNeumannAlgebra H) : Prop := + IsTypeIFactor N ∧ + ∃ e : ℕ → (H →L[ℂ] H), + (∀ n, IsMinimalProjection N (e n)) ∧ + (∀ m n, m ≠ n → e m * e n = 0) + +/-- An orthogonal sequence of minimal projections is injective. -/ +lemma injective_of_isMinimalProjection_orthogonal {N : VonNeumannAlgebra H} + {e : ℕ → (H →L[ℂ] H)} (hmin : ∀ n, IsMinimalProjection N (e n)) + (horth : ∀ m n, m ≠ n → e m * e n = 0) : Function.Injective e := by + intro m n hmn + by_contra hne + have h0 := horth m n hne + rw [hmn, (hmin n).1.isIdempotentElem] at h0 + exact (hmin n).2.2.1 h0 + +/-- The witnessing minimal projections of a type I_∞ factor may be chosen injectively. -/ +lemma IsTypeIInfinite.exists_injective {N : VonNeumannAlgebra H} (hN : IsTypeIInfinite N) : + ∃ e : ℕ → (H →L[ℂ] H), Function.Injective e ∧ + (∀ n, IsMinimalProjection N (e n)) ∧ + (∀ m n, m ≠ n → e m * e n = 0) := by + obtain ⟨-, e, hmin, horth⟩ := hN + exact ⟨e, injective_of_isMinimalProjection_orthogonal hmin horth, hmin, horth⟩ + +/-- A type I_∞ factor is in particular a type I factor. -/ +lemma IsTypeIInfinite.isTypeIFactor {N : VonNeumannAlgebra H} (hN : IsTypeIInfinite N) : + IsTypeIFactor N := hN.1 + +/-! ### Abstract structure theorem + +A type I factor is `⋆`-isomorphic to `B(K)` for some Hilbert space `K`. The spatial content — the +implementing unitary and the multiplicity model `K = ℓ²(F)` — is +`IsFactor.exists_spatial_tensorDecomposition` in `Algebra.VonNeumannAlgebra.TensorIdentification`; +here it is packaged as an abstract `⋆`-isomorphism. -/ + +universe u + +/-- **Type I factor abstract structure theorem.** A type I factor `N` (a factor with a minimal +projection, acting on a nonzero Hilbert space) is `⋆`-isomorphic to the algebra `B(K)` of all +bounded operators on *some* complex Hilbert space `K`. This is the model-independent form of the +classification of type I factors: `B(K)` for `K = ℓ²(F)` is exactly the type `I_{|F|}` factor, and +`K = H` recovers the full algebra `B(H)` as the type `I` factor `⊤`. The spatial content — that the +isomorphism is implemented by a unitary and that `K` is the multiplicity space of the minimal +projection — is `IsFactor.exists_spatial_tensorDecomposition`; here it is packaged as an abstract +`⋆`-isomorphism, hiding the specific model `K = ℓ²(F)` behind an existential. -/ +theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] {N : VonNeumannAlgebra H} + (hN : IsTypeIFactor N) : + ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), + Nonempty (N ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by + obtain ⟨hFactor, e, he⟩ := hN + obtain ⟨F, U, hU, -⟩ := hFactor.exists_spatial_tensorDecomposition he + haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range + haveI : Nontrivial (LinearMap.range (e : H →ₗ[ℂ] H)) := by + rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] + exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective + (h.trans ContinuousLinearMap.coe_zero.symm)) + exact ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, + ⟨(conjEquiv U N).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ + end VonNeumannAlgebra From 22f179229a58fcab0b316bfc7096f7f1a6828543 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 04:30:59 +0000 Subject: [PATCH 060/113] refactor: consolidate VonNeumannAlgebra modules Merge the eleven files under Algebra/VonNeumannAlgebra into five, grouped by mathematical theme (Takesaki IV: tensor products, V: type classification): - Basic: Factor + CentralProjection + Comparison, plus the Top instance moved out of BoundedLinearOperators - SpatialDecomposition: CoveringFamily + MatrixUnits + SpatialDecomposition (structure-theorem ingredients) - StructureTheorem: GeneratedByMatrixUnits + TensorIdentification (generation theorem and spatial identification) - TypeI: TypeI + BoundedLinearOperators (abstract theory and the fundamental example B(H)) - TensorFactor: unchanged, kept separate for split-property use Co-Authored-By: Claude Fable 5 --- QuantumSystem.lean | 10 +- .../Algebra/VonNeumannAlgebra/Basic.lean | 502 ++++++++++++++++++ .../BoundedLinearOperators.lean | 184 ------- .../VonNeumannAlgebra/CentralProjection.lean | 144 ----- .../Algebra/VonNeumannAlgebra/Comparison.lean | 224 -------- .../VonNeumannAlgebra/CoveringFamily.lean | 205 ------- .../Algebra/VonNeumannAlgebra/Factor.lean | 157 ------ .../GeneratedByMatrixUnits.lean | 209 -------- .../VonNeumannAlgebra/MatrixUnits.lean | 149 ------ .../SpatialDecomposition.lean | 355 ++++++++++++- ...ntification.lean => StructureTheorem.lean} | 210 +++++++- .../VonNeumannAlgebra/TensorFactor.lean | 2 +- .../Algebra/VonNeumannAlgebra/TypeI.lean | 150 +++++- 13 files changed, 1194 insertions(+), 1307 deletions(-) create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean delete mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean rename QuantumSystem/Algebra/VonNeumannAlgebra/{TensorIdentification.lean => StructureTheorem.lean} (65%) diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 6328498..5c94abf 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -22,16 +22,10 @@ public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra -public import QuantumSystem.Algebra.VonNeumannAlgebra.BoundedLinearOperators -public import QuantumSystem.Algebra.VonNeumannAlgebra.CentralProjection -public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison -public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily -public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor -public import QuantumSystem.Algebra.VonNeumannAlgebra.GeneratedByMatrixUnits -public import QuantumSystem.Algebra.VonNeumannAlgebra.MatrixUnits +public import QuantumSystem.Algebra.VonNeumannAlgebra.Basic public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition +public import QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor -public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI public import QuantumSystem.Analysis.CFC.Diagonal public import QuantumSystem.Analysis.Entropy.KroneckerProduct diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean new file mode 100644 index 0000000..863d65e --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean @@ -0,0 +1,502 @@ +module + +public import Mathlib.Analysis.VonNeumannAlgebra.Basic +public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry + +/-! +# Basic theory of von Neumann factors and the comparison of projections + +This file sets up the basic vocabulary of the comparison theory of projections in a von Neumann +algebra, the foundation of the type classification (and, downstream, of the type I factor +structure theorem). It also supplies the greatest element `⊤ : VonNeumannAlgebra H` — the full +algebra `B(H)` — which Mathlib's `VonNeumannAlgebra H` does not provide. + +The file is organised in three parts: + +1. **Factors, minimal projections and Murray–von Neumann equivalence** — the basic definitions + `IsFactor`, `IsMinimalProjection`, `IsAbelianProjection` and the equivalence relation + `p ∼[N] q`. +2. **Central projections** — projections in the centre `N ∩ N'`; in a factor these are trivial, + the seed of the central-support lemma `IsFactor.exists_mul_ne`. +3. **Comparison of projections** — the calculus of partial isometries, the subordination relation + `p ≼[N] q`, and the comparison theorem for minimal projections + (`IsMinimalProjection.mvNSub_of_isFactor`). + +## Main definitions + +* `Top (VonNeumannAlgebra H)` — the greatest element `⊤`, the algebra of all bounded operators, + with carrier `Set.univ` (`VonNeumannAlgebra.coe_top` / `VonNeumannAlgebra.mem_top`). +* `VonNeumannAlgebra.IsFactor N` — `N` has trivial centre: every element of `N ∩ N'` is a scalar. +* `VonNeumannAlgebra.IsMinimalProjection N e` — `e` is a nonzero star projection in `N` with + trivial corner `e N e = ℂ e`. This implies the order-theoretic minimality (no proper nonzero + subprojection in `N`, expressed algebraically as: any projection `f ∈ N` with `e * f = f`, i.e. + the Loewner relation `f ≤ e`, is `0` or `e`), recorded as + `IsMinimalProjection.no_proper_subprojection`. +* `VonNeumannAlgebra.IsAbelianProjection N p` — `p` is a star projection in `N` with commutative + corner `p N p`. +* `VonNeumannAlgebra.MvNEquiv N p q` — `p` and `q` are Murray–von Neumann equivalent inside `N`: + there is a partial isometry `v ∈ N` with source `v⋆v = p` and range `vv⋆ = q`. Written `p ∼[N] q`. +* `VonNeumannAlgebra.IsCentralProjection N e` — `e` is a projection in `N ∩ N'`. +* `VonNeumannAlgebra.MvNSub N p q` — `p ≼[N] q`: `p` is Murray–von Neumann equivalent to a + subprojection of `q`. + +## Main results + +* `VonNeumannAlgebra.MvNEquiv.refl` / `symm` / `trans` — Murray–von Neumann equivalence is an + equivalence relation on the projections of `N`. +* `VonNeumannAlgebra.IsFactor.central_projection_eq` — in a factor every central projection is + `0` or `1`. +* `VonNeumannAlgebra.isStarProjection_mem_commutant_iff` — a star projection lies in the commutant + `N'` exactly when its range is invariant under every element of `N` (the projection–reducing + subspace bridge used to build central supports). +* `VonNeumannAlgebra.IsFactor.exists_mul_ne` — the central-support lemma: in a factor, a nonzero + `q` meets the `N`-orbit of any nonzero `e ∈ N`. +* `VonNeumannAlgebra.MvNSub.refl` / `MvNSub.trans` — subordination is a preorder on projections. +* `VonNeumannAlgebra.mvNSub_of_posCorner` — the scaling step of the comparison theorem: a positive + scalar corner `(q a e)⋆(q a e) = c • e`, `c > 0`, yields `e ≼[N] q`. +* `VonNeumannAlgebra.IsMinimalProjection.mvNSub_of_isFactor` — the comparison theorem for minimal + projections: in a factor, a minimal projection is subordinate to every nonzero projection. + +The full comparison theorem (any two projections in a factor are comparable) requires central +supports and polar decomposition for general projections and is not developed here; the +minimal-projection case above is the form the type I structure theorem needs. + +## Notation + +The symbols of the operator-algebra literature live in the opt-in `VonNeumannAlgebra` scope; +activate them with `open scoped VonNeumannAlgebra`. + +| Symbol | Expansion | How to activate | +|---|---|---| +| `p ∼[N] q` | `VonNeumannAlgebra.MvNEquiv N p q` | `open scoped VonNeumannAlgebra` | +| `p ≼[N] q` | `VonNeumannAlgebra.MvNSub N p q` | `open scoped VonNeumannAlgebra` | +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-! ### The full algebra `B(H)` as the greatest von Neumann algebra -/ + +/-- The **algebra of all bounded operators** `B(H) = H →L[ℂ] H`, as the greatest element `⊤` of the +inclusion order on `VonNeumannAlgebra H`. Its carrier is `Set.univ`; the double-commutant property is +the bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest +set. Mathlib's `VonNeumannAlgebra H` carries no `Top` instance, so this file supplies one. -/ +noncomputable instance : Top (VonNeumannAlgebra H) where + top := + { toStarSubalgebra := ⊤ + centralizer_centralizer' := + Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } + +@[simp] lemma coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl + +/-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ +@[simp] lemma mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x + +/-! ### Factors, minimal projections and Murray–von Neumann equivalence -/ + +/-- A von Neumann algebra is closed under scalar multiplication. -/ +lemma smul_mem {N : VonNeumannAlgebra H} (c : ℂ) {x : H →L[ℂ] H} (hx : x ∈ N) : c • x ∈ N := by + rw [Algebra.smul_def] + exact mul_mem (algebraMap_mem N.toStarSubalgebra c) hx + +/-- A von Neumann algebra `N` is a **factor** when its centre is trivial: every operator lying in +both `N` and its commutant is a scalar multiple of the identity. -/ +def IsFactor (N : VonNeumannAlgebra H) : Prop := + ∀ x : H →L[ℂ] H, x ∈ N → x ∈ N.commutant → ∃ c : ℂ, x = c • 1 + +/-- A **minimal projection** of `N`: a nonzero star projection `e ∈ N` whose corner is trivial, +`e N e = ℂ e`. This is the conventional operator-algebraic definition (Takesaki, Kadison–Ringrose); +it implies minimality in the order sense (no proper nonzero subprojection), recorded as +`IsMinimalProjection.no_proper_subprojection`. The corner formulation is the one that +supports comparison theory without invoking Borel functional calculus. -/ +def IsMinimalProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := + IsStarProjection e ∧ e ∈ N ∧ e ≠ 0 ∧ ∀ a ∈ N, ∃ c : ℂ, e * a * e = c • e + +/-- A von Neumann algebra with a minimal projection acts on a nonzero space: the minimal +projection is nonzero, so it sends some vector to a nonzero vector, witnessing `Nontrivial H`. -/ +lemma IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) : Nontrivial H := + let ⟨x, hx⟩ := ContinuousLinearMap.exists_ne_zero he.2.2.1 + ⟨⟨e x, 0, hx⟩⟩ + +/-- A minimal projection has no proper nonzero subprojection in `N`: if a projection `f ∈ N` +satisfies `f ≤ e` (the Loewner order on projections, equivalently the range inclusion +`ran f ⊆ ran e`, written algebraically as `e * f = f`), then `f = 0` or `f = e`. This recovers the +order-theoretic form of minimality from the corner definition `e N e = ℂ e`. -/ +lemma IsMinimalProjection.no_proper_subprojection {N : VonNeumannAlgebra H} + {e : H →L[ℂ] H} (he : IsMinimalProjection N e) + {f : H →L[ℂ] H} (hf : IsStarProjection f) (hfN : f ∈ N) (hsub : e * f = f) : + f = 0 ∨ f = e := by + have hfe : f * e = f := by + have := congrArg star hsub + rwa [star_mul, he.1.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this + have hefe : e * f * e = f := by rw [hsub, hfe] + obtain ⟨c, hc⟩ := he.2.2.2 f hfN + rw [hefe] at hc + have hidem : f * f = f := hf.isIdempotentElem + rw [hc] at hidem + have h2 : (c • e) * (c • e) = (c * c) • (e : H →L[ℂ] H) := by + rw [smul_mul_smul_comm, he.1.isIdempotentElem] + have hcc : (c * c) • (e : H →L[ℂ] H) = c • e := by rw [← h2, hidem] + have hc2 : c * c = c := smul_left_injective ℂ he.2.2.1 hcc + have h0 : c * (c - 1) = 0 := by rw [mul_sub, mul_one, hc2, sub_self] + rcases mul_eq_zero.mp h0 with h | h + · exact Or.inl (by rw [hc, h, zero_smul]) + · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) + +/-- An **abelian projection** of `N`: a star projection `p ∈ N` whose corner `p N p` is +commutative. Minimal projections are abelian (`IsMinimalProjection.isAbelianProjection`); the +general type I property (`IsTypeI`) is phrased through abelian projections. -/ +def IsAbelianProjection (N : VonNeumannAlgebra H) (p : H →L[ℂ] H) : Prop := + IsStarProjection p ∧ p ∈ N ∧ + ∀ a ∈ N, ∀ b ∈ N, (p * a * p) * (p * b * p) = (p * b * p) * (p * a * p) + +/-- A minimal projection is abelian: its corner `e N e = ℂ e` is one-dimensional, hence +commutative. -/ +lemma IsMinimalProjection.isAbelianProjection {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) : IsAbelianProjection N e := by + refine ⟨he.1, he.2.1, fun a haN b hbN => ?_⟩ + obtain ⟨c, hc⟩ := he.2.2.2 a haN + obtain ⟨d, hd⟩ := he.2.2.2 b hbN + rw [hc, hd, smul_mul_smul_comm, smul_mul_smul_comm, mul_comm c d] + +/-- **Murray–von Neumann equivalence** of projections inside `N`: there is a partial isometry +`v ∈ N` with source projection `v⋆v = p` and range projection `vv⋆ = q`. -/ +def MvNEquiv (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := + ∃ v : H →L[ℂ] H, v ∈ N ∧ IsPartialIsometry v ∧ star v * v = p ∧ v * star v = q + +/-- `p ∼[N] q` denotes Murray–von Neumann equivalence `MvNEquiv N p q` of projections inside `N`. -/ +scoped notation:50 p:51 " ∼[" N "] " q:51 => MvNEquiv N p q + +/-- Murray–von Neumann equivalence is reflexive on projections of `N`. -/ +theorem MvNEquiv.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + (hp : IsStarProjection p) (hpN : p ∈ N) : p ∼[N] p := + ⟨p, hpN, hp.isPartialIsometry, by rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq], + by rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq]⟩ + +/-- Murray–von Neumann equivalence is symmetric. -/ +theorem MvNEquiv.symm {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) : q ∼[N] p := by + obtain ⟨v, hv, hpi, hvp, hvq⟩ := h + exact ⟨star v, star_mem hv, IsPartialIsometry.star hpi, by rw [star_star, hvq], + by rw [star_star, hvp]⟩ + +/-- Murray–von Neumann equivalence is transitive. -/ +theorem MvNEquiv.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} + (hpq : p ∼[N] q) (hqr : q ∼[N] r) : p ∼[N] r := by + obtain ⟨v, hv, hvpi, hvp, hvq⟩ := hpq + obtain ⟨w, hw, hwpi, hwq, hwr⟩ := hqr + have hq : IsStarProjection q := hvq ▸ hvpi.isStarProjection_mul_star_self + refine ⟨w * v, mul_mem hw hv, ?_, ?_, ?_⟩ + · unfold IsPartialIsometry + calc w * v * star (w * v) * (w * v) + = w * (v * star v) * (star w * w) * v := by simp only [star_mul, mul_assoc] + _ = w * q * q * v := by rw [hvq, hwq] + _ = w * q * v := by rw [mul_assoc w q q, hq.isIdempotentElem] + _ = w * (star w * w) * v := by rw [hwq] + _ = w * v := by rw [← mul_assoc w (star w) w, hwpi] + · calc star (w * v) * (w * v) = star v * (star w * w) * v := by simp only [star_mul, mul_assoc] + _ = star v * (v * star v) * v := by rw [hwq, hvq] + _ = (star v * v) * (star v * v) := by simp only [mul_assoc] + _ = star v * v := hvpi.isStarProjection_star_mul_self.isIdempotentElem + _ = p := hvp + · calc (w * v) * star (w * v) = w * (v * star v) * star w := by simp only [star_mul, mul_assoc] + _ = w * (star w * w) * star w := by rw [hvq, ← hwq] + _ = (w * star w) * (w * star w) := by simp only [mul_assoc] + _ = w * star w := hwpi.isStarProjection_mul_star_self.isIdempotentElem + _ = r := hwr + +/-! ### Central projections -/ + +/-- A **central projection** of `N`: a star projection lying in both `N` and its commutant +(equivalently, in the centre `N ∩ N'`). -/ +def IsCentralProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := + IsStarProjection e ∧ e ∈ N ∧ e ∈ N.commutant + +/-- `0` is a central projection. -/ +lemma isCentralProjection_zero (N : VonNeumannAlgebra H) : IsCentralProjection N 0 := + ⟨IsStarProjection.zero _, zero_mem _, zero_mem _⟩ + +/-- `1` is a central projection. -/ +lemma isCentralProjection_one (N : VonNeumannAlgebra H) : IsCentralProjection N 1 := + ⟨IsStarProjection.one _, one_mem _, one_mem _⟩ + +/-- In a factor, every central projection is trivial: it is `0` or `1`. This is the +projection-level form of the triviality of the centre. -/ +theorem IsFactor.central_projection_eq [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsCentralProjection N e) : + e = 0 ∨ e = 1 := by + obtain ⟨c, hc⟩ := hN e he.2.1 he.2.2 + have hidem : e * e = e := he.1.isIdempotentElem + rw [hc] at hidem + have hcc : (c * c) • (1 : H →L[ℂ] H) = c • 1 := by + rw [← hidem, smul_mul_smul_comm, mul_one] + have hc2 : c * c = c := smul_left_injective ℂ one_ne_zero hcc + have h0 : c * (c - 1) = 0 := by rw [mul_sub, mul_one, hc2, sub_self] + rcases mul_eq_zero.mp h0 with h | h + · exact Or.inl (by rw [hc, h, zero_smul]) + · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) + +/-- A star projection lies in the commutant `N'` exactly when its range is invariant under every +element of `N`. This is the bridge between reducing subspaces and (eventually central) +projections: it follows from the double-commutant characterisation +`VonNeumannAlgebra.IsStarProjection.mem_iff` together with `commutant_commutant`. -/ +theorem isStarProjection_mem_commutant_iff {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsStarProjection e) : + e ∈ N.commutant ↔ ∀ y ∈ N, (e.range) ∈ Module.End.invtSubmodule (y : Module.End ℂ H) := by + rw [IsStarProjection.mem_iff he N.commutant, commutant_commutant] + +/-- **Central support (factor case).** In a factor, a nonzero operator `q` meets the +"`N`-orbit" of any nonzero `e ∈ N`: there is `a ∈ N` with `q a e ≠ 0`. The statement needs no +projection hypothesis on `e` or `q`, only `e ∈ N`, `e ≠ 0` and `q ≠ 0`. The proof takes the +orthogonal projection `P` onto the closed `N`-invariant subspace generated by `e H`; `P` reduces +both `N` and `N'`, so it is central, hence `0` or `1`; since `P` acts as the identity on `e H` +(so `P ≠ 0`, as `e ≠ 0`), `P = 1`, so the generated subspace is the whole space and `q` cannot +annihilate it. This is the geometric input of the comparison theorem. -/ +theorem IsFactor.exists_mul_ne [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) + {e q : H →L[ℂ] H} (heN : e ∈ N) (he0 : e ≠ 0) (hq0 : q ≠ 0) : ∃ a ∈ N, q * a * e ≠ 0 := by + by_contra hcon + have hcon' : ∀ a ∈ N, q * a * e = 0 := fun a haN => by + by_contra h; exact hcon ⟨a, haN, h⟩ + set S : Set H := {y | ∃ a ∈ N, ∃ x, (a : H →L[ℂ] H) (e x) = y} with hS + set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM + set P : H →L[ℂ] H := M.starProjection with hP + have hPproj : IsStarProjection P := isStarProjection_starProjection + have hSsub : S ⊆ M := Submodule.subset_span.trans (Submodule.le_topologicalClosure _) + have hSmem : ∀ (a : H →L[ℂ] H), a ∈ N → ∀ x, (a : H →L[ℂ] H) (e x) ∈ M := + fun a haN x => hSsub ⟨a, haN, x, rfl⟩ + have hinv : ∀ (y : H →L[ℂ] H), (∀ s ∈ S, y s ∈ M) → + P.range ∈ Module.End.invtSubmodule (y : Module.End ℂ H) := by + intro y hyS + have hcomapclosed : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by + rw [Submodule.comap_coe] + exact ((Submodule.span ℂ S).isClosed_topologicalClosure).preimage y.continuous + have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by + apply Submodule.topologicalClosure_minimal (Submodule.span ℂ S) _ hcomapclosed + rw [Submodule.span_le] + intro s hs + simp only [Submodule.comap_coe, Set.mem_preimage, SetLike.mem_coe] + exact hyS s hs + rw [hP, Submodule.range_starProjection]; exact hle + have hPcomm : P ∈ N.commutant := by + rw [isStarProjection_mem_commutant_iff hPproj] + intro y hyN + refine hinv y ?_ + rintro s ⟨a, haN, x, rfl⟩ + rw [show y ((a : H →L[ℂ] H) (e x)) = (y * a) (e x) from rfl] + exact hSmem (y * a) (mul_mem hyN haN) x + have hPN : P ∈ N := by + rw [IsStarProjection.mem_iff hPproj N] + intro y hyN' + refine hinv y ?_ + rintro s ⟨a, haN, x, rfl⟩ + have hay : a * y = y * a := mem_commutant_iff.mp hyN' a haN + have hey : e * y = y * e := mem_commutant_iff.mp hyN' e heN + have heq : y ((a : H →L[ℂ] H) (e x)) = (a : H →L[ℂ] H) (e (y x)) := by + rw [show y ((a : H →L[ℂ] H) (e x)) = (y * a) (e x) from rfl, ← hay] + rw [show (a * y) (e x) = (a : H →L[ℂ] H) (y (e x)) from rfl] + rw [show y (e x) = (y * e) x from rfl, ← hey]; rfl + rw [heq]; exact hSmem a haN (y x) + have hPcentral : IsCentralProjection N P := ⟨hPproj, hPN, hPcomm⟩ + have hP1 : P = 1 := by + rcases hN.central_projection_eq hPcentral with h0 | h1 + · exact absurd (by + ext x + have hpx : P (e x) = e x := by + rw [hP, Submodule.starProjection_eq_self_iff]; exact hSmem 1 (one_mem _) x + rw [h0] at hpx; simpa using hpx.symm : e = 0) he0 + · exact h1 + have hMtop : M = ⊤ := by + have hMr : M = P.range := (Submodule.range_starProjection M).symm + rw [hMr, hP1]; exact Submodule.eq_top_iff'.2 fun y => ⟨y, rfl⟩ + have hqM : M ≤ LinearMap.ker (q : H →ₗ[ℂ] H) := by + apply Submodule.topologicalClosure_minimal (Submodule.span ℂ S) _ q.isClosed_ker + rw [Submodule.span_le] + rintro s ⟨a, haN, x, rfl⟩ + simp only [SetLike.mem_coe, LinearMap.mem_ker, ContinuousLinearMap.coe_coe] + rw [show q ((a : H →L[ℂ] H) (e x)) = (q * a * e) x from rfl, hcon' a haN]; rfl + apply hq0 + ext x + have hx : x ∈ LinearMap.ker (q : H →ₗ[ℂ] H) := hqM (hMtop ▸ Submodule.mem_top) + simpa using hx + +/-! ### Comparison of projections -/ + +/-- The source projection of a Murray–von Neumann equivalence is a star projection. -/ +lemma MvNEquiv.isStarProjection_left {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) : IsStarProjection p := by + obtain ⟨v, _, hpi, hvp, _⟩ := h; exact hvp ▸ hpi.isStarProjection_star_mul_self + +/-- The range projection of a Murray–von Neumann equivalence is a star projection. -/ +lemma MvNEquiv.isStarProjection_right {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) : IsStarProjection q := by + obtain ⟨v, _, hpi, _, hvq⟩ := h; exact hvq ▸ hpi.isStarProjection_mul_star_self + +/-- For projections, the subprojection relation `e * f = f` is left/right symmetric. -/ +lemma isStarProjection_subproj_comm {R : Type*} [Ring R] [StarRing R] {e f : R} + (he : IsStarProjection e) (hf : IsStarProjection f) (h : e * f = f) : f * e = f := by + have := congrArg star h + rwa [star_mul, he.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this + +/-- The source projection of a partial isometry acts as a right identity. -/ +lemma IsPartialIsometry.mul_source {R : Type*} [Monoid R] [StarMul R] {v : R} + (h : IsPartialIsometry v) : v * (star v * v) = v := by rw [← mul_assoc]; exact h + +/-- `p ≼ q` in `N`: `p` is Murray–von Neumann equivalent to a subprojection of `q`. -/ +def MvNSub (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := + ∃ q' : H →L[ℂ] H, q' ∈ N ∧ q * q' = q' ∧ p ∼[N] q' + +/-- `p ≼[N] q` denotes the subordination relation `MvNSub N p q`: `p` is Murray–von Neumann +equivalent to a subprojection of `q` inside `N`. -/ +scoped notation:50 p:51 " ≼[" N "] " q:51 => MvNSub N p q + +/-- Subordination is reflexive on projections of `N`. -/ +lemma MvNSub.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} + (hp : IsStarProjection p) (hpN : p ∈ N) : p ≼[N] p := + ⟨p, hpN, hp.isIdempotentElem, MvNEquiv.refl hp hpN⟩ + +/-- An equivalence `q ∼[N] r'` transports a subprojection `q' ≤ q` to a subprojection of `r'` that +is Murray–von Neumann equivalent to `q'`. -/ +theorem MvNEquiv.exists_subproj_equiv {N : VonNeumannAlgebra H} {q r' q' : H →L[ℂ] H} + (hqr : q ∼[N] r') (hq' : IsStarProjection q') (hq'N : q' ∈ N) (hsub : q * q' = q') : + ∃ r'' : H →L[ℂ] H, IsStarProjection r'' ∧ r'' ∈ N ∧ r' * r'' = r'' ∧ q' ∼[N] r'' := by + obtain ⟨w, hwN, hwpi, hwq, hwr⟩ := hqr + refine ⟨w * q' * star w, ⟨?_, ?_⟩, mul_mem (mul_mem hwN hq'N) (star_mem hwN), ?_, ?_⟩ + · change (w * q' * star w) * (w * q' * star w) = w * q' * star w + simp only [mul_assoc] + rw [← mul_assoc (star w) w (q' * star w), hwq, ← mul_assoc q q' (star w), hsub, + ← mul_assoc q' q' (star w), hq'.isIdempotentElem] + · change star (w * q' * star w) = w * q' * star w + rw [star_mul, star_mul, star_star, hq'.isSelfAdjoint.star_eq, mul_assoc] + · rw [← hwr] + simp only [mul_assoc] + rw [← mul_assoc (star w) w (q' * star w), hwq, ← mul_assoc q q' (star w), hsub] + · refine ⟨w * q', mul_mem hwN hq'N, ?_, ?_, ?_⟩ + · change (w * q') * star (w * q') * (w * q') = w * q' + rw [star_mul, hq'.isSelfAdjoint.star_eq] + simp only [mul_assoc] + rw [← mul_assoc (star w) w q', hwq, hsub, hq'.isIdempotentElem, hq'.isIdempotentElem] + · change star (w * q') * (w * q') = q' + rw [star_mul, hq'.isSelfAdjoint.star_eq, mul_assoc, ← mul_assoc (star w) w q', hwq, hsub, + hq'.isIdempotentElem] + · change (w * q') * star (w * q') = w * q' * star w + rw [star_mul, hq'.isSelfAdjoint.star_eq] + simp only [mul_assoc] + rw [← mul_assoc q' q' (star w), hq'.isIdempotentElem] + +/-- Subordination is transitive: `≼` is a preorder on the projections of `N`. -/ +lemma MvNSub.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} + (hpq : p ≼[N] q) (hqr : q ≼[N] r) : p ≼[N] r := by + obtain ⟨q', hq'N, hqsub, hpq'⟩ := hpq + obtain ⟨r', hr'N, hrsub, hqr'⟩ := hqr + obtain ⟨r'', _, hr''N, hr'sub, hq'r''⟩ := + hqr'.exists_subproj_equiv hpq'.isStarProjection_right hq'N hqsub + refine ⟨r'', hr''N, ?_, hpq'.trans hq'r''⟩ + calc r * r'' = r * (r' * r'') := by rw [hr'sub] + _ = (r * r') * r'' := by rw [mul_assoc] + _ = r' * r'' := by rw [hrsub] + _ = r'' := hr'sub + +/-- **Scaling step of the comparison theorem.** If the positive corner element +`(q a e)⋆ (q a e)` equals a positive scalar multiple `c • e` of `e` (with `c > 0`), then `e` is +subordinate to `q`: the normalised element `(√c)⁻¹ • (q a e)` is a partial isometry with source +`e` and range a subprojection of `q`. The hypotheses isolate the two analytic inputs of the +comparison theorem — the corner being scalar (minimality) and its positivity. -/ +theorem mvNSub_of_posCorner {N : VonNeumannAlgebra H} {e q a : H →L[ℂ] H} + (he : IsStarProjection e) (hq : IsStarProjection q) + (heN : e ∈ N) (hqN : q ∈ N) (haN : a ∈ N) + {c : ℝ} (hc : 0 < c) + (hcorner : star (q * a * e) * (q * a * e) = (c : ℂ) • e) : + e ≼[N] q := by + set γ : ℂ := ((Real.sqrt c)⁻¹ : ℂ) with hγ + set v : H →L[ℂ] H := γ • (q * a * e) with hv + have hvN : v ∈ N := smul_mem γ (mul_mem (mul_mem hqN haN) heN) + have hsrc : star v * v = e := by + rw [hv, star_smul, smul_mul_smul_comm, hcorner, smul_smul] + have hstar : star γ = γ := by rw [hγ, star_inv₀, ← starRingEnd_apply, Complex.conj_ofReal] + rw [hstar, hγ, ← mul_inv, ← Complex.ofReal_mul, Real.mul_self_sqrt hc.le, + inv_mul_cancel₀ (by exact_mod_cast hc.ne'), one_smul] + have hve : v * e = v := by + rw [hv, smul_mul_assoc, mul_assoc (q * a) e e, he.isIdempotentElem] + have hvpi : IsPartialIsometry v := by + unfold IsPartialIsometry + rw [mul_assoc, hsrc, hve] + refine ⟨v * star v, mul_mem hvN (star_mem hvN), ?_, ⟨v, hvN, hvpi, hsrc, rfl⟩⟩ + have hqv : q * v = v := by + rw [hv, mul_smul_comm, ← mul_assoc, ← mul_assoc, hq.isIdempotentElem] + rw [← mul_assoc, hqv] + +/-- **Positivity of the corner scalar.** For a minimal projection `e` and `a ∈ N` with +`q a e ≠ 0`, the corner element `(q a e)⋆ (q a e) = e (a⋆ q a) e` equals a *strictly positive +real* scalar multiple of `e`. (Reality comes from self-adjointness; strict positivity from +evaluating on a nonzero vector of `e H` on which `q a e` does not vanish.) -/ +lemma IsMinimalProjection.posCorner {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) + (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : + ∃ c : ℝ, 0 < c ∧ star (q * a * e) * (q * a * e) = (c : ℂ) • e := by + set x := q * a * e with hx + have hxx : star x * x = e * (star a * q * a) * e := by + rw [hx, star_mul, star_mul, he.1.isSelfAdjoint.star_eq, hq.isSelfAdjoint.star_eq] + rw [mul_assoc, mul_assoc, mul_assoc, ← mul_assoc q q, hq.isIdempotentElem] + simp only [mul_assoc] + obtain ⟨c', hc'⟩ := he.2.2.2 (star a * q * a) (mul_mem (mul_mem (star_mem haN) hqN) haN) + rw [← hxx] at hc' + have hconj : (starRingEnd ℂ) c' = c' := by + have hsa : star (star x * x) = star x * x := by rw [star_mul, star_star] + rw [hc', star_smul, he.1.isSelfAdjoint.star_eq] at hsa + rw [starRingEnd_apply]; exact smul_left_injective ℂ he.2.2.1 hsa + have hxe : x * e = x := by rw [hx, mul_assoc, he.1.isIdempotentElem] + obtain ⟨η, hη⟩ : ∃ η, x η ≠ 0 := by + by_contra h + exact hne (by ext η; exact not_not.mp (not_exists.mp h η)) + set ξ := e η with hξ + have hxξ : x ξ ≠ 0 := by + rw [hξ, ← ContinuousLinearMap.comp_apply, ← ContinuousLinearMap.mul_def, hxe]; exact hη + have heξ : e ξ = ξ := by + rw [hξ, ← ContinuousLinearMap.comp_apply, ← ContinuousLinearMap.mul_def, he.1.isIdempotentElem] + have hξne : ξ ≠ 0 := fun h => hxξ (by rw [h, map_zero]) + have hinner : ‖x ξ‖ ^ 2 = c'.re * ‖ξ‖ ^ 2 := by + have e1 : inner ℂ ((star x * x) ξ) ξ = inner ℂ (x ξ) (x ξ) := by + rw [ContinuousLinearMap.mul_apply, ContinuousLinearMap.star_eq_adjoint, + ContinuousLinearMap.adjoint_inner_left] + have e2 : inner ℂ ((star x * x) ξ) ξ = (starRingEnd ℂ) c' * inner ℂ ξ ξ := by + rw [hc', ContinuousLinearMap.smul_apply, heξ, inner_smul_left] + have e3 : inner ℂ (x ξ) (x ξ) = (starRingEnd ℂ) c' * inner ℂ ξ ξ := e1.symm.trans e2 + have hre := congrArg RCLike.re e3 + rw [inner_self_eq_norm_sq, inner_self_eq_norm_sq_to_K] at hre + simp only [RCLike.mul_re, RCLike.mul_im, RCLike.conj_re, RCLike.conj_im, RCLike.ofReal_re, + RCLike.ofReal_im, pow_two, mul_zero, zero_mul, add_zero, sub_zero] at hre + rw [show RCLike.re c' = c'.re from rfl] at hre + nlinarith [hre] + have hξpos : 0 < ‖ξ‖ ^ 2 := pow_pos (norm_pos_iff.mpr hξne) 2 + have hxξpos : 0 < ‖x ξ‖ ^ 2 := pow_pos (norm_pos_iff.mpr hxξ) 2 + have hcre : c' = (c'.re : ℂ) := (Complex.conj_eq_iff_re.mp hconj).symm + refine ⟨c'.re, by nlinarith [hinner, hξpos, hxξpos], ?_⟩ + rw [hc']; exact congrArg (· • e) hcre + +/-- A minimal projection is subordinate to any projection it "meets": if some `a ∈ N` has +`q a e ≠ 0`, then `e ≼ q`. Combined with central supports (which guarantee `q a e ≠ 0` for every +nonzero `q` in a factor) this yields the comparison theorem `minimal e ≼ q`. -/ +lemma IsMinimalProjection.mvNSub_of_ne {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) + (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : e ≼[N] q := by + obtain ⟨c, hcpos, hcorner⟩ := he.posCorner hq hqN haN hne + exact mvNSub_of_posCorner he.1 hq he.2.1 hqN haN hcpos hcorner + +/-- **Comparison theorem (minimal projection case).** In a factor, a minimal projection `e` is +Murray–von Neumann subordinate to *every* nonzero projection `q`: `e ≼ q`. This combines the +scaling lemma (via `mvNSub_of_ne`) with the central-support input +(`IsFactor.exists_mul_ne`, which supplies an `a ∈ N` with `q a e ≠ 0`). It is the form of +comparison needed to show a maximal orthogonal family of minimal projections exhausts the +identity. -/ +theorem IsMinimalProjection.mvNSub_of_isFactor [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) + {q : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (hq0 : q ≠ 0) : + e ≼[N] q := by + obtain ⟨a, haN, hane⟩ := hN.exists_mul_ne he.2.1 he.2.2.1 hq0 + exact he.mvNSub_of_ne hq hqN haN hane + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean deleted file mode 100644 index 184f9db..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/BoundedLinearOperators.lean +++ /dev/null @@ -1,184 +0,0 @@ -module - -public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification -public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI -public import Mathlib.Analysis.VonNeumannAlgebra.Basic - -/-! -# The algebra of all bounded operators is a type I factor - -The algebra `B(H) = H →L[ℂ] H` of *all* bounded operators is realised as the greatest von Neumann -algebra `⊤ : VonNeumannAlgebra H`. The von Neumann subalgebras of `B(H)` form a bounded lattice -under inclusion, whose greatest element is `B(H)` itself; Mathlib's `VonNeumannAlgebra H` carries no -`Top` instance, so this file first supplies one (carrier `Set.univ`, double-commutant law from -`Set.subset_centralizer_centralizer` together with `Set.subset_univ`) before developing the factor -theory. - -This `⊤` is a factor: its centre is the scalars, by the elementary fact -that an operator commuting with every rank-one operator is scalar. It possesses a minimal -projection, namely any rank-one orthogonal projection `|u⟩⟨u|` with `‖u‖ = 1`. Hence `B(H)` is a -**type I factor**, and by the abstract structure theorem `IsTypeIFactor.exists_starAlgEquiv` it is -`⋆`-isomorphic to `B(K)` for some Hilbert space `K` (which is `ℓ²` of an orthonormal basis of `H`); -when `H` is infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor**. - -## Main results - -* `Top (VonNeumannAlgebra H)` — the greatest element `⊤`, the algebra of all bounded operators, with - carrier `Set.univ` (`VonNeumannAlgebra.coe_top` / `VonNeumannAlgebra.mem_top`). -* `VonNeumannAlgebra.isFactor_boundedLinearOperators` — `B(H)` is a factor. -* `VonNeumannAlgebra.exists_isMinimalProjection_boundedLinearOperators` — `B(H)` has a minimal - projection (rank-one). -* `VonNeumannAlgebra.isTypeIFactor_boundedLinearOperators` — `B(H)` is a type I factor. -* `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(K)` for some - Hilbert space `K`. -* `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, `B(H)` - is a type I_∞ factor, packaged as the intrinsic predicate `IsTypeIInfinite ⊤`. -* `VonNeumannAlgebra.exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators` — for - infinite-dimensional `H`, `B(H) ≃⋆ₐ B(K)` with `K` itself infinite-dimensional. --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -open InnerProductSpace - -universe u - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- The **algebra of all bounded operators** `B(H) = H →L[ℂ] H`, as the greatest element `⊤` of the -inclusion order on `VonNeumannAlgebra H`. Its carrier is `Set.univ`; the double-commutant property is -the bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest -set. -/ -noncomputable instance : Top (VonNeumannAlgebra H) where - top := - { toStarSubalgebra := ⊤ - centralizer_centralizer' := - Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } - -@[simp] lemma coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl - -/-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ -@[simp] lemma mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x - -/-- **`B(H)` is a factor.** The centre of the full algebra is trivial: an operator lying in the -commutant of `⊤` commutes with every operator, in particular with every rank-one operator, hence is -a scalar (`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ -theorem isFactor_boundedLinearOperators : IsFactor (⊤ : VonNeumannAlgebra H) := by - intro x _ hxComm - rw [VonNeumannAlgebra.mem_commutant_iff] at hxComm - refine ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm (fun a b => ?_) - have hg := hxComm (rankOne ℂ a b) (mem_top _) - rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] at hg - exact hg.symm - -/-- **A rank-one projection is minimal in `B(H)`.** For a unit vector `u`, the rank-one orthogonal -projection `|u⟩⟨u|` is a minimal projection of `⊤`: it is a star projection, nonzero, and its corner -is trivial because `|u⟩⟨u| ∘ a ∘ |u⟩⟨u| = ⟪u, a u⟫ • |u⟩⟨u|`. -/ -lemma isMinimalProjection_rankOne_boundedLinearOperators {u : H} (hu : ‖u‖ = 1) : - IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := by - have hu_ne : u ≠ 0 := by rw [← norm_pos_iff, hu]; norm_num - refine ⟨⟨isIdempotentElem_rankOne_self hu, ?_⟩, mem_top _, - rankOne_ne_zero hu_ne hu_ne, fun a _ => ?_⟩ - · rw [isSelfAdjoint_iff, ContinuousLinearMap.star_eq_adjoint, adjoint_rankOne] - · exact ⟨inner ℂ u (a u), by - rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def, - ContinuousLinearMap.comp_assoc, comp_rankOne, rankOne_comp_rankOne]⟩ - -omit [CompleteSpace H] in -/-- A normalised nonzero vector of a nontrivial space, packaged as a unit vector. -/ -private theorem exists_unit_vector [Nontrivial H] : ∃ u : H, ‖u‖ = 1 := by - obtain ⟨v, hv⟩ := exists_ne (0 : H) - exact ⟨(‖v‖⁻¹ : ℂ) • v, by - rw [norm_smul, norm_inv, Complex.norm_real, norm_norm, - inv_mul_cancel₀ (norm_ne_zero_iff.mpr hv)]⟩ - -/-- **`B(H)` has a minimal projection** (a rank-one projection). Needs `H` nonzero. -/ -theorem exists_isMinimalProjection_boundedLinearOperators [Nontrivial H] : - ∃ e : H →L[ℂ] H, IsMinimalProjection (⊤ : VonNeumannAlgebra H) e := - let ⟨u, hu⟩ := exists_unit_vector (H := H) - ⟨rankOne ℂ u u, isMinimalProjection_rankOne_boundedLinearOperators hu⟩ - -/-- **`B(H)` is a type I factor** (for nonzero `H`). -/ -theorem isTypeIFactor_boundedLinearOperators [Nontrivial H] : - IsTypeIFactor (⊤ : VonNeumannAlgebra H) := - ⟨isFactor_boundedLinearOperators, exists_isMinimalProjection_boundedLinearOperators⟩ - -/-- **`B(H)` is `⋆`-isomorphic to `B(K)`** for some complex Hilbert space `K`. This applies the -abstract type I factor structure theorem `IsTypeIFactor.exists_starAlgEquiv` to the full algebra; -`K` is `ℓ²` of an orthonormal basis of `H`. -/ -theorem exists_starAlgEquiv_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] - [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] : - ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), - Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := - isTypeIFactor_boundedLinearOperators.exists_starAlgEquiv - -/-- **`B(H) ≃⋆ₐ B(K)` with `K` infinite-dimensional, when `H` is infinite-dimensional.** The full -algebra is `⋆`-isomorphic to `B(K)` for a complex Hilbert space `K` that is itself -infinite-dimensional. Here `K = ℓ²(F)` for `F` an orthonormal basis of `H`; a finite `F` would, -through the spatial decomposition `H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` with one-dimensional multiplicity `eH` (the -range of the rank-one minimal projection), force `H` finite-dimensional. Expressing type I_∞ as -`¬FiniteDimensional ℂ K` is the standard reading: a type I_n factor is `B(K)` with `dim K = n`, so -I_∞ is exactly the infinite-dimensional `K`. -/ -theorem exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators {H : Type u} - [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - (hinf : ¬FiniteDimensional ℂ H) : - ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), - ¬FiniteDimensional ℂ K ∧ - Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by - haveI : Nontrivial H := by - rcases subsingleton_or_nontrivial H with h | h - · haveI := h - exact absurd (inferInstance : FiniteDimensional ℂ H) hinf - · exact h - obtain ⟨u, hu⟩ := exists_unit_vector (H := H) - have he : IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := - isMinimalProjection_rankOne_boundedLinearOperators hu - obtain ⟨F, U, hU, -⟩ := isFactor_boundedLinearOperators.exists_spatial_tensorDecomposition he - haveI : CompleteSpace (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := - he.1.completeSpace_range - haveI hfd : FiniteDimensional ℂ (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := - finiteDimensional_range_rankOne u - haveI : Nontrivial (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := by - rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] - exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective - (h.trans ContinuousLinearMap.coe_zero.symm)) - refine ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, ?_, - ⟨(conjEquiv U ⊤).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ - intro hK - haveI := hK - exact hinf U.symm.toLinearEquiv.finiteDimensional - -/-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** Packaged as the intrinsic -predicate `IsTypeIInfinite`: `⊤ = B(H)` is a type I factor (`isTypeIFactor_boundedLinearOperators`) -carrying an infinite orthogonal family of minimal projections — the rank-one projections -`|uₙ⟩⟨uₙ|` onto a countable orthonormal sequence `(uₙ)` extracted from a Hilbert basis of the -infinite-dimensional `H`. The `⋆`-isomorphism to an infinite-dimensional `B(K)` is -`exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators`. -/ -theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] - [InnerProductSpace ℂ H] [CompleteSpace H] (hinf : ¬FiniteDimensional ℂ H) : - IsTypeIInfinite (⊤ : VonNeumannAlgebra H) := by - obtain ⟨w, b, -⟩ := exists_hilbertBasis ℂ H - have hwinf : Infinite w := by - rw [← not_finite_iff_infinite] - intro hfin - haveI : Finite w := hfin - haveI : Fintype w := Fintype.ofFinite w - exact hinf b.toOrthonormalBasis.toBasis.finiteDimensional_of_finite - haveI := hwinf - let g : ℕ ↪ w := Infinite.natEmbedding w - set u : ℕ → H := fun n => b (g n) with hu_def - have hon : Orthonormal ℂ u := by - rw [hu_def]; exact b.orthonormal.comp g g.injective - have hnorm : ∀ n, ‖u n‖ = 1 := fun n => hon.1 n - have hmin : ∀ n, IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ (u n) (u n)) := - fun n => isMinimalProjection_rankOne_boundedLinearOperators (hnorm n) - have horth : ∀ m n, m ≠ n → rankOne ℂ (u m) (u m) * rankOne ℂ (u n) (u n) = 0 := by - intro m n hmn - rw [ContinuousLinearMap.mul_def, rankOne_comp_rankOne, hon.2 hmn, zero_smul] - haveI : Nontrivial H := - nontrivial_of_ne (u 0) 0 (by rw [← norm_ne_zero_iff, hnorm 0]; norm_num) - exact ⟨isTypeIFactor_boundedLinearOperators, fun n => rankOne ℂ (u n) (u n), hmin, horth⟩ - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean deleted file mode 100644 index 4f975c5..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/CentralProjection.lean +++ /dev/null @@ -1,144 +0,0 @@ -module - -public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor - -/-! -# Central projections in a von Neumann algebra - -A **central projection** of `N` is a projection lying in the centre `N ∩ N'`. This file records -the basic facts, in particular that in a *factor* the only central projections are the trivial -ones `0` and `1` — the projection-level expression of the triviality of the centre, and the seed -of "central support `= 1`" used in the comparison theory. - -## Main definitions - -* `VonNeumannAlgebra.IsCentralProjection N e` — `e` is a projection in `N ∩ N'`. - -## Main results - -* `VonNeumannAlgebra.IsFactor.central_projection_eq` — in a factor every central projection is - `0` or `1`. -* `VonNeumannAlgebra.isStarProjection_mem_commutant_iff` — a star projection lies in the commutant - `N'` exactly when its range is invariant under every element of `N` (the projection–reducing - subspace bridge used to build central supports). --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- A **central projection** of `N`: a star projection lying in both `N` and its commutant -(equivalently, in the centre `N ∩ N'`). -/ -def IsCentralProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := - IsStarProjection e ∧ e ∈ N ∧ e ∈ N.commutant - -/-- `0` is a central projection. -/ -lemma isCentralProjection_zero (N : VonNeumannAlgebra H) : IsCentralProjection N 0 := - ⟨IsStarProjection.zero _, zero_mem _, zero_mem _⟩ - -/-- `1` is a central projection. -/ -lemma isCentralProjection_one (N : VonNeumannAlgebra H) : IsCentralProjection N 1 := - ⟨IsStarProjection.one _, one_mem _, one_mem _⟩ - -/-- In a factor, every central projection is trivial: it is `0` or `1`. This is the -projection-level form of the triviality of the centre. -/ -theorem IsFactor.central_projection_eq [Nontrivial H] {N : VonNeumannAlgebra H} - (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsCentralProjection N e) : - e = 0 ∨ e = 1 := by - obtain ⟨c, hc⟩ := hN e he.2.1 he.2.2 - have hidem : e * e = e := he.1.isIdempotentElem - rw [hc] at hidem - have hcc : (c * c) • (1 : H →L[ℂ] H) = c • 1 := by - rw [← hidem, smul_mul_smul_comm, mul_one] - have hc2 : c * c = c := smul_left_injective ℂ one_ne_zero hcc - have h0 : c * (c - 1) = 0 := by rw [mul_sub, mul_one, hc2, sub_self] - rcases mul_eq_zero.mp h0 with h | h - · exact Or.inl (by rw [hc, h, zero_smul]) - · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) - -/-- A star projection lies in the commutant `N'` exactly when its range is invariant under every -element of `N`. This is the bridge between reducing subspaces and (eventually central) -projections: it follows from the double-commutant characterisation -`VonNeumannAlgebra.IsStarProjection.mem_iff` together with `commutant_commutant`. -/ -theorem isStarProjection_mem_commutant_iff {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - (he : IsStarProjection e) : - e ∈ N.commutant ↔ ∀ y ∈ N, (e.range) ∈ Module.End.invtSubmodule (y : Module.End ℂ H) := by - rw [IsStarProjection.mem_iff he N.commutant, commutant_commutant] - -/-- **Central support (factor case).** In a factor, a nonzero operator `q` meets the -"`N`-orbit" of any nonzero `e ∈ N`: there is `a ∈ N` with `q a e ≠ 0`. The statement needs no -projection hypothesis on `e` or `q`, only `e ∈ N`, `e ≠ 0` and `q ≠ 0`. The proof takes the -orthogonal projection `P` onto the closed `N`-invariant subspace generated by `e H`; `P` reduces -both `N` and `N'`, so it is central, hence `0` or `1`; since `P` acts as the identity on `e H` -(so `P ≠ 0`, as `e ≠ 0`), `P = 1`, so the generated subspace is the whole space and `q` cannot -annihilate it. This is the geometric input of the comparison theorem. -/ -theorem IsFactor.exists_mul_ne [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) - {e q : H →L[ℂ] H} (heN : e ∈ N) (he0 : e ≠ 0) (hq0 : q ≠ 0) : ∃ a ∈ N, q * a * e ≠ 0 := by - by_contra hcon - have hcon' : ∀ a ∈ N, q * a * e = 0 := fun a haN => by - by_contra h; exact hcon ⟨a, haN, h⟩ - set S : Set H := {y | ∃ a ∈ N, ∃ x, (a : H →L[ℂ] H) (e x) = y} with hS - set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM - set P : H →L[ℂ] H := M.starProjection with hP - have hPproj : IsStarProjection P := isStarProjection_starProjection - have hSsub : S ⊆ M := Submodule.subset_span.trans (Submodule.le_topologicalClosure _) - have hSmem : ∀ (a : H →L[ℂ] H), a ∈ N → ∀ x, (a : H →L[ℂ] H) (e x) ∈ M := - fun a haN x => hSsub ⟨a, haN, x, rfl⟩ - have hinv : ∀ (y : H →L[ℂ] H), (∀ s ∈ S, y s ∈ M) → - P.range ∈ Module.End.invtSubmodule (y : Module.End ℂ H) := by - intro y hyS - have hcomapclosed : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by - rw [Submodule.comap_coe] - exact ((Submodule.span ℂ S).isClosed_topologicalClosure).preimage y.continuous - have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by - apply Submodule.topologicalClosure_minimal (Submodule.span ℂ S) _ hcomapclosed - rw [Submodule.span_le] - intro s hs - simp only [Submodule.comap_coe, Set.mem_preimage, SetLike.mem_coe] - exact hyS s hs - rw [hP, Submodule.range_starProjection]; exact hle - have hPcomm : P ∈ N.commutant := by - rw [isStarProjection_mem_commutant_iff hPproj] - intro y hyN - refine hinv y ?_ - rintro s ⟨a, haN, x, rfl⟩ - rw [show y ((a : H →L[ℂ] H) (e x)) = (y * a) (e x) from rfl] - exact hSmem (y * a) (mul_mem hyN haN) x - have hPN : P ∈ N := by - rw [IsStarProjection.mem_iff hPproj N] - intro y hyN' - refine hinv y ?_ - rintro s ⟨a, haN, x, rfl⟩ - have hay : a * y = y * a := mem_commutant_iff.mp hyN' a haN - have hey : e * y = y * e := mem_commutant_iff.mp hyN' e heN - have heq : y ((a : H →L[ℂ] H) (e x)) = (a : H →L[ℂ] H) (e (y x)) := by - rw [show y ((a : H →L[ℂ] H) (e x)) = (y * a) (e x) from rfl, ← hay] - rw [show (a * y) (e x) = (a : H →L[ℂ] H) (y (e x)) from rfl] - rw [show y (e x) = (y * e) x from rfl, ← hey]; rfl - rw [heq]; exact hSmem a haN (y x) - have hPcentral : IsCentralProjection N P := ⟨hPproj, hPN, hPcomm⟩ - have hP1 : P = 1 := by - rcases hN.central_projection_eq hPcentral with h0 | h1 - · exact absurd (by - ext x - have hpx : P (e x) = e x := by - rw [hP, Submodule.starProjection_eq_self_iff]; exact hSmem 1 (one_mem _) x - rw [h0] at hpx; simpa using hpx.symm : e = 0) he0 - · exact h1 - have hMtop : M = ⊤ := by - have hMr : M = P.range := (Submodule.range_starProjection M).symm - rw [hMr, hP1]; exact Submodule.eq_top_iff'.2 fun y => ⟨y, rfl⟩ - have hqM : M ≤ LinearMap.ker (q : H →ₗ[ℂ] H) := by - apply Submodule.topologicalClosure_minimal (Submodule.span ℂ S) _ q.isClosed_ker - rw [Submodule.span_le] - rintro s ⟨a, haN, x, rfl⟩ - simp only [SetLike.mem_coe, LinearMap.mem_ker, ContinuousLinearMap.coe_coe] - rw [show q ((a : H →L[ℂ] H) (e x)) = (q * a * e) x from rfl, hcon' a haN]; rfl - apply hq0 - ext x - have hx : x ∈ LinearMap.ker (q : H →ₗ[ℂ] H) := hqM (hMtop ▸ Submodule.mem_top) - simpa using hx - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean deleted file mode 100644 index ed7380d..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Comparison.lean +++ /dev/null @@ -1,224 +0,0 @@ -module - -public import QuantumSystem.Algebra.VonNeumannAlgebra.CentralProjection - -/-! -# Comparison of projections in a von Neumann algebra - -Building on `Factor.lean`, this file develops the basic calculus underlying Murray–von Neumann -comparison theory: the source/range identities of partial isometries, the symmetry of the -subprojection relation, and the subordination relation `MvNSub N p q` ("`p` is equivalent to a -subprojection of `q`"). - -The full comparison theorem (any two projections in a factor are comparable) requires central -supports and polar decomposition; it is developed in subsequent steps. - -## Main definitions - -* `VonNeumannAlgebra.MvNSub N p q` — `p ≼[N] q`: `p` is Murray–von Neumann equivalent to a - subprojection of `q`. - -## Main results - -* `MvNEquiv.isStarProjection_left` / `isStarProjection_right` — the endpoints of an equivalence - are star projections. -* `isStarProjection_subproj_comm` — the subprojection relation `e * f = f` is left/right symmetric - for projections. -* `IsPartialIsometry.mul_source` — the source projection acts as a one-sided identity. -* `MvNEquiv.exists_subproj_equiv` — an equivalence `q ∼[N] r'` transports a subprojection - `q' ≤ q` to a subprojection of `r'` equivalent to `q'`. -* `MvNSub.refl` / `MvNSub.trans` — subordination is a preorder on projections. -* `mvNSub_of_posCorner` — the scaling step of the comparison theorem: a positive scalar corner - `(q a e)⋆(q a e) = c • e`, `c > 0`, yields `e ≼[N] q`. - -## Notation - -The subordination symbol lives in the opt-in `VonNeumannAlgebra` scope (alongside `∼[N]` from -`Factor.lean`); activate it with `open scoped VonNeumannAlgebra`. - -| Symbol | Expansion | How to activate | -|---|---|---| -| `p ≼[N] q` | `VonNeumannAlgebra.MvNSub N p q` | `open scoped VonNeumannAlgebra` | --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- The source projection of a Murray–von Neumann equivalence is a star projection. -/ -lemma MvNEquiv.isStarProjection_left {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} - (h : p ∼[N] q) : IsStarProjection p := by - obtain ⟨v, _, hpi, hvp, _⟩ := h; exact hvp ▸ hpi.isStarProjection_star_mul_self - -/-- The range projection of a Murray–von Neumann equivalence is a star projection. -/ -lemma MvNEquiv.isStarProjection_right {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} - (h : p ∼[N] q) : IsStarProjection q := by - obtain ⟨v, _, hpi, _, hvq⟩ := h; exact hvq ▸ hpi.isStarProjection_mul_star_self - -/-- For projections, the subprojection relation `e * f = f` is left/right symmetric. -/ -lemma isStarProjection_subproj_comm {R : Type*} [Ring R] [StarRing R] {e f : R} - (he : IsStarProjection e) (hf : IsStarProjection f) (h : e * f = f) : f * e = f := by - have := congrArg star h - rwa [star_mul, he.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this - -/-- The source projection of a partial isometry acts as a right identity. -/ -lemma IsPartialIsometry.mul_source {R : Type*} [Monoid R] [StarMul R] {v : R} - (h : IsPartialIsometry v) : v * (star v * v) = v := by rw [← mul_assoc]; exact h - -/-- `p ≼ q` in `N`: `p` is Murray–von Neumann equivalent to a subprojection of `q`. -/ -def MvNSub (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := - ∃ q' : H →L[ℂ] H, q' ∈ N ∧ q * q' = q' ∧ p ∼[N] q' - -/-- `p ≼[N] q` denotes the subordination relation `MvNSub N p q`: `p` is Murray–von Neumann -equivalent to a subprojection of `q` inside `N`. -/ -scoped notation:50 p:51 " ≼[" N "] " q:51 => MvNSub N p q - -/-- Subordination is reflexive on projections of `N`. -/ -lemma MvNSub.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} - (hp : IsStarProjection p) (hpN : p ∈ N) : p ≼[N] p := - ⟨p, hpN, hp.isIdempotentElem, MvNEquiv.refl hp hpN⟩ - -/-- An equivalence `q ∼[N] r'` transports a subprojection `q' ≤ q` to a subprojection of `r'` that -is Murray–von Neumann equivalent to `q'`. -/ -theorem MvNEquiv.exists_subproj_equiv {N : VonNeumannAlgebra H} {q r' q' : H →L[ℂ] H} - (hqr : q ∼[N] r') (hq' : IsStarProjection q') (hq'N : q' ∈ N) (hsub : q * q' = q') : - ∃ r'' : H →L[ℂ] H, IsStarProjection r'' ∧ r'' ∈ N ∧ r' * r'' = r'' ∧ q' ∼[N] r'' := by - obtain ⟨w, hwN, hwpi, hwq, hwr⟩ := hqr - refine ⟨w * q' * star w, ⟨?_, ?_⟩, mul_mem (mul_mem hwN hq'N) (star_mem hwN), ?_, ?_⟩ - · change (w * q' * star w) * (w * q' * star w) = w * q' * star w - simp only [mul_assoc] - rw [← mul_assoc (star w) w (q' * star w), hwq, ← mul_assoc q q' (star w), hsub, - ← mul_assoc q' q' (star w), hq'.isIdempotentElem] - · change star (w * q' * star w) = w * q' * star w - rw [star_mul, star_mul, star_star, hq'.isSelfAdjoint.star_eq, mul_assoc] - · rw [← hwr] - simp only [mul_assoc] - rw [← mul_assoc (star w) w (q' * star w), hwq, ← mul_assoc q q' (star w), hsub] - · refine ⟨w * q', mul_mem hwN hq'N, ?_, ?_, ?_⟩ - · change (w * q') * star (w * q') * (w * q') = w * q' - rw [star_mul, hq'.isSelfAdjoint.star_eq] - simp only [mul_assoc] - rw [← mul_assoc (star w) w q', hwq, hsub, hq'.isIdempotentElem, hq'.isIdempotentElem] - · change star (w * q') * (w * q') = q' - rw [star_mul, hq'.isSelfAdjoint.star_eq, mul_assoc, ← mul_assoc (star w) w q', hwq, hsub, - hq'.isIdempotentElem] - · change (w * q') * star (w * q') = w * q' * star w - rw [star_mul, hq'.isSelfAdjoint.star_eq] - simp only [mul_assoc] - rw [← mul_assoc q' q' (star w), hq'.isIdempotentElem] - -/-- Subordination is transitive: `≼` is a preorder on the projections of `N`. -/ -lemma MvNSub.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} - (hpq : p ≼[N] q) (hqr : q ≼[N] r) : p ≼[N] r := by - obtain ⟨q', hq'N, hqsub, hpq'⟩ := hpq - obtain ⟨r', hr'N, hrsub, hqr'⟩ := hqr - obtain ⟨r'', _, hr''N, hr'sub, hq'r''⟩ := - hqr'.exists_subproj_equiv hpq'.isStarProjection_right hq'N hqsub - refine ⟨r'', hr''N, ?_, hpq'.trans hq'r''⟩ - calc r * r'' = r * (r' * r'') := by rw [hr'sub] - _ = (r * r') * r'' := by rw [mul_assoc] - _ = r' * r'' := by rw [hrsub] - _ = r'' := hr'sub - -/-- **Scaling step of the comparison theorem.** If the positive corner element -`(q a e)⋆ (q a e)` equals a positive scalar multiple `c • e` of `e` (with `c > 0`), then `e` is -subordinate to `q`: the normalised element `(√c)⁻¹ • (q a e)` is a partial isometry with source -`e` and range a subprojection of `q`. The hypotheses isolate the two analytic inputs of the -comparison theorem — the corner being scalar (minimality) and its positivity. -/ -theorem mvNSub_of_posCorner {N : VonNeumannAlgebra H} {e q a : H →L[ℂ] H} - (he : IsStarProjection e) (hq : IsStarProjection q) - (heN : e ∈ N) (hqN : q ∈ N) (haN : a ∈ N) - {c : ℝ} (hc : 0 < c) - (hcorner : star (q * a * e) * (q * a * e) = (c : ℂ) • e) : - e ≼[N] q := by - set γ : ℂ := ((Real.sqrt c)⁻¹ : ℂ) with hγ - set v : H →L[ℂ] H := γ • (q * a * e) with hv - have hvN : v ∈ N := smul_mem γ (mul_mem (mul_mem hqN haN) heN) - have hsrc : star v * v = e := by - rw [hv, star_smul, smul_mul_smul_comm, hcorner, smul_smul] - have hstar : star γ = γ := by rw [hγ, star_inv₀, ← starRingEnd_apply, Complex.conj_ofReal] - rw [hstar, hγ, ← mul_inv, ← Complex.ofReal_mul, Real.mul_self_sqrt hc.le, - inv_mul_cancel₀ (by exact_mod_cast hc.ne'), one_smul] - have hve : v * e = v := by - rw [hv, smul_mul_assoc, mul_assoc (q * a) e e, he.isIdempotentElem] - have hvpi : IsPartialIsometry v := by - unfold IsPartialIsometry - rw [mul_assoc, hsrc, hve] - refine ⟨v * star v, mul_mem hvN (star_mem hvN), ?_, ⟨v, hvN, hvpi, hsrc, rfl⟩⟩ - have hqv : q * v = v := by - rw [hv, mul_smul_comm, ← mul_assoc, ← mul_assoc, hq.isIdempotentElem] - rw [← mul_assoc, hqv] - -/-- **Positivity of the corner scalar.** For a minimal projection `e` and `a ∈ N` with -`q a e ≠ 0`, the corner element `(q a e)⋆ (q a e) = e (a⋆ q a) e` equals a *strictly positive -real* scalar multiple of `e`. (Reality comes from self-adjointness; strict positivity from -evaluating on a nonzero vector of `e H` on which `q a e` does not vanish.) -/ -lemma IsMinimalProjection.posCorner {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) - (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : - ∃ c : ℝ, 0 < c ∧ star (q * a * e) * (q * a * e) = (c : ℂ) • e := by - set x := q * a * e with hx - have hxx : star x * x = e * (star a * q * a) * e := by - rw [hx, star_mul, star_mul, he.1.isSelfAdjoint.star_eq, hq.isSelfAdjoint.star_eq] - rw [mul_assoc, mul_assoc, mul_assoc, ← mul_assoc q q, hq.isIdempotentElem] - simp only [mul_assoc] - obtain ⟨c', hc'⟩ := he.2.2.2 (star a * q * a) (mul_mem (mul_mem (star_mem haN) hqN) haN) - rw [← hxx] at hc' - have hconj : (starRingEnd ℂ) c' = c' := by - have hsa : star (star x * x) = star x * x := by rw [star_mul, star_star] - rw [hc', star_smul, he.1.isSelfAdjoint.star_eq] at hsa - rw [starRingEnd_apply]; exact smul_left_injective ℂ he.2.2.1 hsa - have hxe : x * e = x := by rw [hx, mul_assoc, he.1.isIdempotentElem] - obtain ⟨η, hη⟩ : ∃ η, x η ≠ 0 := by - by_contra h - exact hne (by ext η; exact not_not.mp (not_exists.mp h η)) - set ξ := e η with hξ - have hxξ : x ξ ≠ 0 := by - rw [hξ, ← ContinuousLinearMap.comp_apply, ← ContinuousLinearMap.mul_def, hxe]; exact hη - have heξ : e ξ = ξ := by - rw [hξ, ← ContinuousLinearMap.comp_apply, ← ContinuousLinearMap.mul_def, he.1.isIdempotentElem] - have hξne : ξ ≠ 0 := fun h => hxξ (by rw [h, map_zero]) - have hinner : ‖x ξ‖ ^ 2 = c'.re * ‖ξ‖ ^ 2 := by - have e1 : inner ℂ ((star x * x) ξ) ξ = inner ℂ (x ξ) (x ξ) := by - rw [ContinuousLinearMap.mul_apply, ContinuousLinearMap.star_eq_adjoint, - ContinuousLinearMap.adjoint_inner_left] - have e2 : inner ℂ ((star x * x) ξ) ξ = (starRingEnd ℂ) c' * inner ℂ ξ ξ := by - rw [hc', ContinuousLinearMap.smul_apply, heξ, inner_smul_left] - have e3 : inner ℂ (x ξ) (x ξ) = (starRingEnd ℂ) c' * inner ℂ ξ ξ := e1.symm.trans e2 - have hre := congrArg RCLike.re e3 - rw [inner_self_eq_norm_sq, inner_self_eq_norm_sq_to_K] at hre - simp only [RCLike.mul_re, RCLike.mul_im, RCLike.conj_re, RCLike.conj_im, RCLike.ofReal_re, - RCLike.ofReal_im, pow_two, mul_zero, zero_mul, add_zero, sub_zero] at hre - rw [show RCLike.re c' = c'.re from rfl] at hre - nlinarith [hre] - have hξpos : 0 < ‖ξ‖ ^ 2 := pow_pos (norm_pos_iff.mpr hξne) 2 - have hxξpos : 0 < ‖x ξ‖ ^ 2 := pow_pos (norm_pos_iff.mpr hxξ) 2 - have hcre : c' = (c'.re : ℂ) := (Complex.conj_eq_iff_re.mp hconj).symm - refine ⟨c'.re, by nlinarith [hinner, hξpos, hxξpos], ?_⟩ - rw [hc']; exact congrArg (· • e) hcre - -/-- A minimal projection is subordinate to any projection it "meets": if some `a ∈ N` has -`q a e ≠ 0`, then `e ≼ q`. Combined with central supports (which guarantee `q a e ≠ 0` for every -nonzero `q` in a factor) this yields the comparison theorem `minimal e ≼ q`. -/ -lemma IsMinimalProjection.mvNSub_of_ne {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - (he : IsMinimalProjection N e) {q a : H →L[ℂ] H} (hq : IsStarProjection q) - (hqN : q ∈ N) (haN : a ∈ N) (hne : q * a * e ≠ 0) : e ≼[N] q := by - obtain ⟨c, hcpos, hcorner⟩ := he.posCorner hq hqN haN hne - exact mvNSub_of_posCorner he.1 hq he.2.1 hqN haN hcpos hcorner - -/-- **Comparison theorem (minimal projection case).** In a factor, a minimal projection `e` is -Murray–von Neumann subordinate to *every* nonzero projection `q`: `e ≼ q`. This combines the -scaling lemma (via `mvNSub_of_ne`) with the central-support input -(`IsFactor.exists_mul_ne`, which supplies an `a ∈ N` with `q a e ≠ 0`). It is the form of -comparison needed to show a maximal orthogonal family of minimal projections exhausts the -identity. -/ -theorem IsMinimalProjection.mvNSub_of_isFactor [Nontrivial H] {N : VonNeumannAlgebra H} - (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) - {q : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (hq0 : q ≠ 0) : - e ≼[N] q := by - obtain ⟨a, haN, hane⟩ := hN.exists_mul_ne he.2.1 he.2.2.1 hq0 - exact he.mvNSub_of_ne hq hqN haN hane - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean deleted file mode 100644 index a7eed32..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/CoveringFamily.lean +++ /dev/null @@ -1,205 +0,0 @@ -module - -public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison -public import Mathlib.Analysis.InnerProductSpace.Projection.Basic - -/-! -# Towards the type I factor structure theorem: a covering family of minimal projections - -For a type I factor `N` with minimal projection `e`, this file produces (by Zorn's lemma and the -comparison theorem `IsMinimalProjection.mvNSub_of_isFactor`) a family of mutually orthogonal -projections, each Murray–von Neumann equivalent to `e`, whose ranges span densely — the -projection-theoretic backbone `Σ eᵢ = 1` of the structure theorem `N ≅ B(H₁) ⊗̄ 1`. - -The spatial identification (Hilbert sum and `U • N = B(H₁) ⊗̄ 1`) is a further step. - -The dense span is expressed as -`(Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤`, i.e. the closed linear -span of the union of the ranges is the whole space; this is the operator-friendly form of -`⨆ᵢ ranges = 1` and matches the central-support construction `IsFactor.exists_mul_ne`. - -## Main definitions - -* `VonNeumannAlgebra.OrthEquivFam N e F` — `F` is a set of pairwise-orthogonal nonzero projections - in `N`, each Murray–von Neumann equivalent to `e`. - -## Main results - -* `VonNeumannAlgebra.IsFactor.exists_orthEquivFam_top` — in a factor, there is a maximal such - family whose ranges have dense span. --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- The range projection of a Murray–von Neumann equivalence with nonzero source is nonzero. -/ -lemma MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} - (h : p ∼[N] q) (hp : p ≠ 0) : q ≠ 0 := by - obtain ⟨v, _, hvpi, hvp, hvq⟩ := h - intro hq0 - apply hp - have hv0 : v = 0 := by - have hpi : v * star v * v = v := hvpi - rw [hvq, hq0, zero_mul] at hpi - exact hpi.symm - rw [← hvp, hv0]; simp - -/-- **Minimality transports along Murray–von Neumann equivalence.** If `e` is a minimal projection -and `e ∼[N] p`, then `p` is minimal: with `v⋆v = e` and `vv⋆ = p`, the corner computes as -`p a p = v (e (v⋆ a v) e) v⋆ = c • v e v⋆ = c • p`. -/ -lemma IsMinimalProjection.of_mvNEquiv {N : VonNeumannAlgebra H} {e p : H →L[ℂ] H} - (he : IsMinimalProjection N e) (h : e ∼[N] p) : IsMinimalProjection N p := by - have hpproj : IsStarProjection p := h.isStarProjection_right - have hp0 : p ≠ 0 := h.ne_zero he.2.2.1 - obtain ⟨v, hvN, hvpi, hvp, hvq⟩ := h - have hpN : p ∈ N := by rw [← hvq]; exact mul_mem hvN (star_mem hvN) - have hve : v * e = v := by rw [← hvp]; exact IsPartialIsometry.mul_source hvpi - have hev : e * star v = star v := by - have := congrArg star hve - rwa [star_mul, he.1.isSelfAdjoint.star_eq] at this - refine ⟨hpproj, hpN, hp0, fun a haN => ?_⟩ - obtain ⟨c, hc⟩ := he.2.2.2 (star v * a * v) (mul_mem (mul_mem (star_mem hvN) haN) hvN) - refine ⟨c, ?_⟩ - calc p * a * p - = (v * star v) * a * (v * star v) := by rw [hvq] - _ = (v * e) * (star v * a * v) * (e * star v) := by - rw [hve, hev]; simp only [mul_assoc] - _ = v * (e * (star v * a * v) * e) * star v := by simp only [mul_assoc] - _ = v * (c • e) * star v := by rw [hc] - _ = c • (v * e * star v) := by simp only [mul_smul_comm, smul_mul_assoc] - _ = c • p := by rw [hve, hvq] - -/-- A family of pairwise-orthogonal nonzero projections in `N`, each Murray–von Neumann equivalent -to `e`. -/ -def OrthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ℂ] H)) : Prop := - (∀ p ∈ F, IsStarProjection p ∧ p ∈ N ∧ p ≠ 0 ∧ e ∼[N] p) ∧ - F.Pairwise (fun p q => p * q = 0) - -/-- When `e` is minimal, every member of an `OrthEquivFam` for `e` is itself a minimal -projection, since minimality transports along `∼[N]` (`IsMinimalProjection.of_mvNEquiv`). -/ -lemma OrthEquivFam.isMinimalProjection_of_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) - {p : H →L[ℂ] H} (hp : p ∈ F) : IsMinimalProjection N p := - he.of_mvNEquiv (hF.1 p hp).2.2.2 - -/-- By Zorn's lemma, there is a maximal orthogonal family of `e`-equivalent projections. -/ -lemma exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : - ∃ F, OrthEquivFam N e F ∧ ∀ G, OrthEquivFam N e G → F ⊆ G → G ⊆ F := by - obtain ⟨F, hFmax⟩ := zorn_subset {F | OrthEquivFam N e F} (by - intro c hcsub hchain - refine ⟨⋃₀ c, ⟨?_, ?_⟩, fun s hs => Set.subset_sUnion_of_mem hs⟩ - · rintro p ⟨s, hsc, hps⟩; exact (hcsub hsc).1 p hps - · rintro p ⟨s, hsc, hps⟩ q ⟨t, htc, hqt⟩ hpq - rcases hchain.total hsc htc with h | h - · exact (hcsub htc).2 (h hps) hqt hpq - · exact (hcsub hsc).2 hps (h hqt) hpq) - exact ⟨F, hFmax.1, fun G hG hFG => hFmax.2 hG hFG⟩ - -/-- The orthogonal projection onto the closed span of the ranges of an `OrthEquivFam` lies in `N`, -because that subspace is invariant under the commutant `N'`: for `y ∈ N'` and `f ∈ F ⊆ N`, -`y (f x) = (y f) x = (f y) x = f (y x)` lies in the range of `f`. -/ -lemma OrthEquivFam.starProjection_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) : - (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure.starProjection ∈ N := by - set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS - set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM - set p : H →L[ℂ] H := M.starProjection with hp - have hpproj : IsStarProjection p := isStarProjection_starProjection - rw [IsStarProjection.mem_iff hpproj N] - intro y hyN' - rw [hp, Submodule.range_starProjection] - have hcl : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by - rw [Submodule.comap_coe] - exact ((Submodule.span ℂ S).isClosed_topologicalClosure).preimage y.continuous - have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by - refine Submodule.topologicalClosure_minimal (Submodule.span ℂ S) ?_ hcl - rw [Submodule.span_le] - rintro s ⟨f, hf, x, rfl⟩ - simp only [Submodule.comap_coe, Set.mem_preimage, SetLike.mem_coe, ContinuousLinearMap.coe_coe] - have hfy : f * y = y * f := mem_commutant_iff.mp hyN' f (hF.1 f hf).2.1 - rw [show y (f x) = (y * f) x from rfl, ← hfy] - exact Submodule.le_topologicalClosure _ (Submodule.subset_span ⟨f, hf, y x, rfl⟩) - exact hle - -/-- **Covering family of minimal projections (factor case).** In a factor, there is a family `F` -of pairwise-orthogonal nonzero projections in `N`, each equivalent to the minimal projection `e`, -whose ranges span densely: the closed linear span of the union of their ranges is `⊤`. This is the -`Σ eᵢ = 1` input of the type I structure theorem. - -The proof takes a *maximal* such family `F` (Zorn) and lets `p` be the orthogonal projection onto -the closed span `M` of the ranges; `p ∈ N`. If `M ≠ ⊤` then `r = 1 - p` is a nonzero projection in -`N`, so by the comparison theorem some nonzero `q' ≼ r` is equivalent to `e`; `q'` is orthogonal to -every `f ∈ F`, contradicting maximality. -/ -theorem IsFactor.exists_orthEquivFam_top [Nontrivial H] {N : VonNeumannAlgebra H} - (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : - ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ - (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ := by - obtain ⟨F, hF, hFmax⟩ := exists_maximal_orthEquivFam N e - refine ⟨F, hF, ?_⟩ - set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS - set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM - set p : H →L[ℂ] H := M.starProjection with hp - have hpproj : IsStarProjection p := isStarProjection_starProjection - have hpN : p ∈ N := hF.starProjection_mem - have hpf : ∀ f ∈ F, p * f = f := by - intro f hf - ext x - simp only [ContinuousLinearMap.mul_apply, hp] - rw [Submodule.starProjection_eq_self_iff] - exact Submodule.le_topologicalClosure _ (Submodule.subset_span ⟨f, hf, x, rfl⟩) - by_contra hMtop - set r : H →L[ℂ] H := 1 - p with hr - have hrproj : IsStarProjection r := by - refine ⟨?_, ?_⟩ - · change (1 - p) * (1 - p) = 1 - p - rw [mul_sub, sub_mul, sub_mul, one_mul, one_mul, mul_one, hpproj.isIdempotentElem, - sub_self, sub_zero] - · change star (1 - p) = 1 - p - rw [star_sub, star_one, hpproj.isSelfAdjoint.star_eq] - have hrN : r ∈ N := by rw [hr]; exact sub_mem (one_mem _) hpN - have hr0 : r ≠ 0 := by - intro h - apply hMtop - have hp1 : p = 1 := by rw [hr, sub_eq_zero] at h; exact h.symm - have hMrange : M = p.range := (Submodule.range_starProjection M).symm - rw [hMrange, hp1] - exact Submodule.eq_top_iff'.2 fun y => ⟨y, rfl⟩ - obtain ⟨q', hq'N, hrq', heq'⟩ := he.mvNSub_of_isFactor hN hrproj hrN hr0 - have hq'proj : IsStarProjection q' := heq'.isStarProjection_right - have hq'0 : q' ≠ 0 := heq'.ne_zero he.2.2.1 - have hpq' : p * q' = 0 := by - have h := hrq' - rw [hr, sub_mul, one_mul, sub_eq_self] at h - exact h - have horth : ∀ f ∈ F, q' * f = 0 ∧ f * q' = 0 := by - intro f hf - have hq'p : q' * p = 0 := by - have h := congrArg star hpq' - rwa [star_mul, hq'proj.isSelfAdjoint.star_eq, hpproj.isSelfAdjoint.star_eq, star_zero] at h - have h1 : q' * f = 0 := by - calc q' * f = q' * (p * f) := by rw [hpf f hf] - _ = (q' * p) * f := by rw [mul_assoc] - _ = 0 := by rw [hq'p, zero_mul] - refine ⟨h1, ?_⟩ - have h := congrArg star h1 - rwa [star_mul, (hF.1 f hf).1.isSelfAdjoint.star_eq, hq'proj.isSelfAdjoint.star_eq, - star_zero] at h - have hq'notF : q' ∉ F := fun hq'F => - hq'0 (by have := (horth q' hq'F).1; rwa [hq'proj.isIdempotentElem] at this) - have hbigger : OrthEquivFam N e (insert q' F) := by - refine ⟨?_, ?_⟩ - · rintro x (rfl | hx) - · exact ⟨hq'proj, hq'N, hq'0, heq'⟩ - · exact hF.1 x hx - · rintro x (rfl | hx) z (rfl | hz) hxz - · exact absurd rfl hxz - · exact (horth z hz).1 - · exact (horth x hx).2 - · exact hF.2 hx hz hxz - have hsub := hFmax (insert q' F) hbigger (Set.subset_insert _ _) - exact hq'notF (hsub (Set.mem_insert _ _)) - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean deleted file mode 100644 index d138082..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Factor.lean +++ /dev/null @@ -1,157 +0,0 @@ -module - -public import Mathlib.Analysis.VonNeumannAlgebra.Basic -public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry - -/-! -# Factors, minimal projections and Murray–von Neumann equivalence - -This file sets up the basic vocabulary of the comparison theory of projections in a von Neumann -algebra, the foundation of the type classification (and, downstream, of the type I factor -structure theorem). - -## Main definitions - -* `VonNeumannAlgebra.IsFactor N` — `N` has trivial centre: every element of `N ∩ N'` is a scalar. -* `VonNeumannAlgebra.IsMinimalProjection N e` — `e` is a nonzero star projection in `N` with - trivial corner `e N e = ℂ e`. This implies the order-theoretic minimality (no proper nonzero - subprojection in `N`, expressed algebraically as: any projection `f ∈ N` with `e * f = f`, i.e. - the Loewner relation `f ≤ e`, is `0` or `e`), recorded as - `IsMinimalProjection.no_proper_subprojection`. -* `VonNeumannAlgebra.MvNEquiv N p q` — `p` and `q` are Murray–von Neumann equivalent inside `N`: - there is a partial isometry `v ∈ N` with source `v⋆v = p` and range `vv⋆ = q`. Written `p ∼[N] q`. - -## Main results - -* `VonNeumannAlgebra.MvNEquiv.refl` / `symm` / `trans` — Murray–von Neumann equivalence is an - equivalence relation on the projections of `N`. - -## Notation - -The equivalence relation symbol of the operator-algebra literature lives in the opt-in -`VonNeumannAlgebra` scope; activate it with `open scoped VonNeumannAlgebra`. - -| Symbol | Expansion | How to activate | -|---|---|---| -| `p ∼[N] q` | `VonNeumannAlgebra.MvNEquiv N p q` | `open scoped VonNeumannAlgebra` | --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] - -/-- A von Neumann algebra is closed under scalar multiplication. -/ -lemma smul_mem {N : VonNeumannAlgebra H} (c : ℂ) {x : H →L[ℂ] H} (hx : x ∈ N) : c • x ∈ N := by - rw [Algebra.smul_def] - exact mul_mem (algebraMap_mem N.toStarSubalgebra c) hx - -/-- A von Neumann algebra `N` is a **factor** when its centre is trivial: every operator lying in -both `N` and its commutant is a scalar multiple of the identity. -/ -def IsFactor (N : VonNeumannAlgebra H) : Prop := - ∀ x : H →L[ℂ] H, x ∈ N → x ∈ N.commutant → ∃ c : ℂ, x = c • 1 - -/-- A **minimal projection** of `N`: a nonzero star projection `e ∈ N` whose corner is trivial, -`e N e = ℂ e`. This is the conventional operator-algebraic definition (Takesaki, Kadison–Ringrose); -it implies minimality in the order sense (no proper nonzero subprojection), recorded as -`IsMinimalProjection.no_proper_subprojection`. The corner formulation is the one that -supports comparison theory without invoking Borel functional calculus. -/ -def IsMinimalProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := - IsStarProjection e ∧ e ∈ N ∧ e ≠ 0 ∧ ∀ a ∈ N, ∃ c : ℂ, e * a * e = c • e - -/-- A von Neumann algebra with a minimal projection acts on a nonzero space: the minimal -projection is nonzero, so it sends some vector to a nonzero vector, witnessing `Nontrivial H`. -/ -lemma IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - (he : IsMinimalProjection N e) : Nontrivial H := - let ⟨x, hx⟩ := ContinuousLinearMap.exists_ne_zero he.2.2.1 - ⟨⟨e x, 0, hx⟩⟩ - -/-- A minimal projection has no proper nonzero subprojection in `N`: if a projection `f ∈ N` -satisfies `f ≤ e` (the Loewner order on projections, equivalently the range inclusion -`ran f ⊆ ran e`, written algebraically as `e * f = f`), then `f = 0` or `f = e`. This recovers the -order-theoretic form of minimality from the corner definition `e N e = ℂ e`. -/ -lemma IsMinimalProjection.no_proper_subprojection {N : VonNeumannAlgebra H} - {e : H →L[ℂ] H} (he : IsMinimalProjection N e) - {f : H →L[ℂ] H} (hf : IsStarProjection f) (hfN : f ∈ N) (hsub : e * f = f) : - f = 0 ∨ f = e := by - have hfe : f * e = f := by - have := congrArg star hsub - rwa [star_mul, he.1.isSelfAdjoint.star_eq, hf.isSelfAdjoint.star_eq] at this - have hefe : e * f * e = f := by rw [hsub, hfe] - obtain ⟨c, hc⟩ := he.2.2.2 f hfN - rw [hefe] at hc - have hidem : f * f = f := hf.isIdempotentElem - rw [hc] at hidem - have h2 : (c • e) * (c • e) = (c * c) • (e : H →L[ℂ] H) := by - rw [smul_mul_smul_comm, he.1.isIdempotentElem] - have hcc : (c * c) • (e : H →L[ℂ] H) = c • e := by rw [← h2, hidem] - have hc2 : c * c = c := smul_left_injective ℂ he.2.2.1 hcc - have h0 : c * (c - 1) = 0 := by rw [mul_sub, mul_one, hc2, sub_self] - rcases mul_eq_zero.mp h0 with h | h - · exact Or.inl (by rw [hc, h, zero_smul]) - · exact Or.inr (by rw [hc, sub_eq_zero.mp h, one_smul]) - -/-- An **abelian projection** of `N`: a star projection `p ∈ N` whose corner `p N p` is -commutative. Minimal projections are abelian (`IsMinimalProjection.isAbelianProjection`); the -general type I property (`IsTypeI`) is phrased through abelian projections. -/ -def IsAbelianProjection (N : VonNeumannAlgebra H) (p : H →L[ℂ] H) : Prop := - IsStarProjection p ∧ p ∈ N ∧ - ∀ a ∈ N, ∀ b ∈ N, (p * a * p) * (p * b * p) = (p * b * p) * (p * a * p) - -/-- A minimal projection is abelian: its corner `e N e = ℂ e` is one-dimensional, hence -commutative. -/ -lemma IsMinimalProjection.isAbelianProjection {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} - (he : IsMinimalProjection N e) : IsAbelianProjection N e := by - refine ⟨he.1, he.2.1, fun a haN b hbN => ?_⟩ - obtain ⟨c, hc⟩ := he.2.2.2 a haN - obtain ⟨d, hd⟩ := he.2.2.2 b hbN - rw [hc, hd, smul_mul_smul_comm, smul_mul_smul_comm, mul_comm c d] - -/-- **Murray–von Neumann equivalence** of projections inside `N`: there is a partial isometry -`v ∈ N` with source projection `v⋆v = p` and range projection `vv⋆ = q`. -/ -def MvNEquiv (N : VonNeumannAlgebra H) (p q : H →L[ℂ] H) : Prop := - ∃ v : H →L[ℂ] H, v ∈ N ∧ IsPartialIsometry v ∧ star v * v = p ∧ v * star v = q - -/-- `p ∼[N] q` denotes Murray–von Neumann equivalence `MvNEquiv N p q` of projections inside `N`. -/ -scoped notation:50 p:51 " ∼[" N "] " q:51 => MvNEquiv N p q - -/-- Murray–von Neumann equivalence is reflexive on projections of `N`. -/ -theorem MvNEquiv.refl {N : VonNeumannAlgebra H} {p : H →L[ℂ] H} - (hp : IsStarProjection p) (hpN : p ∈ N) : p ∼[N] p := - ⟨p, hpN, hp.isPartialIsometry, by rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq], - by rw [hp.isSelfAdjoint.star_eq, hp.isIdempotentElem.eq]⟩ - -/-- Murray–von Neumann equivalence is symmetric. -/ -theorem MvNEquiv.symm {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} - (h : p ∼[N] q) : q ∼[N] p := by - obtain ⟨v, hv, hpi, hvp, hvq⟩ := h - exact ⟨star v, star_mem hv, IsPartialIsometry.star hpi, by rw [star_star, hvq], - by rw [star_star, hvp]⟩ - -/-- Murray–von Neumann equivalence is transitive. -/ -theorem MvNEquiv.trans {N : VonNeumannAlgebra H} {p q r : H →L[ℂ] H} - (hpq : p ∼[N] q) (hqr : q ∼[N] r) : p ∼[N] r := by - obtain ⟨v, hv, hvpi, hvp, hvq⟩ := hpq - obtain ⟨w, hw, hwpi, hwq, hwr⟩ := hqr - have hq : IsStarProjection q := hvq ▸ hvpi.isStarProjection_mul_star_self - refine ⟨w * v, mul_mem hw hv, ?_, ?_, ?_⟩ - · unfold IsPartialIsometry - calc w * v * star (w * v) * (w * v) - = w * (v * star v) * (star w * w) * v := by simp only [star_mul, mul_assoc] - _ = w * q * q * v := by rw [hvq, hwq] - _ = w * q * v := by rw [mul_assoc w q q, hq.isIdempotentElem] - _ = w * (star w * w) * v := by rw [hwq] - _ = w * v := by rw [← mul_assoc w (star w) w, hwpi] - · calc star (w * v) * (w * v) = star v * (star w * w) * v := by simp only [star_mul, mul_assoc] - _ = star v * (v * star v) * v := by rw [hwq, hvq] - _ = (star v * v) * (star v * v) := by simp only [mul_assoc] - _ = star v * v := hvpi.isStarProjection_star_mul_self.isIdempotentElem - _ = p := hvp - · calc (w * v) * star (w * v) = w * (v * star v) * star w := by simp only [star_mul, mul_assoc] - _ = w * (star w * w) * star w := by rw [hvq, ← hwq] - _ = (w * star w) * (w * star w) := by simp only [mul_assoc] - _ = w * star w := hwpi.isStarProjection_mul_star_self.isIdempotentElem - _ = r := hwr - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean deleted file mode 100644 index 69ae639..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/GeneratedByMatrixUnits.lean +++ /dev/null @@ -1,209 +0,0 @@ -module - -public import QuantumSystem.Algebra.VonNeumannAlgebra.MatrixUnits -public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition -public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra -public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant -public import Mathlib.Algebra.Star.Subalgebra - -/-! -# Matrix units generate the type I factor - -For a type I factor `N ⊆ B(H)` with minimal projection `e` and a covering orthogonal family `F` of -`e`-equivalent projections (`OrthEquivFam`, produced by `IsFactor.exists_orthEquivFam_top`), the -system of matrix units `e_{pq} = v_p v_q⋆` generates `N` as a von Neumann algebra: - -> `VonNeumannAlgebra.generated S = N`, where `S = { e_{pq} | p q : F }`. - -This is the von-Neumann-algebraic (double-commutant) reformulation of the strong-operator -reconstruction `a = Σ_{pq} c_{pq}(a) e_{pq}` of `MatrixUnits.lean`. The reformulation avoids any -strong/weak-operator infinite-sum API (which Mathlib lacks) by working through the commutant: the -inclusion `S'' ⊆ N` is monotonicity, and the content `N ⊆ S''` is the statement that every operator -commuting with all matrix units commutes with all of `N`. - -The proof of that content (`commutes_of_mem_centralizer`) is genuinely analytic: it inserts the -resolution of the identity `Σ_r p_r = 1` (here `p_r = e_{rr} = v_r v_r⋆`) as a `HasSum`, and uses -that each `↑p · a · ↑r` is a *scalar* multiple of the matrix unit `e_{pr}` (multiplicity one, -`exists_matrixEntry`), hence commutes with `b`. The sum over the possibly-infinite index set `F` is -handled throughout by `HasSum`/`HasSum.mapL`/`HasSum.unique`; no operator-level infinite series is -formed. - -## Main results - -* `VonNeumannAlgebra.OrthEquivFam.hasSum_resolutionOfIdentity` — the resolution of the identity - `HasSum (fun i : F => (↑i) y) y`, the analytic core. -* `VonNeumannAlgebra.OrthEquivFam.commutes_of_mem_centralizer` — an operator commuting with every - matrix unit commutes with every element of `N`. -* `VonNeumannAlgebra.OrthEquivFam.generated_matrixUnits_eq` — **the matrix units generate `N`**: - `generated S = N`. -* `VonNeumannAlgebra.OrthEquivFam.mem_sotClosure_adjoin` — the literal SOT-reconstruction corollary: - every `a ∈ N` lies in the SOT-closure of the `*`-subalgebra generated by the matrix units. --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -open StrongOperatorTopology - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] -variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} - -/-- The set of matrix units is contained in `N`. -/ -lemma OrthEquivFam.matrixUnit_subset (hF : OrthEquivFam N e F) : - Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) ⊆ (N : Set (H →L[ℂ] H)) := by - rintro x ⟨pq, rfl⟩ - exact hF.matrixUnit_mem pq.1 pq.2 - -/-- **Resolution of the identity.** For a covering orthogonal family, the projections `↑i` sum to -the identity in the strong operator sense: `HasSum (fun i : F => (↑i) y) y` for every `y`. This is -the analytic heart of the generation theorem; it is the Hilbert-sum reconstruction of `y` from its -coordinates, with the `i`-th coordinate recognised as the orthogonal projection `(↑i) y` by -`coe_hilbertSumEquiv_apply`. -/ -theorem OrthEquivFam.hasSum_resolutionOfIdentity (hF : OrthEquivFam N e F) - (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) (y : H) : - HasSum (fun i : F => (i : H →L[ℂ] H) y) y := by - have hdecomp : HasSum - (fun i : F => ((hF.hilbertSumEquiv htop y i : - LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) : H)) y := by - have h := (hF.isHilbertSum htop).hasSum_linearIsometryEquiv_symm (hF.hilbertSumEquiv htop y) - have hy : (hF.isHilbertSum htop).linearIsometryEquiv.symm (hF.hilbertSumEquiv htop y) = y := - (hF.hilbertSumEquiv htop).symm_apply_apply y - rwa [hy] at h - simpa only [hF.coe_hilbertSumEquiv_apply htop y] using hdecomp - -/-- **The content of the generation theorem.** Any operator `b` commuting with every matrix unit -commutes with every `a ∈ N`. Equivalently `Set.centralizer S ⊆ Set.centralizer N`, which is the -nontrivial inclusion `N ⊆ S''`. - -The proof tests `a * b = b * a` against arbitrary inner products. Inserting the resolution of the -identity `Σ_r p_r = 1` between and around `a`, the commutator reduces to the family of operators -`↑p · a · ↑r`, each of which equals a *scalar* multiple of the matrix unit `e_{pr}` -(`exists_matrixEntry`) and therefore commutes with `b`. -/ -theorem OrthEquivFam.commutes_of_mem_centralizer (hF : OrthEquivFam N e F) - (he : IsMinimalProjection N e) - (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) - {a : H →L[ℂ] H} (ha : a ∈ N) {b : H →L[ℂ] H} - (hb : b ∈ Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2))) : - a * b = b * a := by - have hbcomm : ∀ p q : F, hF.matrixUnit p q * b = b * hF.matrixUnit p q := - fun p q => (Set.mem_centralizer_iff.mp hb) _ ⟨(p, q), rfl⟩ - -- `↑p · a · ↑r` is a scalar multiple of `e_{pr}`, hence commutes with `b`. - have hcomm_T : ∀ p r : F, ((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) * b - = b * ((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) := by - intro p r - obtain ⟨c, hc⟩ := hF.exists_matrixEntry he p r ha - have hT : (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) = c • hF.matrixUnit p r := by - rw [← hF.pisom_range p, ← hF.pisom_range r] - calc hF.pisom p * star (hF.pisom p) * a * (hF.pisom r * star (hF.pisom r)) - = hF.pisom p * (star (hF.pisom p) * a * hF.pisom r) * star (hF.pisom r) := by - simp only [mul_assoc] - _ = hF.pisom p * (c • e) * star (hF.pisom r) := by rw [hc] - _ = c • (hF.pisom p * e * star (hF.pisom r)) := by rw [mul_smul_comm, smul_mul_assoc] - _ = c • (hF.pisom p * star (hF.pisom r)) := by rw [hF.pisom_mul_source p] - _ = c • hF.matrixUnit p r := rfl - rw [hT, smul_mul_assoc, hbcomm p r, mul_smul_comm] - -- Test `a * b = b * a` against inner products. - apply ContinuousLinearMap.ext - intro y - apply ext_inner_left ℂ - intro x - -- For each `r`, the `r`-summands agree (insert `Σ_p p_p` to the left of `a`). - have step : ∀ r : F, inner ℂ x ((a * (r : H →L[ℂ] H) * b) y) - = inner ℂ x ((b * a * (r : H →L[ℂ] H)) y) := by - intro r - have hLp : HasSum - (fun p : F => inner ℂ x (((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b) y)) - (inner ℂ x ((a * (r : H →L[ℂ] H) * b) y)) := by - have h := (hF.hasSum_resolutionOfIdentity htop ((a * (r : H →L[ℂ] H) * b) y)).mapL (innerSL ℂ x) - simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h - have hRp : HasSum - (fun p : F => inner ℂ x ((b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) y)) - (inner ℂ x ((b * a * (r : H →L[ℂ] H)) y)) := by - have h := (((hF.hasSum_resolutionOfIdentity htop ((a * (r : H →L[ℂ] H)) y)).mapL b).mapL (innerSL ℂ x)) - simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h - have hfun : (fun p : F => inner ℂ x (((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b) y)) - = (fun p : F => inner ℂ x ((b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) y)) := by - funext p - have hkey : (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b - = b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) := by - rw [hcomm_T p r, ← mul_assoc, ← mul_assoc] - rw [hkey] - rw [hfun] at hLp - exact hLp.unique hRp - have hL : HasSum (fun r : F => inner ℂ x ((a * (r : H →L[ℂ] H) * b) y)) - (inner ℂ x ((a * b) y)) := by - have h := ((hF.hasSum_resolutionOfIdentity htop (b y)).mapL a).mapL (innerSL ℂ x) - simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h - have hR : HasSum (fun r : F => inner ℂ x ((b * a * (r : H →L[ℂ] H)) y)) - (inner ℂ x ((b * a) y)) := by - have h := ((hF.hasSum_resolutionOfIdentity htop y).mapL (b * a)).mapL (innerSL ℂ x) - simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h - rw [funext step] at hL - exact hL.unique hR - -/-- The centralizer of the matrix units is contained in the commutant of `N`. -/ -lemma OrthEquivFam.centralizer_subset_commutant (hF : OrthEquivFam N e F) - (he : IsMinimalProjection N e) - (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : - Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) - ⊆ Set.centralizer (N : Set (H →L[ℂ] H)) := by - intro b hb - rw [Set.mem_centralizer_iff] - intro a ha - exact hF.commutes_of_mem_centralizer he htop ha hb - -/-- **Matrix units generate the type I factor.** The von Neumann algebra generated by the system of -matrix units `e_{pq} = v_p v_q⋆` is `N`. This is the von-Neumann-algebraic form of the structure -theorem `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ -theorem OrthEquivFam.generated_matrixUnits_eq (hF : OrthEquivFam N e F) - (he : IsMinimalProjection N e) - (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : - VonNeumannAlgebra.generated (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) = N := by - set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef - apply le_antisymm - · exact VonNeumannAlgebra.generated_le hF.matrixUnit_subset - · intro a ha - rw [← SetLike.mem_coe] - change a ∈ ((VonNeumannAlgebra.commutantSet S).commutant : Set (H →L[ℂ] H)) - rw [VonNeumannAlgebra.coe_commutant, VonNeumannAlgebra.coe_commutantSet] - have hsub : (S ∪ star S).centralizer ⊆ (N : Set (H →L[ℂ] H)).centralizer := - (Set.centralizer_subset Set.subset_union_left).trans (hF.centralizer_subset_commutant he htop) - have h2 : ((N : Set (H →L[ℂ] H)).centralizer).centralizer - ⊆ ((S ∪ star S).centralizer).centralizer := Set.centralizer_subset hsub - exact h2 (Set.subset_centralizer_centralizer (SetLike.mem_coe.mpr ha)) - -/-- **SOT reconstruction (corollary).** Every `a ∈ N` lies in the strong-operator closure of the -`*`-subalgebra generated by the matrix units. This is the literal `a = Σ_{pq} c_{pq}(a) e_{pq}` -content of the structure theorem, in closure form, obtained from the generation theorem and the SOT -double commutant theorem. -/ -theorem OrthEquivFam.mem_sotClosure_adjoin (hF : OrthEquivFam N e F) - (he : IsMinimalProjection N e) - (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) - {a : H →L[ℂ] H} (ha : a ∈ N) : - (⟨a⟩ : ContinuousLinearMapSOT H) ∈ closure (Set.toSOT - (StarAlgebra.adjoin ℂ (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) : - Set (H →L[ℂ] H))) := by - set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef - apply SOTClosedSubalgebra.mem_sotClosure_of_mem_doubleCommutant (StarAlgebra.adjoin ℂ S) a - have hunion : S ∪ star S ⊆ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := by - refine Set.union_subset (StarAlgebra.subset_adjoin ℂ S) ?_ - intro y hy - rw [Set.mem_star] at hy - have hya : star y ∈ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := - StarAlgebra.subset_adjoin ℂ S hy - have := star_mem (s := StarAlgebra.adjoin ℂ S) hya - rwa [star_star] at this - have hgen : (VonNeumannAlgebra.generated S : Set (H →L[ℂ] H)) - = Set.centralizer (Set.centralizer (S ∪ star S)) := by - change ((VonNeumannAlgebra.commutantSet S).commutant : Set (H →L[ℂ] H)) = _ - rw [VonNeumannAlgebra.coe_commutant, VonNeumannAlgebra.coe_commutantSet] - have hmono : Set.centralizer (Set.centralizer (S ∪ star S)) - ⊆ Set.centralizer (Set.centralizer (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H))) := - Set.centralizer_subset (Set.centralizer_subset hunion) - apply hmono - have hmem : a ∈ (VonNeumannAlgebra.generated S : Set (H →L[ℂ] H)) := by - rw [hF.generated_matrixUnits_eq he htop]; exact SetLike.mem_coe.mpr ha - rwa [hgen] at hmem - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean deleted file mode 100644 index 1ad22cd..0000000 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/MatrixUnits.lean +++ /dev/null @@ -1,149 +0,0 @@ -module - -public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily - -/-! -# Matrix units of a type I factor and the multiplicity-one property - -For a covering orthogonal family `F` of projections each Murray–von Neumann equivalent to the -minimal projection `e` (produced by `IsFactor.exists_orthEquivFam_top`; the members are minimal as -a consequence, though `OrthEquivFam` only records that each is a nonzero star projection in `N` -equivalent to `e`), this file builds the **system of matrix units** `e_{pq} = v_p v_q⋆` from the -equivalence partial isometries `v_p : e ≅ p`, and proves the -defining matrix-unit relations. It then establishes the **multiplicity-one** property: for every -`a ∈ N`, the matrix entry `v_p⋆ a v_q` is a *scalar* multiple of `e` (a direct consequence of the -corner condition `e N e = ℂ e` defining a minimal projection). - -Together these say that `N` is, algebraically, the `*`-algebra of `F × F` matrices over `ℂ` — the -algebraic heart of the structure theorem `N ≅ B(ℓ²(F)) ⊗̄ 1`. The remaining (analytic) step is the -strong-operator convergence of `a = Σ_{pq} c_{pq}(a) e_{pq}` and the identification with -`vnTensorLeft`. - -## Main definitions - -* `VonNeumannAlgebra.OrthEquivFam.pisom` — a choice of equivalence partial isometry `v_p : e ≅ p`. -* `VonNeumannAlgebra.OrthEquivFam.matrixUnit` — the matrix unit `e_{pq} = v_p v_q⋆`. - -## Main results - -* `matrixUnit_mul_of_eq` / `matrixUnit_mul_of_ne` — the matrix-unit multiplication law - `e_{pq} e_{rs} = δ_{qr} e_{ps}`. -* `OrthEquivFam.exists_matrixEntry` — multiplicity one: `∃ c, v_p⋆ a v_q = c • e` for `a ∈ N`. --/ - -@[expose] public section - -namespace VonNeumannAlgebra - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] -variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} - -/-- A choice of partial isometry `v_p` implementing the Murray–von Neumann equivalence `e ∼[N] p`, -oriented with source projection `v_p⋆ v_p = e` (`pisom_source`) and range projection -`v_p v_p⋆ = p` (`pisom_range`). -/ -noncomputable def OrthEquivFam.pisom (hF : OrthEquivFam N e F) (p : F) : H →L[ℂ] H := - (hF.1 p.1 p.2).2.2.2.choose - -lemma OrthEquivFam.pisom_mem (hF : OrthEquivFam N e F) (p : F) : hF.pisom p ∈ N := - (hF.1 p.1 p.2).2.2.2.choose_spec.1 - -lemma OrthEquivFam.pisom_isPI (hF : OrthEquivFam N e F) (p : F) : - IsPartialIsometry (hF.pisom p) := - (hF.1 p.1 p.2).2.2.2.choose_spec.2.1 - -lemma OrthEquivFam.pisom_source (hF : OrthEquivFam N e F) (p : F) : - star (hF.pisom p) * hF.pisom p = e := - (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.1 - -lemma OrthEquivFam.pisom_range (hF : OrthEquivFam N e F) (p : F) : - hF.pisom p * star (hF.pisom p) = (p : H →L[ℂ] H) := - (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.2 - -/-- `v_p e = v_p`: the source projection acts as a right unit on `v_p`. -/ -lemma OrthEquivFam.pisom_mul_source (hF : OrthEquivFam N e F) (p : F) : - hF.pisom p * e = hF.pisom p := by - have h : hF.pisom p * (star (hF.pisom p) * hF.pisom p) = hF.pisom p := by - rw [← mul_assoc]; exact hF.pisom_isPI p - rwa [hF.pisom_source p] at h - -/-- `e v_p⋆ = v_p⋆`: the source projection acts as a left unit on `v_p⋆`. -/ -lemma OrthEquivFam.e_mul_star_pisom (hF : OrthEquivFam N e F) (p : F) : - e * star (hF.pisom p) = star (hF.pisom p) := by - have h : star (hF.pisom p) * hF.pisom p * star (hF.pisom p) = star (hF.pisom p) := by - have h' : star (hF.pisom p) * star (star (hF.pisom p)) * star (hF.pisom p) - = star (hF.pisom p) := IsPartialIsometry.star (hF.pisom_isPI p) - rwa [star_star] at h' - rwa [hF.pisom_source p] at h - -/-- For distinct family members the partial isometries are orthogonal: `v_q⋆ v_r = 0`. -/ -lemma OrthEquivFam.star_pisom_mul_pisom_of_ne (hF : OrthEquivFam N e F) {q r : F} - (hqr : q ≠ r) : star (hF.pisom q) * hF.pisom r = 0 := by - have hq : (q : H →L[ℂ] H) * hF.pisom q = hF.pisom q := by - have h : hF.pisom q * star (hF.pisom q) * hF.pisom q = hF.pisom q := hF.pisom_isPI q - rwa [hF.pisom_range q] at h - have hr : (r : H →L[ℂ] H) * hF.pisom r = hF.pisom r := by - have h : hF.pisom r * star (hF.pisom r) * hF.pisom r = hF.pisom r := hF.pisom_isPI r - rwa [hF.pisom_range r] at h - have hsq : star (hF.pisom q) * (q : H →L[ℂ] H) = star (hF.pisom q) := by - have := congrArg star hq - rwa [star_mul, (hF.1 q.1 q.2).1.isSelfAdjoint.star_eq] at this - have h0 : (q : H →L[ℂ] H) * r = 0 := hF.2 q.2 r.2 (fun h => hqr (Subtype.ext h)) - calc star (hF.pisom q) * hF.pisom r - = (star (hF.pisom q) * (q : H →L[ℂ] H)) * ((r : H →L[ℂ] H) * hF.pisom r) := by - rw [hsq, hr] - _ = star (hF.pisom q) * ((q : H →L[ℂ] H) * r) * hF.pisom r := by simp only [mul_assoc] - _ = 0 := by rw [h0, mul_zero, zero_mul] - -/-- The **matrix unit** `e_{pq} = v_p v_q⋆`. -/ -noncomputable def OrthEquivFam.matrixUnit (hF : OrthEquivFam N e F) (p q : F) : H →L[ℂ] H := - hF.pisom p * star (hF.pisom q) - -/-- Definitional unfolding of the matrix unit: `e_{pq} = v_p v_q⋆`. -/ -lemma OrthEquivFam.matrixUnit_def (hF : OrthEquivFam N e F) (p q : F) : - hF.matrixUnit p q = hF.pisom p * star (hF.pisom q) := rfl - -/-- Matrix units lie in `N`. -/ -lemma OrthEquivFam.matrixUnit_mem (hF : OrthEquivFam N e F) (p q : F) : - hF.matrixUnit p q ∈ N := - mul_mem (hF.pisom_mem p) (star_mem (hF.pisom_mem q)) - -/-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, diagonal case `q = r`: -`e_{pq} e_{qs} = e_{ps}`. -/ -theorem OrthEquivFam.matrixUnit_mul_of_eq (hF : OrthEquivFam N e F) (p q s : F) : - hF.matrixUnit p q * hF.matrixUnit q s = hF.matrixUnit p s := by - rw [matrixUnit_def, matrixUnit_def, matrixUnit_def] - calc hF.pisom p * star (hF.pisom q) * (hF.pisom q * star (hF.pisom s)) - = hF.pisom p * (star (hF.pisom q) * hF.pisom q) * star (hF.pisom s) := by - simp only [mul_assoc] - _ = hF.pisom p * e * star (hF.pisom s) := by rw [hF.pisom_source q] - _ = hF.pisom p * star (hF.pisom s) := by rw [hF.pisom_mul_source p] - -/-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, off-diagonal case `q ≠ r`: -`e_{pq} e_{rs} = 0`. -/ -theorem OrthEquivFam.matrixUnit_mul_of_ne (hF : OrthEquivFam N e F) (p s : F) {q r : F} - (hqr : q ≠ r) : hF.matrixUnit p q * hF.matrixUnit r s = 0 := by - rw [matrixUnit_def, matrixUnit_def] - calc hF.pisom p * star (hF.pisom q) * (hF.pisom r * star (hF.pisom s)) - = hF.pisom p * (star (hF.pisom q) * hF.pisom r) * star (hF.pisom s) := by - simp only [mul_assoc] - _ = 0 := by rw [hF.star_pisom_mul_pisom_of_ne hqr, mul_zero, zero_mul] - -/-- **Multiplicity one.** For a minimal projection `e` and any `a ∈ N`, the matrix entry -`v_p⋆ a v_q` is a scalar multiple of `e`. This is the corner condition `e N e = ℂ e` transported -along the equivalences, and is the algebraic content of `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ -theorem OrthEquivFam.exists_matrixEntry (hF : OrthEquivFam N e F) - (he : IsMinimalProjection N e) (p q : F) {a : H →L[ℂ] H} (ha : a ∈ N) : - ∃ c : ℂ, star (hF.pisom p) * a * hF.pisom q = c • e := by - have hbN : star (hF.pisom p) * a * hF.pisom q ∈ N := - mul_mem (mul_mem (star_mem (hF.pisom_mem p)) ha) (hF.pisom_mem q) - obtain ⟨c, hc⟩ := he.2.2.2 _ hbN - refine ⟨c, ?_⟩ - have key : e * (star (hF.pisom p) * a * hF.pisom q) * e - = star (hF.pisom p) * a * hF.pisom q := by - calc e * (star (hF.pisom p) * a * hF.pisom q) * e - = (e * star (hF.pisom p)) * a * (hF.pisom q * e) := by simp only [mul_assoc] - _ = star (hF.pisom p) * a * hF.pisom q := by - rw [hF.e_mul_star_pisom p, hF.pisom_mul_source q] - rw [← key, hc] - -end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean index 77367b2..0d07378 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean @@ -1,28 +1,72 @@ module -public import QuantumSystem.Algebra.VonNeumannAlgebra.CoveringFamily +public import QuantumSystem.Algebra.VonNeumannAlgebra.Basic public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion +public import Mathlib.Analysis.InnerProductSpace.Projection.Basic public import Mathlib.Analysis.InnerProductSpace.Adjoint public import Mathlib.Analysis.InnerProductSpace.l2Space /-! -# Spatial decomposition: partial-isometry-induced isometries between projection ranges +# Spatial decomposition of a type I factor -This file begins the spatial half of the type I factor structure theorem. A partial isometry `v` -with source projection `p = v⋆v` and range projection `q = vv⋆` restricts to a linear isometric -equivalence between the closed subspaces `range p` and `range q`. For a family of projections -each Murray–von Neumann equivalent to a fixed minimal projection `e`, these isometries identify -every summand `range eᵢ` with the multiplicity space `range e`, the first step in building the -spatial isomorphism `H ≅ ℓ²(I) ⊗̂ (eH)`. +This file assembles the proof ingredients of the type I factor structure theorem +`N ≅ B(ℓ²(F)) ⊗̄ 1` up to the spatial decomposition `H ≅ ℓ²(F) ⊗̂ (eH)`: + +1. **Covering family.** For a factor `N` with minimal projection `e`, Zorn's lemma and the + comparison theorem `IsMinimalProjection.mvNSub_of_isFactor` produce a family of mutually + orthogonal projections, each Murray–von Neumann equivalent to `e`, whose ranges span densely — + the projection-theoretic backbone `Σ eᵢ = 1` of the structure theorem. +2. **Matrix units.** From the equivalence partial isometries `v_p : e ≅ p` the system of **matrix + units** `e_{pq} = v_p v_q⋆` is built, with the defining matrix-unit relations, and the + **multiplicity-one** property: for every `a ∈ N` the matrix entry `v_p⋆ a v_q` is a *scalar* + multiple of `e` (a direct consequence of the corner condition `e N e = ℂ e` defining a minimal + projection). Together these say that `N` is, algebraically, the `*`-algebra of `F × F` matrices + over `ℂ` — the algebraic heart of the structure theorem. +3. **Spatial ℓ² decomposition.** A partial isometry `v` with source projection `p = v⋆v` and range + projection `q = vv⋆` restricts to a linear isometric equivalence between the closed subspaces + `range p` and `range q`. These isometries identify every summand `range eᵢ` with the + multiplicity space `range e`, giving `H ≅ ℓ²(F; eH)` and, through the tensor bridge + `HilbertTensor.lpTensorEquiv`, the literal tensor form `H ≅ ℓ²(F) ⊗̂ (eH)`. + +The remaining steps — the strong-operator reconstruction `a = Σ_{pq} c_{pq}(a) e_{pq}` (in its +double-commutant form: the matrix units generate `N`) and the identification of `N` with +`B(ℓ²(F)) ⊗̄ 1` under the spatial isomorphism — are carried out in +`QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem`. + +## Conventions + +The dense span of the ranges is expressed as +`(Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤`, i.e. the closed linear +span of the union of the ranges is the whole space; this is the operator-friendly form of +`⨆ᵢ ranges = 1` and matches the central-support construction `IsFactor.exists_mul_ne`. + +`OrthEquivFam` only records that each member is a nonzero star projection in `N` equivalent to +`e`; when `e` is minimal the members are minimal as a consequence +(`OrthEquivFam.isMinimalProjection_of_mem`). + +## Main definitions + +* `VonNeumannAlgebra.OrthEquivFam N e F` — `F` is a set of pairwise-orthogonal nonzero projections + in `N`, each Murray–von Neumann equivalent to `e`. +* `VonNeumannAlgebra.OrthEquivFam.pisom` — a choice of equivalence partial isometry `v_p : e ≅ p`. +* `VonNeumannAlgebra.OrthEquivFam.matrixUnit` — the matrix unit `e_{pq} = v_p v_q⋆`. +* `VonNeumannAlgebra.OrthEquivFam.multiplicityEquiv` — the spatial isomorphism `H ≅ ℓ²(F; eH)`. ## Main results +* `VonNeumannAlgebra.IsFactor.exists_orthEquivFam_top` — in a factor, there is a maximal + orthogonal family of `e`-equivalent projections whose ranges have dense span. +* `VonNeumannAlgebra.OrthEquivFam.matrixUnit_mul_of_eq` / `matrixUnit_mul_of_ne` — the matrix-unit + multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`. +* `VonNeumannAlgebra.OrthEquivFam.exists_matrixEntry` — multiplicity one: + `∃ c, v_p⋆ a v_q = c • e` for `a ∈ N`. * `IsPartialIsometry.sourceRangeEquiv` — the isometric equivalence `range (v⋆v) ≃ₗᵢ range (vv⋆)` induced by a partial isometry `v`. -* `IsFactor.exists_tensor_decomposition` — the `ℓ²`-sum form `H ≅ ℓ²(F; eH)` of the spatial - decomposition of a type I factor. -* `IsFactor.exists_tmul_decomposition` — the literal tensor form `H ≅ ℓ²(F) ⊗̂ (eH)`, obtained by - composing with the tensor bridge `HilbertTensor.lpTensorEquiv`. +* `VonNeumannAlgebra.IsFactor.exists_tensor_decomposition` — the `ℓ²`-sum form `H ≅ ℓ²(F; eH)` of + the spatial decomposition of a type I factor. +* `VonNeumannAlgebra.IsFactor.exists_tmul_decomposition` — the literal tensor form + `H ≅ ℓ²(F) ⊗̂ (eH)`, obtained by composing with the tensor bridge + `HilbertTensor.lpTensorEquiv`. -/ @[expose] public section @@ -31,6 +75,293 @@ open scoped ENNReal variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] +/-! ### Covering families of `e`-equivalent projections -/ + +namespace VonNeumannAlgebra + +/-- The range projection of a Murray–von Neumann equivalence with nonzero source is nonzero. -/ +lemma MvNEquiv.ne_zero {N : VonNeumannAlgebra H} {p q : H →L[ℂ] H} + (h : p ∼[N] q) (hp : p ≠ 0) : q ≠ 0 := by + obtain ⟨v, _, hvpi, hvp, hvq⟩ := h + intro hq0 + apply hp + have hv0 : v = 0 := by + have hpi : v * star v * v = v := hvpi + rw [hvq, hq0, zero_mul] at hpi + exact hpi.symm + rw [← hvp, hv0]; simp + +/-- **Minimality transports along Murray–von Neumann equivalence.** If `e` is a minimal projection +and `e ∼[N] p`, then `p` is minimal: with `v⋆v = e` and `vv⋆ = p`, the corner computes as +`p a p = v (e (v⋆ a v) e) v⋆ = c • v e v⋆ = c • p`. -/ +lemma IsMinimalProjection.of_mvNEquiv {N : VonNeumannAlgebra H} {e p : H →L[ℂ] H} + (he : IsMinimalProjection N e) (h : e ∼[N] p) : IsMinimalProjection N p := by + have hpproj : IsStarProjection p := h.isStarProjection_right + have hp0 : p ≠ 0 := h.ne_zero he.2.2.1 + obtain ⟨v, hvN, hvpi, hvp, hvq⟩ := h + have hpN : p ∈ N := by rw [← hvq]; exact mul_mem hvN (star_mem hvN) + have hve : v * e = v := by rw [← hvp]; exact IsPartialIsometry.mul_source hvpi + have hev : e * star v = star v := by + have := congrArg star hve + rwa [star_mul, he.1.isSelfAdjoint.star_eq] at this + refine ⟨hpproj, hpN, hp0, fun a haN => ?_⟩ + obtain ⟨c, hc⟩ := he.2.2.2 (star v * a * v) (mul_mem (mul_mem (star_mem hvN) haN) hvN) + refine ⟨c, ?_⟩ + calc p * a * p + = (v * star v) * a * (v * star v) := by rw [hvq] + _ = (v * e) * (star v * a * v) * (e * star v) := by + rw [hve, hev]; simp only [mul_assoc] + _ = v * (e * (star v * a * v) * e) * star v := by simp only [mul_assoc] + _ = v * (c • e) * star v := by rw [hc] + _ = c • (v * e * star v) := by simp only [mul_smul_comm, smul_mul_assoc] + _ = c • p := by rw [hve, hvq] + +/-- A family of pairwise-orthogonal nonzero projections in `N`, each Murray–von Neumann equivalent +to `e`. -/ +def OrthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ℂ] H)) : Prop := + (∀ p ∈ F, IsStarProjection p ∧ p ∈ N ∧ p ≠ 0 ∧ e ∼[N] p) ∧ + F.Pairwise (fun p q => p * q = 0) + +/-- When `e` is minimal, every member of an `OrthEquivFam` for `e` is itself a minimal +projection, since minimality transports along `∼[N]` (`IsMinimalProjection.of_mvNEquiv`). -/ +lemma OrthEquivFam.isMinimalProjection_of_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) + {p : H →L[ℂ] H} (hp : p ∈ F) : IsMinimalProjection N p := + he.of_mvNEquiv (hF.1 p hp).2.2.2 + +/-- By Zorn's lemma, there is a maximal orthogonal family of `e`-equivalent projections. -/ +lemma exists_maximal_orthEquivFam (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : + ∃ F, OrthEquivFam N e F ∧ ∀ G, OrthEquivFam N e G → F ⊆ G → G ⊆ F := by + obtain ⟨F, hFmax⟩ := zorn_subset {F | OrthEquivFam N e F} (by + intro c hcsub hchain + refine ⟨⋃₀ c, ⟨?_, ?_⟩, fun s hs => Set.subset_sUnion_of_mem hs⟩ + · rintro p ⟨s, hsc, hps⟩; exact (hcsub hsc).1 p hps + · rintro p ⟨s, hsc, hps⟩ q ⟨t, htc, hqt⟩ hpq + rcases hchain.total hsc htc with h | h + · exact (hcsub htc).2 (h hps) hqt hpq + · exact (hcsub hsc).2 hps (h hqt) hpq) + exact ⟨F, hFmax.1, fun G hG hFG => hFmax.2 hG hFG⟩ + +/-- The orthogonal projection onto the closed span of the ranges of an `OrthEquivFam` lies in `N`, +because that subspace is invariant under the commutant `N'`: for `y ∈ N'` and `f ∈ F ⊆ N`, +`y (f x) = (y f) x = (f y) x = f (y x)` lies in the range of `f`. -/ +lemma OrthEquivFam.starProjection_mem {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} + {F : Set (H →L[ℂ] H)} (hF : OrthEquivFam N e F) : + (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure.starProjection ∈ N := by + set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS + set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM + set p : H →L[ℂ] H := M.starProjection with hp + have hpproj : IsStarProjection p := isStarProjection_starProjection + rw [IsStarProjection.mem_iff hpproj N] + intro y hyN' + rw [hp, Submodule.range_starProjection] + have hcl : IsClosed ((M.comap (y : H →ₗ[ℂ] H)) : Set H) := by + rw [Submodule.comap_coe] + exact ((Submodule.span ℂ S).isClosed_topologicalClosure).preimage y.continuous + have hle : M ≤ M.comap (y : H →ₗ[ℂ] H) := by + refine Submodule.topologicalClosure_minimal (Submodule.span ℂ S) ?_ hcl + rw [Submodule.span_le] + rintro s ⟨f, hf, x, rfl⟩ + simp only [Submodule.comap_coe, Set.mem_preimage, SetLike.mem_coe, ContinuousLinearMap.coe_coe] + have hfy : f * y = y * f := mem_commutant_iff.mp hyN' f (hF.1 f hf).2.1 + rw [show y (f x) = (y * f) x from rfl, ← hfy] + exact Submodule.le_topologicalClosure _ (Submodule.subset_span ⟨f, hf, y x, rfl⟩) + exact hle + +/-- **Covering family of minimal projections (factor case).** In a factor, there is a family `F` +of pairwise-orthogonal nonzero projections in `N`, each equivalent to the minimal projection `e`, +whose ranges span densely: the closed linear span of the union of their ranges is `⊤`. This is the +`Σ eᵢ = 1` input of the type I structure theorem. + +The proof takes a *maximal* such family `F` (Zorn) and lets `p` be the orthogonal projection onto +the closed span `M` of the ranges; `p ∈ N`. If `M ≠ ⊤` then `r = 1 - p` is a nonzero projection in +`N`, so by the comparison theorem some nonzero `q' ≼ r` is equivalent to `e`; `q'` is orthogonal to +every `f ∈ F`, contradicting maximality. -/ +theorem IsFactor.exists_orthEquivFam_top [Nontrivial H] {N : VonNeumannAlgebra H} + (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : + ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ + (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ := by + obtain ⟨F, hF, hFmax⟩ := exists_maximal_orthEquivFam N e + refine ⟨F, hF, ?_⟩ + set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS + set M : Submodule ℂ H := (Submodule.span ℂ S).topologicalClosure with hM + set p : H →L[ℂ] H := M.starProjection with hp + have hpproj : IsStarProjection p := isStarProjection_starProjection + have hpN : p ∈ N := hF.starProjection_mem + have hpf : ∀ f ∈ F, p * f = f := by + intro f hf + ext x + simp only [ContinuousLinearMap.mul_apply, hp] + rw [Submodule.starProjection_eq_self_iff] + exact Submodule.le_topologicalClosure _ (Submodule.subset_span ⟨f, hf, x, rfl⟩) + by_contra hMtop + set r : H →L[ℂ] H := 1 - p with hr + have hrproj : IsStarProjection r := by + refine ⟨?_, ?_⟩ + · change (1 - p) * (1 - p) = 1 - p + rw [mul_sub, sub_mul, sub_mul, one_mul, one_mul, mul_one, hpproj.isIdempotentElem, + sub_self, sub_zero] + · change star (1 - p) = 1 - p + rw [star_sub, star_one, hpproj.isSelfAdjoint.star_eq] + have hrN : r ∈ N := by rw [hr]; exact sub_mem (one_mem _) hpN + have hr0 : r ≠ 0 := by + intro h + apply hMtop + have hp1 : p = 1 := by rw [hr, sub_eq_zero] at h; exact h.symm + have hMrange : M = p.range := (Submodule.range_starProjection M).symm + rw [hMrange, hp1] + exact Submodule.eq_top_iff'.2 fun y => ⟨y, rfl⟩ + obtain ⟨q', hq'N, hrq', heq'⟩ := he.mvNSub_of_isFactor hN hrproj hrN hr0 + have hq'proj : IsStarProjection q' := heq'.isStarProjection_right + have hq'0 : q' ≠ 0 := heq'.ne_zero he.2.2.1 + have hpq' : p * q' = 0 := by + have h := hrq' + rw [hr, sub_mul, one_mul, sub_eq_self] at h + exact h + have horth : ∀ f ∈ F, q' * f = 0 ∧ f * q' = 0 := by + intro f hf + have hq'p : q' * p = 0 := by + have h := congrArg star hpq' + rwa [star_mul, hq'proj.isSelfAdjoint.star_eq, hpproj.isSelfAdjoint.star_eq, star_zero] at h + have h1 : q' * f = 0 := by + calc q' * f = q' * (p * f) := by rw [hpf f hf] + _ = (q' * p) * f := by rw [mul_assoc] + _ = 0 := by rw [hq'p, zero_mul] + refine ⟨h1, ?_⟩ + have h := congrArg star h1 + rwa [star_mul, (hF.1 f hf).1.isSelfAdjoint.star_eq, hq'proj.isSelfAdjoint.star_eq, + star_zero] at h + have hq'notF : q' ∉ F := fun hq'F => + hq'0 (by have := (horth q' hq'F).1; rwa [hq'proj.isIdempotentElem] at this) + have hbigger : OrthEquivFam N e (insert q' F) := by + refine ⟨?_, ?_⟩ + · rintro x (rfl | hx) + · exact ⟨hq'proj, hq'N, hq'0, heq'⟩ + · exact hF.1 x hx + · rintro x (rfl | hx) z (rfl | hz) hxz + · exact absurd rfl hxz + · exact (horth z hz).1 + · exact (horth x hx).2 + · exact hF.2 hx hz hxz + have hsub := hFmax (insert q' F) hbigger (Set.subset_insert _ _) + exact hq'notF (hsub (Set.mem_insert _ _)) + +/-! ### Matrix units and the multiplicity-one property -/ + +variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} + +/-- A choice of partial isometry `v_p` implementing the Murray–von Neumann equivalence `e ∼[N] p`, +oriented with source projection `v_p⋆ v_p = e` (`pisom_source`) and range projection +`v_p v_p⋆ = p` (`pisom_range`). -/ +noncomputable def OrthEquivFam.pisom (hF : OrthEquivFam N e F) (p : F) : H →L[ℂ] H := + (hF.1 p.1 p.2).2.2.2.choose + +lemma OrthEquivFam.pisom_mem (hF : OrthEquivFam N e F) (p : F) : hF.pisom p ∈ N := + (hF.1 p.1 p.2).2.2.2.choose_spec.1 + +lemma OrthEquivFam.pisom_isPI (hF : OrthEquivFam N e F) (p : F) : + IsPartialIsometry (hF.pisom p) := + (hF.1 p.1 p.2).2.2.2.choose_spec.2.1 + +lemma OrthEquivFam.pisom_source (hF : OrthEquivFam N e F) (p : F) : + star (hF.pisom p) * hF.pisom p = e := + (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.1 + +lemma OrthEquivFam.pisom_range (hF : OrthEquivFam N e F) (p : F) : + hF.pisom p * star (hF.pisom p) = (p : H →L[ℂ] H) := + (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.2 + +/-- `v_p e = v_p`: the source projection acts as a right unit on `v_p`. -/ +lemma OrthEquivFam.pisom_mul_source (hF : OrthEquivFam N e F) (p : F) : + hF.pisom p * e = hF.pisom p := by + have h : hF.pisom p * (star (hF.pisom p) * hF.pisom p) = hF.pisom p := by + rw [← mul_assoc]; exact hF.pisom_isPI p + rwa [hF.pisom_source p] at h + +/-- `e v_p⋆ = v_p⋆`: the source projection acts as a left unit on `v_p⋆`. -/ +lemma OrthEquivFam.e_mul_star_pisom (hF : OrthEquivFam N e F) (p : F) : + e * star (hF.pisom p) = star (hF.pisom p) := by + have h : star (hF.pisom p) * hF.pisom p * star (hF.pisom p) = star (hF.pisom p) := by + have h' : star (hF.pisom p) * star (star (hF.pisom p)) * star (hF.pisom p) + = star (hF.pisom p) := IsPartialIsometry.star (hF.pisom_isPI p) + rwa [star_star] at h' + rwa [hF.pisom_source p] at h + +/-- For distinct family members the partial isometries are orthogonal: `v_q⋆ v_r = 0`. -/ +lemma OrthEquivFam.star_pisom_mul_pisom_of_ne (hF : OrthEquivFam N e F) {q r : F} + (hqr : q ≠ r) : star (hF.pisom q) * hF.pisom r = 0 := by + have hq : (q : H →L[ℂ] H) * hF.pisom q = hF.pisom q := by + have h : hF.pisom q * star (hF.pisom q) * hF.pisom q = hF.pisom q := hF.pisom_isPI q + rwa [hF.pisom_range q] at h + have hr : (r : H →L[ℂ] H) * hF.pisom r = hF.pisom r := by + have h : hF.pisom r * star (hF.pisom r) * hF.pisom r = hF.pisom r := hF.pisom_isPI r + rwa [hF.pisom_range r] at h + have hsq : star (hF.pisom q) * (q : H →L[ℂ] H) = star (hF.pisom q) := by + have := congrArg star hq + rwa [star_mul, (hF.1 q.1 q.2).1.isSelfAdjoint.star_eq] at this + have h0 : (q : H →L[ℂ] H) * r = 0 := hF.2 q.2 r.2 (fun h => hqr (Subtype.ext h)) + calc star (hF.pisom q) * hF.pisom r + = (star (hF.pisom q) * (q : H →L[ℂ] H)) * ((r : H →L[ℂ] H) * hF.pisom r) := by + rw [hsq, hr] + _ = star (hF.pisom q) * ((q : H →L[ℂ] H) * r) * hF.pisom r := by simp only [mul_assoc] + _ = 0 := by rw [h0, mul_zero, zero_mul] + +/-- The **matrix unit** `e_{pq} = v_p v_q⋆`. -/ +noncomputable def OrthEquivFam.matrixUnit (hF : OrthEquivFam N e F) (p q : F) : H →L[ℂ] H := + hF.pisom p * star (hF.pisom q) + +/-- Definitional unfolding of the matrix unit: `e_{pq} = v_p v_q⋆`. -/ +lemma OrthEquivFam.matrixUnit_def (hF : OrthEquivFam N e F) (p q : F) : + hF.matrixUnit p q = hF.pisom p * star (hF.pisom q) := rfl + +/-- Matrix units lie in `N`. -/ +lemma OrthEquivFam.matrixUnit_mem (hF : OrthEquivFam N e F) (p q : F) : + hF.matrixUnit p q ∈ N := + mul_mem (hF.pisom_mem p) (star_mem (hF.pisom_mem q)) + +/-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, diagonal case `q = r`: +`e_{pq} e_{qs} = e_{ps}`. -/ +theorem OrthEquivFam.matrixUnit_mul_of_eq (hF : OrthEquivFam N e F) (p q s : F) : + hF.matrixUnit p q * hF.matrixUnit q s = hF.matrixUnit p s := by + rw [matrixUnit_def, matrixUnit_def, matrixUnit_def] + calc hF.pisom p * star (hF.pisom q) * (hF.pisom q * star (hF.pisom s)) + = hF.pisom p * (star (hF.pisom q) * hF.pisom q) * star (hF.pisom s) := by + simp only [mul_assoc] + _ = hF.pisom p * e * star (hF.pisom s) := by rw [hF.pisom_source q] + _ = hF.pisom p * star (hF.pisom s) := by rw [hF.pisom_mul_source p] + +/-- Matrix-unit multiplication law `e_{pq} e_{rs} = δ_{qr} e_{ps}`, off-diagonal case `q ≠ r`: +`e_{pq} e_{rs} = 0`. -/ +theorem OrthEquivFam.matrixUnit_mul_of_ne (hF : OrthEquivFam N e F) (p s : F) {q r : F} + (hqr : q ≠ r) : hF.matrixUnit p q * hF.matrixUnit r s = 0 := by + rw [matrixUnit_def, matrixUnit_def] + calc hF.pisom p * star (hF.pisom q) * (hF.pisom r * star (hF.pisom s)) + = hF.pisom p * (star (hF.pisom q) * hF.pisom r) * star (hF.pisom s) := by + simp only [mul_assoc] + _ = 0 := by rw [hF.star_pisom_mul_pisom_of_ne hqr, mul_zero, zero_mul] + +/-- **Multiplicity one.** For a minimal projection `e` and any `a ∈ N`, the matrix entry +`v_p⋆ a v_q` is a scalar multiple of `e`. This is the corner condition `e N e = ℂ e` transported +along the equivalences, and is the algebraic content of `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ +theorem OrthEquivFam.exists_matrixEntry (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) (p q : F) {a : H →L[ℂ] H} (ha : a ∈ N) : + ∃ c : ℂ, star (hF.pisom p) * a * hF.pisom q = c • e := by + have hbN : star (hF.pisom p) * a * hF.pisom q ∈ N := + mul_mem (mul_mem (star_mem (hF.pisom_mem p)) ha) (hF.pisom_mem q) + obtain ⟨c, hc⟩ := he.2.2.2 _ hbN + refine ⟨c, ?_⟩ + have key : e * (star (hF.pisom p) * a * hF.pisom q) * e + = star (hF.pisom p) * a * hF.pisom q := by + calc e * (star (hF.pisom p) * a * hF.pisom q) * e + = (e * star (hF.pisom p)) * a * (hF.pisom q * e) := by simp only [mul_assoc] + _ = star (hF.pisom p) * a * hF.pisom q := by + rw [hF.e_mul_star_pisom p, hF.pisom_mul_source q] + rw [← key, hc] + +end VonNeumannAlgebra + +/-! ### Partial-isometry isometries and the spatial ℓ² decomposition -/ + section LpCongr variable {α : Type*} {𝕜 : Type*} [RCLike 𝕜] {G G' : α → Type*} diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean similarity index 65% rename from QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean rename to QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean index 6e8edf2..3a72219 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorIdentification.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean @@ -1,23 +1,52 @@ module -public import QuantumSystem.Algebra.VonNeumannAlgebra.GeneratedByMatrixUnits +public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor +public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import Mathlib.Algebra.Star.Subalgebra /-! -# Spatial identification of a type I factor with `B(H₁) ⊗̄ 1` +# The structure theorem for type I factors -This file completes the spatial structure theorem for a type I factor `N ⊆ B(H)` with minimal +This file proves the spatial structure theorem for a type I factor `N ⊆ B(H)` with minimal projection `e`: there is a linear isometric equivalence `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` under which `N` becomes exactly the tensor factor `B(ℓ²(F)) ⊗̄ 1` and `N'` becomes the right factor `1 ⊗̄ B(eH)`. - -The identification glues the generation theorem `N = ⟨matrix units⟩''` (`GeneratedByMatrixUnits`) -to the tensor commutation theorem (`Algebra.VonNeumannAlgebra.TensorFactor`) through the spatial isomorphism -`U = multiplicityEquiv ∘ lpTensorEquiv`. The key computation is that `U` carries the matrix unit -`e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨δ_q| ⊗̂ 1`, where `δ_p = lp.single 2 p 1` is the -`p`-th standard basis vector of `ℓ²(F)`. +The ingredients — the covering orthogonal family `F` (`OrthEquivFam`), the matrix units +`e_{pq} = v_p v_q⋆`, and the spatial isomorphism `multiplicityEquiv` — are built in +`QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition`. The proof here has two halves. + +**Generation half.** The system of matrix units generates `N` as a von Neumann algebra: + +> `VonNeumannAlgebra.generated S = N`, where `S = { e_{pq} | p q : F }`. + +This is the von-Neumann-algebraic (double-commutant) reformulation of the strong-operator +reconstruction `a = Σ_{pq} c_{pq}(a) e_{pq}`. The reformulation avoids any strong/weak-operator +infinite-sum API (which Mathlib lacks) by working through the commutant: the inclusion `S'' ⊆ N` +is monotonicity, and the content `N ⊆ S''` is the statement that every operator commuting with all +matrix units commutes with all of `N`. The proof of that content +(`commutes_of_mem_centralizer`) is genuinely analytic: it inserts the resolution of the identity +`Σ_r p_r = 1` (here `p_r = e_{rr} = v_r v_r⋆`) as a `HasSum`, and uses that each `↑p · a · ↑r` is +a *scalar* multiple of the matrix unit `e_{pr}` (multiplicity one, `exists_matrixEntry`), hence +commutes with `b`. The sum over the possibly-infinite index set `F` is handled throughout by +`HasSum`/`HasSum.mapL`/`HasSum.unique`; no operator-level infinite series is formed. + +**Identification half.** The identification glues the generation theorem `N = ⟨matrix units⟩''` +to the tensor commutation theorem (`QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`) through +the spatial isomorphism `U = multiplicityEquiv ∘ lpTensorEquiv`. The key computation is that `U` +carries the matrix unit `e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨δ_q| ⊗̂ 1`, where +`δ_p = lp.single 2 p 1` is the `p`-th standard basis vector of `ℓ²(F)`. ## Main results +* `VonNeumannAlgebra.OrthEquivFam.hasSum_resolutionOfIdentity` — the resolution of the identity + `HasSum (fun i : F => (↑i) y) y`, the analytic core. +* `VonNeumannAlgebra.OrthEquivFam.commutes_of_mem_centralizer` — an operator commuting with every + matrix unit commutes with every element of `N`. +* `VonNeumannAlgebra.OrthEquivFam.generated_matrixUnits_eq` — **the matrix units generate `N`**: + `generated S = N`. +* `VonNeumannAlgebra.OrthEquivFam.mem_sotClosure_adjoin` — the literal SOT-reconstruction corollary: + every `a ∈ N` lies in the SOT-closure of the `*`-subalgebra generated by the matrix units. * `VonNeumannAlgebra.OrthEquivFam.coe_multiplicityEquiv_apply` — the explicit `i`-th coordinate of `U y`: `(multiplicityEquiv y) i = v_i⋆ y`. * `VonNeumannAlgebra.OrthEquivFam.hasSum_tmul_spatialEquiv` — the resulting expansion @@ -37,11 +66,172 @@ open scoped TensorProduct namespace VonNeumannAlgebra -open HilbertTensor +open StrongOperatorTopology HilbertTensor variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] variable {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} {F : Set (H →L[ℂ] H)} +/-! ### The matrix units generate the factor -/ + +/-- The set of matrix units is contained in `N`. -/ +lemma OrthEquivFam.matrixUnit_subset (hF : OrthEquivFam N e F) : + Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) ⊆ (N : Set (H →L[ℂ] H)) := by + rintro x ⟨pq, rfl⟩ + exact hF.matrixUnit_mem pq.1 pq.2 + +/-- **Resolution of the identity.** For a covering orthogonal family, the projections `↑i` sum to +the identity in the strong operator sense: `HasSum (fun i : F => (↑i) y) y` for every `y`. This is +the analytic heart of the generation theorem; it is the Hilbert-sum reconstruction of `y` from its +coordinates, with the `i`-th coordinate recognised as the orthogonal projection `(↑i) y` by +`coe_hilbertSumEquiv_apply`. -/ +theorem OrthEquivFam.hasSum_resolutionOfIdentity (hF : OrthEquivFam N e F) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) (y : H) : + HasSum (fun i : F => (i : H →L[ℂ] H) y) y := by + have hdecomp : HasSum + (fun i : F => ((hF.hilbertSumEquiv htop y i : + LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) : H)) y := by + have h := (hF.isHilbertSum htop).hasSum_linearIsometryEquiv_symm (hF.hilbertSumEquiv htop y) + have hy : (hF.isHilbertSum htop).linearIsometryEquiv.symm (hF.hilbertSumEquiv htop y) = y := + (hF.hilbertSumEquiv htop).symm_apply_apply y + rwa [hy] at h + simpa only [hF.coe_hilbertSumEquiv_apply htop y] using hdecomp + +/-- **The content of the generation theorem.** Any operator `b` commuting with every matrix unit +commutes with every `a ∈ N`. Equivalently `Set.centralizer S ⊆ Set.centralizer N`, which is the +nontrivial inclusion `N ⊆ S''`. + +The proof tests `a * b = b * a` against arbitrary inner products. Inserting the resolution of the +identity `Σ_r p_r = 1` between and around `a`, the commutator reduces to the family of operators +`↑p · a · ↑r`, each of which equals a *scalar* multiple of the matrix unit `e_{pr}` +(`exists_matrixEntry`) and therefore commutes with `b`. -/ +theorem OrthEquivFam.commutes_of_mem_centralizer (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + {a : H →L[ℂ] H} (ha : a ∈ N) {b : H →L[ℂ] H} + (hb : b ∈ Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2))) : + a * b = b * a := by + have hbcomm : ∀ p q : F, hF.matrixUnit p q * b = b * hF.matrixUnit p q := + fun p q => (Set.mem_centralizer_iff.mp hb) _ ⟨(p, q), rfl⟩ + -- `↑p · a · ↑r` is a scalar multiple of `e_{pr}`, hence commutes with `b`. + have hcomm_T : ∀ p r : F, ((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) * b + = b * ((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) := by + intro p r + obtain ⟨c, hc⟩ := hF.exists_matrixEntry he p r ha + have hT : (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) = c • hF.matrixUnit p r := by + rw [← hF.pisom_range p, ← hF.pisom_range r] + calc hF.pisom p * star (hF.pisom p) * a * (hF.pisom r * star (hF.pisom r)) + = hF.pisom p * (star (hF.pisom p) * a * hF.pisom r) * star (hF.pisom r) := by + simp only [mul_assoc] + _ = hF.pisom p * (c • e) * star (hF.pisom r) := by rw [hc] + _ = c • (hF.pisom p * e * star (hF.pisom r)) := by rw [mul_smul_comm, smul_mul_assoc] + _ = c • (hF.pisom p * star (hF.pisom r)) := by rw [hF.pisom_mul_source p] + _ = c • hF.matrixUnit p r := rfl + rw [hT, smul_mul_assoc, hbcomm p r, mul_smul_comm] + -- Test `a * b = b * a` against inner products. + apply ContinuousLinearMap.ext + intro y + apply ext_inner_left ℂ + intro x + -- For each `r`, the `r`-summands agree (insert `Σ_p p_p` to the left of `a`). + have step : ∀ r : F, inner ℂ x ((a * (r : H →L[ℂ] H) * b) y) + = inner ℂ x ((b * a * (r : H →L[ℂ] H)) y) := by + intro r + have hLp : HasSum + (fun p : F => inner ℂ x (((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b) y)) + (inner ℂ x ((a * (r : H →L[ℂ] H) * b) y)) := by + have h := (hF.hasSum_resolutionOfIdentity htop ((a * (r : H →L[ℂ] H) * b) y)).mapL (innerSL ℂ x) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + have hRp : HasSum + (fun p : F => inner ℂ x ((b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) y)) + (inner ℂ x ((b * a * (r : H →L[ℂ] H)) y)) := by + have h := (((hF.hasSum_resolutionOfIdentity htop ((a * (r : H →L[ℂ] H)) y)).mapL b).mapL (innerSL ℂ x)) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + have hfun : (fun p : F => inner ℂ x (((p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b) y)) + = (fun p : F => inner ℂ x ((b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H)) y)) := by + funext p + have hkey : (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) * b + = b * (p : H →L[ℂ] H) * a * (r : H →L[ℂ] H) := by + rw [hcomm_T p r, ← mul_assoc, ← mul_assoc] + rw [hkey] + rw [hfun] at hLp + exact hLp.unique hRp + have hL : HasSum (fun r : F => inner ℂ x ((a * (r : H →L[ℂ] H) * b) y)) + (inner ℂ x ((a * b) y)) := by + have h := ((hF.hasSum_resolutionOfIdentity htop (b y)).mapL a).mapL (innerSL ℂ x) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + have hR : HasSum (fun r : F => inner ℂ x ((b * a * (r : H →L[ℂ] H)) y)) + (inner ℂ x ((b * a) y)) := by + have h := ((hF.hasSum_resolutionOfIdentity htop y).mapL (b * a)).mapL (innerSL ℂ x) + simpa only [innerSL_apply_apply, ContinuousLinearMap.mul_apply] using h + rw [funext step] at hL + exact hL.unique hR + +/-- The centralizer of the matrix units is contained in the commutant of `N`. -/ +lemma OrthEquivFam.centralizer_subset_commutant (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + Set.centralizer (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) + ⊆ Set.centralizer (N : Set (H →L[ℂ] H)) := by + intro b hb + rw [Set.mem_centralizer_iff] + intro a ha + exact hF.commutes_of_mem_centralizer he htop ha hb + +/-- **Matrix units generate the type I factor.** The von Neumann algebra generated by the system of +matrix units `e_{pq} = v_p v_q⋆` is `N`. This is the von-Neumann-algebraic form of the structure +theorem `N ≅ B(ℓ²(F)) ⊗̄ 1`. -/ +theorem OrthEquivFam.generated_matrixUnits_eq (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) : + VonNeumannAlgebra.generated (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) = N := by + set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef + apply le_antisymm + · exact VonNeumannAlgebra.generated_le hF.matrixUnit_subset + · intro a ha + rw [← SetLike.mem_coe] + change a ∈ ((VonNeumannAlgebra.commutantSet S).commutant : Set (H →L[ℂ] H)) + rw [VonNeumannAlgebra.coe_commutant, VonNeumannAlgebra.coe_commutantSet] + have hsub : (S ∪ star S).centralizer ⊆ (N : Set (H →L[ℂ] H)).centralizer := + (Set.centralizer_subset Set.subset_union_left).trans (hF.centralizer_subset_commutant he htop) + have h2 : ((N : Set (H →L[ℂ] H)).centralizer).centralizer + ⊆ ((S ∪ star S).centralizer).centralizer := Set.centralizer_subset hsub + exact h2 (Set.subset_centralizer_centralizer (SetLike.mem_coe.mpr ha)) + +/-- **SOT reconstruction (corollary).** Every `a ∈ N` lies in the strong-operator closure of the +`*`-subalgebra generated by the matrix units. This is the literal `a = Σ_{pq} c_{pq}(a) e_{pq}` +content of the structure theorem, in closure form, obtained from the generation theorem and the SOT +double commutant theorem. -/ +theorem OrthEquivFam.mem_sotClosure_adjoin (hF : OrthEquivFam N e F) + (he : IsMinimalProjection N e) + (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) + {a : H →L[ℂ] H} (ha : a ∈ N) : + (⟨a⟩ : ContinuousLinearMapSOT H) ∈ closure (Set.toSOT + (StarAlgebra.adjoin ℂ (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) : + Set (H →L[ℂ] H))) := by + set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef + apply SOTClosedSubalgebra.mem_sotClosure_of_mem_doubleCommutant (StarAlgebra.adjoin ℂ S) a + have hunion : S ∪ star S ⊆ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := by + refine Set.union_subset (StarAlgebra.subset_adjoin ℂ S) ?_ + intro y hy + rw [Set.mem_star] at hy + have hya : star y ∈ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := + StarAlgebra.subset_adjoin ℂ S hy + have := star_mem (s := StarAlgebra.adjoin ℂ S) hya + rwa [star_star] at this + have hgen : (VonNeumannAlgebra.generated S : Set (H →L[ℂ] H)) + = Set.centralizer (Set.centralizer (S ∪ star S)) := by + change ((VonNeumannAlgebra.commutantSet S).commutant : Set (H →L[ℂ] H)) = _ + rw [VonNeumannAlgebra.coe_commutant, VonNeumannAlgebra.coe_commutantSet] + have hmono : Set.centralizer (Set.centralizer (S ∪ star S)) + ⊆ Set.centralizer (Set.centralizer (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H))) := + Set.centralizer_subset (Set.centralizer_subset hunion) + apply hmono + have hmem : a ∈ (VonNeumannAlgebra.generated S : Set (H →L[ℂ] H)) := by + rw [hF.generated_matrixUnits_eq he htop]; exact SetLike.mem_coe.mpr ha + rwa [hgen] at hmem + +/-! ### Spatial identification with the tensor factor `B(ℓ²(F)) ⊗̄ 1` -/ + /-- The `i`-th standard basis vector `δ_i = lp.single 2 i 1` of `ℓ²(F) = lp (fun _ : F => ℂ) 2`. This is a thin wrapper whose only purpose is to pin the index family `fun _ : F => ℂ`, so that the basis vectors are unambiguous in scalar positions (such as inner products). -/ diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index cfaf968..fff8da5 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -3,7 +3,7 @@ module public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.RankOne public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProductCompletion public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant -public import QuantumSystem.Algebra.VonNeumannAlgebra.Factor +public import QuantumSystem.Algebra.VonNeumannAlgebra.Basic public import Mathlib.Analysis.InnerProductSpace.Adjoint /-! diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean index 4b1fb50..90389a9 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -1,7 +1,7 @@ module -public import QuantumSystem.Algebra.VonNeumannAlgebra.Comparison -public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorIdentification +public import QuantumSystem.Algebra.VonNeumannAlgebra.Basic +public import QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant public import Mathlib.Analysis.InnerProductSpace.Projection.Basic public import Mathlib.Analysis.InnerProductSpace.StarOrder @@ -26,7 +26,16 @@ corner element to a real multiple of `p`. This file is also the home of the factor-level type I predicates `IsTypeIFactor` and `IsTypeIInfinite`, and of the abstract structure theorem `IsTypeIFactor.exists_starAlgEquiv` identifying a type I factor with `B(K)` for some Hilbert space `K` (whose spatial content lives in -`Algebra.VonNeumannAlgebra.TensorIdentification`). +`QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem`). + +Finally, the file develops the **fundamental example** `B(H)`: the algebra of *all* bounded +operators, realised as the greatest von Neumann algebra `⊤ : VonNeumannAlgebra H` (supplied in +`QuantumSystem.Algebra.VonNeumannAlgebra.Basic`), is a factor — its centre is the scalars, by the +elementary fact that an operator commuting with every rank-one operator is scalar. It possesses a +minimal projection, namely any rank-one orthogonal projection `|u⟩⟨u|` with `‖u‖ = 1`. Hence +`B(H)` is a **type I factor**, and by the abstract structure theorem it is `⋆`-isomorphic to +`B(K)` for some Hilbert space `K` (which is `ℓ²` of an orthonormal basis of `H`); when `H` is +infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor**. ## Main definitions @@ -54,6 +63,16 @@ identifying a type I factor with `B(K)` for some Hilbert space `K` (whose spatia type I_∞ factor may be chosen injectively. * `VonNeumannAlgebra.IsTypeIFactor.exists_starAlgEquiv` — a type I factor is `⋆`-isomorphic to `B(K)` for some complex Hilbert space `K`. +* `VonNeumannAlgebra.isFactor_boundedLinearOperators` — `B(H)` is a factor. +* `VonNeumannAlgebra.exists_isMinimalProjection_boundedLinearOperators` — `B(H)` has a minimal + projection (rank-one). +* `VonNeumannAlgebra.isTypeIFactor_boundedLinearOperators` — `B(H)` is a type I factor. +* `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(K)` for some + Hilbert space `K`. +* `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, `B(H)` + is a type I_∞ factor, packaged as the intrinsic predicate `IsTypeIInfinite ⊤`. +* `VonNeumannAlgebra.exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators` — for + infinite-dimensional `H`, `B(H) ≃⋆ₐ B(K)` with `K` itself infinite-dimensional. -/ @[expose] public section @@ -633,7 +652,7 @@ lemma IsTypeIInfinite.isTypeIFactor {N : VonNeumannAlgebra H} (hN : IsTypeIInfin A type I factor is `⋆`-isomorphic to `B(K)` for some Hilbert space `K`. The spatial content — the implementing unitary and the multiplicity model `K = ℓ²(F)` — is -`IsFactor.exists_spatial_tensorDecomposition` in `Algebra.VonNeumannAlgebra.TensorIdentification`; +`IsFactor.exists_spatial_tensorDecomposition` in `Algebra.VonNeumannAlgebra.StructureTheorem`; here it is packaged as an abstract `⋆`-isomorphism. -/ universe u @@ -661,4 +680,127 @@ theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] exact ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, ⟨(conjEquiv U N).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ +/-! ### The fundamental example: `B(H)` is a type I factor -/ + +open InnerProductSpace + +/-- **`B(H)` is a factor.** The centre of the full algebra is trivial: an operator lying in the +commutant of `⊤` commutes with every operator, in particular with every rank-one operator, hence is +a scalar (`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ +theorem isFactor_boundedLinearOperators : IsFactor (⊤ : VonNeumannAlgebra H) := by + intro x _ hxComm + rw [VonNeumannAlgebra.mem_commutant_iff] at hxComm + refine ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm (fun a b => ?_) + have hg := hxComm (rankOne ℂ a b) (mem_top _) + rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] at hg + exact hg.symm + +/-- **A rank-one projection is minimal in `B(H)`.** For a unit vector `u`, the rank-one orthogonal +projection `|u⟩⟨u|` is a minimal projection of `⊤`: it is a star projection, nonzero, and its corner +is trivial because `|u⟩⟨u| ∘ a ∘ |u⟩⟨u| = ⟪u, a u⟫ • |u⟩⟨u|`. -/ +lemma isMinimalProjection_rankOne_boundedLinearOperators {u : H} (hu : ‖u‖ = 1) : + IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := by + have hu_ne : u ≠ 0 := by rw [← norm_pos_iff, hu]; norm_num + refine ⟨⟨isIdempotentElem_rankOne_self hu, ?_⟩, mem_top _, + rankOne_ne_zero hu_ne hu_ne, fun a _ => ?_⟩ + · rw [isSelfAdjoint_iff, ContinuousLinearMap.star_eq_adjoint, adjoint_rankOne] + · exact ⟨inner ℂ u (a u), by + rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def, + ContinuousLinearMap.comp_assoc, comp_rankOne, rankOne_comp_rankOne]⟩ + +omit [CompleteSpace H] in +/-- A normalised nonzero vector of a nontrivial space, packaged as a unit vector. -/ +private theorem exists_unit_vector [Nontrivial H] : ∃ u : H, ‖u‖ = 1 := by + obtain ⟨v, hv⟩ := exists_ne (0 : H) + exact ⟨(‖v‖⁻¹ : ℂ) • v, by + rw [norm_smul, norm_inv, Complex.norm_real, norm_norm, + inv_mul_cancel₀ (norm_ne_zero_iff.mpr hv)]⟩ + +/-- **`B(H)` has a minimal projection** (a rank-one projection). Needs `H` nonzero. -/ +theorem exists_isMinimalProjection_boundedLinearOperators [Nontrivial H] : + ∃ e : H →L[ℂ] H, IsMinimalProjection (⊤ : VonNeumannAlgebra H) e := + let ⟨u, hu⟩ := exists_unit_vector (H := H) + ⟨rankOne ℂ u u, isMinimalProjection_rankOne_boundedLinearOperators hu⟩ + +/-- **`B(H)` is a type I factor** (for nonzero `H`). -/ +theorem isTypeIFactor_boundedLinearOperators [Nontrivial H] : + IsTypeIFactor (⊤ : VonNeumannAlgebra H) := + ⟨isFactor_boundedLinearOperators, exists_isMinimalProjection_boundedLinearOperators⟩ + +/-- **`B(H)` is `⋆`-isomorphic to `B(K)`** for some complex Hilbert space `K`. This applies the +abstract type I factor structure theorem `IsTypeIFactor.exists_starAlgEquiv` to the full algebra; +`K` is `ℓ²` of an orthonormal basis of `H`. -/ +theorem exists_starAlgEquiv_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] : + ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), + Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := + isTypeIFactor_boundedLinearOperators.exists_starAlgEquiv + +/-- **`B(H) ≃⋆ₐ B(K)` with `K` infinite-dimensional, when `H` is infinite-dimensional.** The full +algebra is `⋆`-isomorphic to `B(K)` for a complex Hilbert space `K` that is itself +infinite-dimensional. Here `K = ℓ²(F)` for `F` an orthonormal basis of `H`; a finite `F` would, +through the spatial decomposition `H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` with one-dimensional multiplicity `eH` (the +range of the rank-one minimal projection), force `H` finite-dimensional. Expressing type I_∞ as +`¬FiniteDimensional ℂ K` is the standard reading: a type I_n factor is `B(K)` with `dim K = n`, so +I_∞ is exactly the infinite-dimensional `K`. -/ +theorem exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators {H : Type u} + [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + (hinf : ¬FiniteDimensional ℂ H) : + ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), + ¬FiniteDimensional ℂ K ∧ + Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by + haveI : Nontrivial H := by + rcases subsingleton_or_nontrivial H with h | h + · haveI := h + exact absurd (inferInstance : FiniteDimensional ℂ H) hinf + · exact h + obtain ⟨u, hu⟩ := exists_unit_vector (H := H) + have he : IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := + isMinimalProjection_rankOne_boundedLinearOperators hu + obtain ⟨F, U, hU, -⟩ := isFactor_boundedLinearOperators.exists_spatial_tensorDecomposition he + haveI : CompleteSpace (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := + he.1.completeSpace_range + haveI hfd : FiniteDimensional ℂ (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := + finiteDimensional_range_rankOne u + haveI : Nontrivial (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := by + rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] + exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective + (h.trans ContinuousLinearMap.coe_zero.symm)) + refine ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, ?_, + ⟨(conjEquiv U ⊤).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ + intro hK + haveI := hK + exact hinf U.symm.toLinearEquiv.finiteDimensional + +/-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** Packaged as the intrinsic +predicate `IsTypeIInfinite`: `⊤ = B(H)` is a type I factor (`isTypeIFactor_boundedLinearOperators`) +carrying an infinite orthogonal family of minimal projections — the rank-one projections +`|uₙ⟩⟨uₙ|` onto a countable orthonormal sequence `(uₙ)` extracted from a Hilbert basis of the +infinite-dimensional `H`. The `⋆`-isomorphism to an infinite-dimensional `B(K)` is +`exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators`. -/ +theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] (hinf : ¬FiniteDimensional ℂ H) : + IsTypeIInfinite (⊤ : VonNeumannAlgebra H) := by + obtain ⟨w, b, -⟩ := exists_hilbertBasis ℂ H + have hwinf : Infinite w := by + rw [← not_finite_iff_infinite] + intro hfin + haveI : Finite w := hfin + haveI : Fintype w := Fintype.ofFinite w + exact hinf b.toOrthonormalBasis.toBasis.finiteDimensional_of_finite + haveI := hwinf + let g : ℕ ↪ w := Infinite.natEmbedding w + set u : ℕ → H := fun n => b (g n) with hu_def + have hon : Orthonormal ℂ u := by + rw [hu_def]; exact b.orthonormal.comp g g.injective + have hnorm : ∀ n, ‖u n‖ = 1 := fun n => hon.1 n + have hmin : ∀ n, IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ (u n) (u n)) := + fun n => isMinimalProjection_rankOne_boundedLinearOperators (hnorm n) + have horth : ∀ m n, m ≠ n → rankOne ℂ (u m) (u m) * rankOne ℂ (u n) (u n) = 0 := by + intro m n hmn + rw [ContinuousLinearMap.mul_def, rankOne_comp_rankOne, hon.2 hmn, zero_smul] + haveI : Nontrivial H := + nontrivial_of_ne (u 0) 0 (by rw [← norm_ne_zero_iff, hnorm 0]; norm_num) + exact ⟨isTypeIFactor_boundedLinearOperators, fun n => rankOne ℂ (u n) (u n), hmin, horth⟩ + end VonNeumannAlgebra From bc08cf2369fdcfb262466595d59f1bf5f6f8c1a8 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 05:36:34 +0000 Subject: [PATCH 061/113] =?UTF-8?q?refactor:=20replace=20Top=20instance=20?= =?UTF-8?q?with=20named=20=F0=9D=93=91(H)=20and=20a=20bridging=20star-isom?= =?UTF-8?q?orphism?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The full algebra B(H) was exposed only as the lattice element ⊤ : VonNeumannAlgebra H, whose vocabulary has no counterpart in the operator-algebra literature. Replace it with a literature-faithful named def boundedLinearOperators, notated 𝓑(H) (overloading the existing type-level 𝓑(H) = H →L[ℂ] H), and record the two-level identity explicitly via the canonical ⋆-isomorphism boundedLinearOperators.starAlgEquiv (the ⋆-algebra analogue of Subalgebra.topEquiv), rather than leaving it to a silent notation overload. Co-Authored-By: Claude Fable 5 --- .../Algebra/VonNeumannAlgebra/Basic.lean | 82 ++++++++++++++----- .../Algebra/VonNeumannAlgebra/TypeI.lean | 38 ++++----- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean index 863d65e..7e36afd 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean @@ -8,8 +8,9 @@ public import QuantumSystem.ForMathlib.Algebra.Star.PartialIsometry This file sets up the basic vocabulary of the comparison theory of projections in a von Neumann algebra, the foundation of the type classification (and, downstream, of the type I factor -structure theorem). It also supplies the greatest element `⊤ : VonNeumannAlgebra H` — the full -algebra `B(H)` — which Mathlib's `VonNeumannAlgebra H` does not provide. +structure theorem). It also supplies `𝓑(H)`, the von Neumann algebra of *all* bounded operators +— the object the literature writes `B(H)` — which Mathlib's `VonNeumannAlgebra H` does not provide +as a distinguished element. The file is organised in three parts: @@ -24,8 +25,12 @@ The file is organised in three parts: ## Main definitions -* `Top (VonNeumannAlgebra H)` — the greatest element `⊤`, the algebra of all bounded operators, - with carrier `Set.univ` (`VonNeumannAlgebra.coe_top` / `VonNeumannAlgebra.mem_top`). +* `VonNeumannAlgebra.boundedLinearOperators H` — the algebra of all bounded operators, with carrier + `Set.univ`, denoted `𝓑(H)` (`VonNeumannAlgebra.coe_boundedLinearOperators` / + `VonNeumannAlgebra.mem_boundedLinearOperators`). +* `VonNeumannAlgebra.boundedLinearOperators.starAlgEquiv` — the canonical `⋆`-isomorphism + `𝓑(H) ≃⋆ₐ[ℂ] (H →L[ℂ] H)` identifying the bundled von Neumann algebra with the operator type + (the `⋆`-algebra analogue of `Subalgebra.topEquiv`). * `VonNeumannAlgebra.IsFactor N` — `N` has trivial centre: every element of `N ∩ N'` is a scalar. * `VonNeumannAlgebra.IsMinimalProjection N e` — `e` is a nonzero star projection in `N` with trivial corner `e N e = ℂ e`. This implies the order-theoretic minimality (no proper nonzero @@ -70,6 +75,11 @@ activate them with `open scoped VonNeumannAlgebra`. |---|---|---| | `p ∼[N] q` | `VonNeumannAlgebra.MvNEquiv N p q` | `open scoped VonNeumannAlgebra` | | `p ≼[N] q` | `VonNeumannAlgebra.MvNSub N p q` | `open scoped VonNeumannAlgebra` | +| `𝓑(H)` | `VonNeumannAlgebra.boundedLinearOperators H` | `open scoped VonNeumannAlgebra` | + +The `𝓑(H)` glyph overloads the type-level notation `𝓑(H) = H →L[ℂ] H` of +`ForMathlib.Analysis.CStarAlgebra.HilbertSpace`; the two denote the same object B(H) at different +levels and are related by `boundedLinearOperators.starAlgEquiv`. The expected type disambiguates. -/ @[expose] public section @@ -78,22 +88,54 @@ namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] -/-! ### The full algebra `B(H)` as the greatest von Neumann algebra -/ - -/-- The **algebra of all bounded operators** `B(H) = H →L[ℂ] H`, as the greatest element `⊤` of the -inclusion order on `VonNeumannAlgebra H`. Its carrier is `Set.univ`; the double-commutant property is -the bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest -set. Mathlib's `VonNeumannAlgebra H` carries no `Top` instance, so this file supplies one. -/ -noncomputable instance : Top (VonNeumannAlgebra H) where - top := - { toStarSubalgebra := ⊤ - centralizer_centralizer' := - Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer } - -@[simp] lemma coe_top : ((⊤ : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl - -/-- Every bounded operator lies in the full algebra `⊤ = B(H)`. -/ -@[simp] lemma mem_top (x : H →L[ℂ] H) : x ∈ (⊤ : VonNeumannAlgebra H) := Set.mem_univ x +/-! ### The full algebra `𝓑(H)` of all bounded operators -/ + +/-- The von Neumann algebra `𝓑(H)` of **all bounded linear operators** on `H` — the object the +literature writes `B(H)`. Its carrier is `Set.univ`; the double-commutant property is the +bicommutant inclusion `s ⊆ s''` applied to `s = univ`, together with `univ` being the largest set. +Mathlib's bundled `VonNeumannAlgebra H` provides no such distinguished element, so this file +supplies it. -/ +noncomputable def boundedLinearOperators (H : Type*) [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] : VonNeumannAlgebra H where + toStarSubalgebra := ⊤ + centralizer_centralizer' := + Set.Subset.antisymm (Set.subset_univ _) Set.subset_centralizer_centralizer + +/-- `𝓑(H)` denotes the von Neumann algebra of all bounded operators on `H` +(`VonNeumannAlgebra.boundedLinearOperators H`). This overloads the type-level notation +`𝓑(H) = H →L[ℂ] H` of `ForMathlib.Analysis.CStarAlgebra.HilbertSpace`: the two denote the same +mathematical object B(H) at different levels (the operator *type* vs. the bundled *von Neumann +algebra* of all operators), and the expected type disambiguates. The two levels are related by the +canonical `⋆`-isomorphism `boundedLinearOperators.starAlgEquiv`. -/ +scoped notation:max "𝓑(" H ")" => VonNeumannAlgebra.boundedLinearOperators H + +@[simp] lemma coe_boundedLinearOperators : + ((𝓑(H) : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl + +/-- Every bounded operator lies in `𝓑(H)`. -/ +@[simp] lemma mem_boundedLinearOperators (x : H →L[ℂ] H) : x ∈ (𝓑(H) : VonNeumannAlgebra H) := + Set.mem_univ x + +/-- **The two levels of `𝓑(H)` agree.** The underlying `⋆`-subalgebra of the bundled von Neumann +algebra `𝓑(H)`, coerced to a type, is canonically `⋆`-isomorphic to the operator type +`H →L[ℂ] H` (itself the type-level `𝓑(H)` of `ForMathlib.Analysis.CStarAlgebra.HilbertSpace`). +This is the `⋆`-algebra analogue of `Subalgebra.topEquiv` / `Submodule.topEquiv`, making explicit +that the notation overload denotes one and the same object B(H). The equivalence is phrased on +`(𝓑(H)).toStarSubalgebra` because Mathlib equips the `⋆`-subalgebra — not the bundled +`VonNeumannAlgebra` — with the `ℂ`-algebra structure. -/ +noncomputable def boundedLinearOperators.starAlgEquiv : + (𝓑(H) : VonNeumannAlgebra H).toStarSubalgebra ≃⋆ₐ[ℂ] (H →L[ℂ] H) := + StarAlgEquiv.ofStarAlgHom + (𝓑(H) : VonNeumannAlgebra H).toStarSubalgebra.subtype + ({ toFun := fun x => ⟨x, StarSubalgebra.mem_top⟩ + map_one' := rfl + map_mul' := fun _ _ => rfl + map_zero' := rfl + map_add' := fun _ _ => rfl + commutes' := fun _ => rfl + map_star' := fun _ => rfl } : + (H →L[ℂ] H) →⋆ₐ[ℂ] (𝓑(H) : VonNeumannAlgebra H).toStarSubalgebra) + (fun _ => rfl) (fun _ => rfl) /-! ### Factors, minimal projections and Murray–von Neumann equivalence -/ diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean index 90389a9..6e0b9b9 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -29,7 +29,7 @@ identifying a type I factor with `B(K)` for some Hilbert space `K` (whose spatia `QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem`). Finally, the file develops the **fundamental example** `B(H)`: the algebra of *all* bounded -operators, realised as the greatest von Neumann algebra `⊤ : VonNeumannAlgebra H` (supplied in +operators, `𝓑(H) : VonNeumannAlgebra H` (supplied in `QuantumSystem.Algebra.VonNeumannAlgebra.Basic`), is a factor — its centre is the scalars, by the elementary fact that an operator commuting with every rank-one operator is scalar. It possesses a minimal projection, namely any rank-one orthogonal projection `|u⟩⟨u|` with `‖u‖ = 1`. Hence @@ -70,7 +70,7 @@ infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor**. * `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(K)` for some Hilbert space `K`. * `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, `B(H)` - is a type I_∞ factor, packaged as the intrinsic predicate `IsTypeIInfinite ⊤`. + is a type I_∞ factor, packaged as the intrinsic predicate `IsTypeIInfinite 𝓑(H)`. * `VonNeumannAlgebra.exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators` — for infinite-dimensional `H`, `B(H) ≃⋆ₐ B(K)` with `K` itself infinite-dimensional. -/ @@ -661,7 +661,7 @@ universe u projection, acting on a nonzero Hilbert space) is `⋆`-isomorphic to the algebra `B(K)` of all bounded operators on *some* complex Hilbert space `K`. This is the model-independent form of the classification of type I factors: `B(K)` for `K = ℓ²(F)` is exactly the type `I_{|F|}` factor, and -`K = H` recovers the full algebra `B(H)` as the type `I` factor `⊤`. The spatial content — that the +`K = H` recovers the full algebra `B(H)` as the type `I` factor `𝓑(H)`. The spatial content — that the isomorphism is implemented by a unitary and that `K` is the multiplicity space of the minimal projection — is `IsFactor.exists_spatial_tensorDecomposition`; here it is packaged as an abstract `⋆`-isomorphism, hiding the specific model `K = ℓ²(F)` behind an existential. -/ @@ -685,23 +685,23 @@ theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] open InnerProductSpace /-- **`B(H)` is a factor.** The centre of the full algebra is trivial: an operator lying in the -commutant of `⊤` commutes with every operator, in particular with every rank-one operator, hence is -a scalar (`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ -theorem isFactor_boundedLinearOperators : IsFactor (⊤ : VonNeumannAlgebra H) := by +commutant of `𝓑(H)` commutes with every operator, in particular with every rank-one operator, hence +is a scalar (`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ +theorem isFactor_boundedLinearOperators : IsFactor 𝓑(H) := by intro x _ hxComm rw [VonNeumannAlgebra.mem_commutant_iff] at hxComm refine ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm (fun a b => ?_) - have hg := hxComm (rankOne ℂ a b) (mem_top _) + have hg := hxComm (rankOne ℂ a b) (mem_boundedLinearOperators _) rw [ContinuousLinearMap.mul_def, ContinuousLinearMap.mul_def] at hg exact hg.symm /-- **A rank-one projection is minimal in `B(H)`.** For a unit vector `u`, the rank-one orthogonal -projection `|u⟩⟨u|` is a minimal projection of `⊤`: it is a star projection, nonzero, and its corner +projection `|u⟩⟨u|` is a minimal projection of `𝓑(H)`: it is a star projection, nonzero, and its corner is trivial because `|u⟩⟨u| ∘ a ∘ |u⟩⟨u| = ⟪u, a u⟫ • |u⟩⟨u|`. -/ lemma isMinimalProjection_rankOne_boundedLinearOperators {u : H} (hu : ‖u‖ = 1) : - IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := by + IsMinimalProjection 𝓑(H) (rankOne ℂ u u) := by have hu_ne : u ≠ 0 := by rw [← norm_pos_iff, hu]; norm_num - refine ⟨⟨isIdempotentElem_rankOne_self hu, ?_⟩, mem_top _, + refine ⟨⟨isIdempotentElem_rankOne_self hu, ?_⟩, mem_boundedLinearOperators _, rankOne_ne_zero hu_ne hu_ne, fun a _ => ?_⟩ · rw [isSelfAdjoint_iff, ContinuousLinearMap.star_eq_adjoint, adjoint_rankOne] · exact ⟨inner ℂ u (a u), by @@ -718,13 +718,13 @@ private theorem exists_unit_vector [Nontrivial H] : ∃ u : H, ‖u‖ = 1 := by /-- **`B(H)` has a minimal projection** (a rank-one projection). Needs `H` nonzero. -/ theorem exists_isMinimalProjection_boundedLinearOperators [Nontrivial H] : - ∃ e : H →L[ℂ] H, IsMinimalProjection (⊤ : VonNeumannAlgebra H) e := + ∃ e : H →L[ℂ] H, IsMinimalProjection 𝓑(H) e := let ⟨u, hu⟩ := exists_unit_vector (H := H) ⟨rankOne ℂ u u, isMinimalProjection_rankOne_boundedLinearOperators hu⟩ /-- **`B(H)` is a type I factor** (for nonzero `H`). -/ theorem isTypeIFactor_boundedLinearOperators [Nontrivial H] : - IsTypeIFactor (⊤ : VonNeumannAlgebra H) := + IsTypeIFactor 𝓑(H) := ⟨isFactor_boundedLinearOperators, exists_isMinimalProjection_boundedLinearOperators⟩ /-- **`B(H)` is `⋆`-isomorphic to `B(K)`** for some complex Hilbert space `K`. This applies the @@ -733,7 +733,7 @@ abstract type I factor structure theorem `IsTypeIFactor.exists_starAlgEquiv` to theorem exists_starAlgEquiv_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] : ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), - Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := + Nonempty (𝓑(H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := isTypeIFactor_boundedLinearOperators.exists_starAlgEquiv /-- **`B(H) ≃⋆ₐ B(K)` with `K` infinite-dimensional, when `H` is infinite-dimensional.** The full @@ -748,14 +748,14 @@ theorem exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators {H : Type (hinf : ¬FiniteDimensional ℂ H) : ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), ¬FiniteDimensional ℂ K ∧ - Nonempty ((⊤ : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by + Nonempty (𝓑(H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by haveI : Nontrivial H := by rcases subsingleton_or_nontrivial H with h | h · haveI := h exact absurd (inferInstance : FiniteDimensional ℂ H) hinf · exact h obtain ⟨u, hu⟩ := exists_unit_vector (H := H) - have he : IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ u u) := + have he : IsMinimalProjection 𝓑(H) (rankOne ℂ u u) := isMinimalProjection_rankOne_boundedLinearOperators hu obtain ⟨F, U, hU, -⟩ := isFactor_boundedLinearOperators.exists_spatial_tensorDecomposition he haveI : CompleteSpace (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := @@ -767,20 +767,20 @@ theorem exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators {H : Type exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective (h.trans ContinuousLinearMap.coe_zero.symm)) refine ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, ?_, - ⟨(conjEquiv U ⊤).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ + ⟨(conjEquiv U 𝓑(H)).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ intro hK haveI := hK exact hinf U.symm.toLinearEquiv.finiteDimensional /-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** Packaged as the intrinsic -predicate `IsTypeIInfinite`: `⊤ = B(H)` is a type I factor (`isTypeIFactor_boundedLinearOperators`) +predicate `IsTypeIInfinite`: `𝓑(H) = B(H)` is a type I factor (`isTypeIFactor_boundedLinearOperators`) carrying an infinite orthogonal family of minimal projections — the rank-one projections `|uₙ⟩⟨uₙ|` onto a countable orthonormal sequence `(uₙ)` extracted from a Hilbert basis of the infinite-dimensional `H`. The `⋆`-isomorphism to an infinite-dimensional `B(K)` is `exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators`. -/ theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] (hinf : ¬FiniteDimensional ℂ H) : - IsTypeIInfinite (⊤ : VonNeumannAlgebra H) := by + IsTypeIInfinite 𝓑(H) := by obtain ⟨w, b, -⟩ := exists_hilbertBasis ℂ H have hwinf : Infinite w := by rw [← not_finite_iff_infinite] @@ -794,7 +794,7 @@ theorem isTypeIInfinite_boundedLinearOperators {H : Type u} [NormedAddCommGroup have hon : Orthonormal ℂ u := by rw [hu_def]; exact b.orthonormal.comp g g.injective have hnorm : ∀ n, ‖u n‖ = 1 := fun n => hon.1 n - have hmin : ∀ n, IsMinimalProjection (⊤ : VonNeumannAlgebra H) (rankOne ℂ (u n) (u n)) := + have hmin : ∀ n, IsMinimalProjection 𝓑(H) (rankOne ℂ (u n) (u n)) := fun n => isMinimalProjection_rankOne_boundedLinearOperators (hnorm n) have horth : ∀ m n, m ≠ n → rankOne ℂ (u m) (u m) * rankOne ℂ (u n) (u n) = 0 := by intro m n hmn From fa6639ab898993156121aaafbffeb0ae5309b02b Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 05:44:43 +0000 Subject: [PATCH 062/113] =?UTF-8?q?refactor:=20make=20type-level=20?= =?UTF-8?q?=F0=9D=93=91(H)=20an=20opt-in=20scoped=20notation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the notation style: the type-level 𝓑(H) = H →L[ℂ] H was a global notation, while the von Neumann algebra 𝓑(H) is scoped. Move the type-level one into the opt-in ComplexHilbertSpace scope (precedence :max, matching the vN one) and add 'open scoped ComplexHilbertSpace' to the seven C*-algebra/GNS files that use it. Co-Authored-By: Claude Fable 5 --- QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean | 2 +- QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean | 2 +- QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean | 2 +- QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean | 2 +- QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean | 2 ++ QuantumSystem/Algebra/CStarAlgebra/Representation.lean | 2 ++ .../Algebra/CStarAlgebra/Representation/DirectSum.lean | 2 +- .../ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean | 7 +++++-- 8 files changed, 14 insertions(+), 7 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean index 38084ab..197fcd4 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean @@ -15,7 +15,7 @@ namespace GNS namespace Construction open ComplexConjugate NNReal Topology Filter -open scoped InnerProductSpace Adjoint +open scoped InnerProductSpace Adjoint ComplexHilbertSpace variable {A : Type*} [NonUnitalCStarAlgebra A] variable (ω : State ℂ A) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean index 8e4a165..20a40eb 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean @@ -7,7 +7,7 @@ public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotatio @[expose] public section -open scoped Adjoint +open scoped Adjoint ComplexHilbertSpace namespace GNS diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean index 7ede837..b57730a 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean @@ -20,7 +20,7 @@ namespace GNS namespace Representation -open scoped ComplexConjugate CStarAlgebra InnerProduct NNReal +open scoped ComplexConjugate CStarAlgebra InnerProduct NNReal ComplexHilbertSpace local notation "⟪" x ", " y "⟫" => inner ℂ x y diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean index 1cb4230..62e6eb8 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean @@ -9,7 +9,7 @@ public import QuantumSystem.Algebra.CStarAlgebra.Representation.Irreducible @[expose] public section -open scoped InnerProductSpace +open scoped InnerProductSpace ComplexHilbertSpace namespace GNS diff --git a/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean b/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean index 669fae7..fc16d4c 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean @@ -4,6 +4,8 @@ public import QuantumSystem.Algebra.CStarAlgebra.GNS.DirectSum @[expose] public section +open scoped ComplexHilbertSpace + universe u diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation.lean index 1b23730..95b1aa7 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation.lean @@ -56,6 +56,8 @@ The forgetful projection sending a GNS triplet to its underlying @[expose] public section +open scoped ComplexHilbertSpace + universe u v variable {A : Type u} [NonUnitalCStarAlgebra A] diff --git a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean index cbe9998..cae55ae 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/Representation/DirectSum.lean @@ -48,7 +48,7 @@ decomposition. The skeleton version @[expose] public section open ENNReal -open scoped Adjoint +open scoped Adjoint ComplexHilbertSpace namespace SectorFamily diff --git a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean index 9ef9fb6..a467d56 100644 --- a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean +++ b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean @@ -20,8 +20,11 @@ variable (H : Type*) [ComplexHilbertSpace H] /-- The space of bounded linear operators on a complex Hilbert space. -/ abbrev BoundedLinearOperator := H →L[ℂ] H -/-- Notation for bounded linear operators on a Hilbert space. -/ -notation:50 "𝓑(" H ")" => BoundedLinearOperator H +/-- Notation `𝓑(H)` for the bounded linear operators on a Hilbert space, living in the opt-in +`ComplexHilbertSpace` scope; activate it with `open scoped ComplexHilbertSpace`. This is the +type-level counterpart of the von Neumann algebra `𝓑(H)` of `Algebra.VonNeumannAlgebra.Basic` +(they denote the same object B(H) at different levels; see `boundedLinearOperators.starAlgEquiv`). -/ +scoped notation:max "𝓑(" H ")" => BoundedLinearOperator H noncomputable instance : NonUnitalCStarAlgebra (𝓑(H)) := inferInstance From 97797d0e225d66ea7fc3c860835d4e26fa1e53f5 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 11:42:53 +0000 Subject: [PATCH 063/113] docs: clarify LocalNet scope, Faithful split, and empty-region algebra Co-Authored-By: Claude Fable 5 --- QuantumSystem/Algebra/LocalNet/Net.lean | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 9494ac0..e31c787 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -9,7 +9,10 @@ public import Mathlib.Order.DirectedInverseSystem # Local nets of C⋆-algebras This file contains the abstract **local net** data: finite regions are assigned local C⋆-algebras, -with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms. +with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms; +in particular, additivity/generation axioms (e.g. `𝔄(Λ₁ ∪ Λ₂)` being generated by the images of +`𝔄(Λ₁)` and `𝔄(Λ₂)`, as in tensor-product spin-system nets) are intentionally out of scope here +and belong to concrete instantiations. The quasi-local algebra built from a net lives in `LocalNet.QuasiLocalAlgebra`; covariance data and its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. @@ -20,9 +23,14 @@ its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. /-- A **local net of C⋆-algebras** over the finite regions of a site set `sites`: the assignment `Λ ↦ 𝔄(Λ)` together with isotony embeddings `incl : 𝔄(Λ) →⋆ₐ[ℂ] 𝔄(Λ')` for `Λ ⊆ Λ'`, functorial (`incl_refl`/`incl_trans`) and local (`locality`). This is the Haag–Kastler net - structure for a lattice of sites. -/ + structure for a lattice of sites, *without* the injectivity requirement on the isotony + embeddings; the literature's net (Naaijkens 2012 §3.4) is `LocalNet` together with the + `Faithful` class, which carries that requirement. -/ structure LocalNet (sites : Type*) [DecidableEq sites] where - /-- The local C⋆-algebra `𝔄(Λ)` assigned to a finite region. -/ + /-- The local C⋆-algebra `𝔄(Λ)` assigned to a finite region. The axioms force `𝔄(∅)` to be + commutative (instantiate `locality` at `Λ₁ = Λ₂ = Λ = ∅`) but do *not* force it to be + trivial: the literature's `𝔄(∅) = ℂ·1` is not required and must be imposed by a concrete + instantiation when needed. -/ algebra : Finset sites → Type* /-- Each local algebra is a (complex) C⋆-algebra. -/ [algebraCStar : ∀ Λ, CStarAlgebra (algebra Λ)] From b7c1098fe05a34d6d772ae825461a86f20a39c03 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 11:43:20 +0000 Subject: [PATCH 064/113] feat: add union-only smart constructor LocalNet.mk' Co-Authored-By: Claude Fable 5 --- QuantumSystem/Algebra/LocalNet/Net.lean | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index e31c787..3a2c90a 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -55,6 +55,27 @@ attribute [instance] algebraCStar variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) +/-- Smart constructor for `LocalNet` taking locality only inside the canonical union region + `Λ₁ ∪ Λ₂`: given `incl_trans`, commutation there pushes forward along + `incl : 𝔄(Λ₁ ∪ Λ₂) →⋆ₐ[ℂ] 𝔄(Λ)` to any common superregion `Λ`, so the union case is + equivalent to the general `locality` field. -/ +def mk' (algebra : Finset sites → Type*) [algebraCStar : ∀ Λ, CStarAlgebra (algebra Λ)] + (incl : ∀ {Λ Λ' : Finset sites}, Λ ⊆ Λ' → (algebra Λ →⋆ₐ[ℂ] algebra Λ')) + (incl_refl : ∀ {Λ : Finset sites} (x : algebra Λ), incl (Finset.Subset.refl Λ) x = x) + (incl_trans : ∀ {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (x : algebra Λ₁), + incl h₂₃ (incl h₁₂ x) = incl (h₁₂.trans h₂₃) x) + (locality_union : ∀ {Λ₁ Λ₂ : Finset sites}, Disjoint Λ₁ Λ₂ → + ∀ (x : algebra Λ₁) (y : algebra Λ₂), + Commute (incl Finset.subset_union_left x) (incl Finset.subset_union_right y)) : + LocalNet sites where + algebra := algebra + incl := incl + incl_refl := incl_refl + incl_trans := incl_trans + locality h₁ h₂ hdisj x y := by + have h := (locality_union hdisj x y).map (incl (Finset.union_subset h₁ h₂)) + rwa [incl_trans, incl_trans] at h + /-- The net forms a directed system of `*`-algebras: the isotony embeddings compose and the identity inclusion is the identity. -/ instance directedSystem : From 53c129001e1f3063d634c81cc78a9ad417d12530 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 11:43:37 +0000 Subject: [PATCH 065/113] refactor: drop algebraCongr_apply subsumed by algebraCongr_self Co-Authored-By: Claude Fable 5 --- QuantumSystem/Algebra/LocalNet/Net.lean | 3 --- 1 file changed, 3 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 3a2c90a..e261ad8 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -106,9 +106,6 @@ class Faithful {sites : Type*} [DecidableEq sites] (N : LocalNet sites) : Prop w def algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') : N.algebra Λ ≃⋆ₐ[ℂ] N.algebra Λ' := by subst h; exact StarAlgEquiv.refl -@[simp] lemma algebraCongr_apply {Λ : Finset sites} (x : N.algebra Λ) : - N.algebraCongr (rfl : Λ = Λ) x = x := rfl - /-- The isotony embeddings are natural with respect to the region-equality transport. -/ lemma incl_algebraCongr {Λ₁ Λ₂ Λ₁' Λ₂' : Finset sites} (e₁ : Λ₁ = Λ₁') (e₂ : Λ₂ = Λ₂') (h : Λ₁ ⊆ Λ₂) (h' : Λ₁' ⊆ Λ₂') (x : N.algebra Λ₁) : From 20f7d4db1943561662fbdddf5f08ac928080ef7a Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 15:00:45 +0000 Subject: [PATCH 066/113] refactor: index local nets by a causal poset of regions Generalize LocalNet from Finset sites to an abstract Haag-Kastler causal index set: a partial order K with a causal orthogonality relation (CausalOrthogonality, symmetric and hereditary under shrinking), replacing Finset disjointness in the locality axiom. Lattice nets are recovered as the instance K = Finset sites with orthogonality = Disjoint. Covariance becomes an orthogonality-preserving order automorphism of K with natural local *-isomorphisms; site-permutation covariances are recovered by Covariance.ofSitePerm. The quasi-local algebra now only requires the index set to be directed and nonempty, as demanded by the direct-limit machinery. Co-Authored-By: Claude Fable 5 --- .../Algebra/LocalNet/Covariance.lean | 205 ++++++++++-------- QuantumSystem/Algebra/LocalNet/Net.lean | 189 +++++++++++----- .../Algebra/LocalNet/QuasiLocalAlgebra.lean | 147 +++++++------ 3 files changed, 316 insertions(+), 225 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 460d395..41f3e45 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -5,18 +5,22 @@ public import QuantumSystem.Algebra.LocalNet.Net /-! # Covariance data for a local net -A **covariance** of a local net is a site permutation `σ` together with, for every finite region -`Λ`, a `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect -to the isotony embeddings. The naturality field `β_incl` is the AQFT covariance axiom -`β(𝔄(Λ)) = 𝔄(σΛ)` compatibly with inclusions (Naaijkens 2012 §3.2, Verch 2025 §1.2). These -covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp`, `Covariance.inv`). +A **covariance** of a local net over a causal index set `K` is an order automorphism `σ : K ≃o K` +of the regions preserving causal orthogonality, together with, for every region `O`, a +`*`-isomorphism `β_O : 𝔄(O) ≃⋆ₐ[ℂ] 𝔄(σO)` of local algebras that is natural with respect to the +isotony embeddings. The naturality field `β_incl` is the AQFT covariance axiom +`β(𝔄(O)) = 𝔄(σO)` compatibly with inclusions (Naaijkens 2012 §3.2, Verch 2025 §1.2). These +covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp`, +`Covariance.inv`). For lattice nets (`K = Finset sites`) a covariance is induced by a site +permutation via `Covariance.ofSitePerm` — and every covariance of a lattice net arises this way, +since an order automorphism of `Finset sites` is determined by its action on singletons. This file isolates the abstract covariance *data* and its group structure. Its *action* on the quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism `quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. A symmetry group `G` acts on the net by supplying a group homomorphism `G →* N.Covariance` (whose `σ`-component is the geometric action -`G → sites ≃ sites`); composing it with `quasiLocalCovarianceHom` — or, for a `Faithful` net, +`G → K ≃o K`); composing it with `quasiLocalCovarianceHom` — or, for a `Faithful` net, `quasiLocalCStarCovarianceHom` — yields the automorphic action of `G` on the (quasi-local) algebra. -/ @@ -24,154 +28,146 @@ supplying a group homomorphism `G →* N.Covariance` (whose `σ`-component is th namespace LocalNet -variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) +open scoped CausalOrthogonality + +variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] (N : LocalNet K) /-! ### Covariances of the net -A covariance of a local net is a site permutation `σ` together with, for each finite region, a -`*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` of local algebras that is natural with respect to the -isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)` at the abstract net -level. Being purely algebraic, the covariance group needs no faithfulness hypothesis. +A covariance of a local net is a causal order automorphism `σ` of the index set together with, +for each region, a `*`-isomorphism `β_O : 𝔄(O) ≃⋆ₐ[ℂ] 𝔄(σO)` of local algebras that is natural +with respect to the isotony embeddings. This realises the AQFT covariance axiom `β(𝔄(O)) = 𝔄(σO)` +at the abstract net level. Being purely algebraic, the covariance group needs no faithfulness +hypothesis. -/ -/-- A **covariance** of a local net `N`: a site permutation `σ` together with, for every finite - region `Λ`, a `*`-isomorphism `β Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)`, natural with respect to the isotony - embeddings (`β_incl`). This is the AQFT covariance datum at the abstract net level. -/ +/-- A **covariance** of a local net `N`: an order automorphism `σ` of the causal index set + preserving causal orthogonality (`map_orthogonal_iff`), together with, for every region `O`, + a `*`-isomorphism `β O : 𝔄(O) ≃⋆ₐ[ℂ] 𝔄(σO)`, natural with respect to the isotony embeddings + (`β_incl`). This is the AQFT covariance datum at the abstract net level. -/ structure Covariance where - /-- The underlying site permutation; its image map `Λ ↦ σΛ` carries the region map. -/ - σ : sites ≃ sites - /-- The covariance `*`-isomorphism `β_Λ : 𝔄(Λ) ≃⋆ₐ[ℂ] 𝔄(σΛ)` on each region. -/ - β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding) + /-- The underlying automorphism of the causal index set, carrying the region map `O ↦ σO`. -/ + σ : K ≃o K + /-- The region automorphism preserves causal orthogonality. Stated as an `iff` so that the + inverse covariance is again a covariance. -/ + map_orthogonal_iff : ∀ ⦃O₁ O₂ : K⦄, σ O₁ ⟂ σ O₂ ↔ O₁ ⟂ O₂ + /-- The covariance `*`-isomorphism `β_O : 𝔄(O) ≃⋆ₐ[ℂ] 𝔄(σO)` on each region. -/ + β : ∀ O : K, N.algebra O ≃⋆ₐ[ℂ] N.algebra (σ O) /-- **Naturality / covariance**: `β` intertwines the isotony embeddings, so it maps the net to - itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(Λ)) = 𝔄(σΛ)`. -/ - β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), - β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x) + itself compatibly with inclusions — the AQFT covariance axiom `β(𝔄(O)) = 𝔄(σO)`. -/ + β_incl : ∀ {O O' : K} (h : O ≤ O') (x : N.algebra O), + β O' (N.incl h x) = N.incl (σ.monotone h) (β O x) namespace Covariance variable {N} (a : N.Covariance) -/-- The image `σΛ` of a region under the covariance. -/ -def region (Λ : Finset sites) : Finset sites := Λ.map a.σ.toEmbedding +/-- The image `σO` of a region under the covariance. -/ +def region (O : K) : K := a.σ O -/-- **Extensionality** for covariances: two covariances with the same site permutation and the same - local `*`-isomorphisms (compared along the induced region equality) are equal. The naturality - field `β_incl` is a proposition, hence irrelevant. -/ +/-- **Extensionality** for covariances: two covariances with the same region automorphism and the + same local `*`-isomorphisms (compared along the induced region equality) are equal. The + remaining fields are propositions, hence irrelevant. -/ @[ext (iff := false)] lemma ext {s t : N.Covariance} (hσ : s.σ = t.σ) - (hβ : ∀ (Λ : Finset sites) (x : N.algebra Λ) (e : s.region Λ = t.region Λ), - N.algebraCongr e (s.β Λ x) = t.β Λ x) : s = t := by + (hβ : ∀ (O : K) (x : N.algebra O) (e : s.region O = t.region O), + N.algebraCongr e (s.β O x) = t.β O x) : s = t := by revert hσ hβ - obtain ⟨sσ, sβ, -⟩ := s - obtain ⟨tσ, tβ, -⟩ := t + obtain ⟨sσ, -, sβ, -⟩ := s + obtain ⟨tσ, -, tβ, -⟩ := t rintro rfl hβ have hβ' : sβ = tβ := by - funext Λ + funext O ext x - simpa using hβ Λ x rfl + simpa using hβ O x rfl subst hβ' rfl /-- Naturality of the inverse local `*`-isomorphisms with respect to isotony. -/ -lemma β_symm_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (y : N.algebra (Λ.map a.σ.toEmbedding)) : - (a.β Λ').symm (N.incl (Finset.map_subset_map.mpr h) y) = N.incl h ((a.β Λ).symm y) := by - have key := a.β_incl h ((a.β Λ).symm y) +lemma β_symm_incl {O O' : K} (h : O ≤ O') (y : N.algebra (a.σ O)) : + (a.β O').symm (N.incl (a.σ.monotone h) y) = N.incl h ((a.β O).symm y) := by + have key := a.β_incl h ((a.β O).symm y) rw [StarAlgEquiv.apply_symm_apply] at key rw [← key, StarAlgEquiv.symm_apply_apply] /-- The local `*`-isomorphisms commute with the region-equality transport. -/ -lemma β_algebraCongr {Λ Λ' : Finset sites} (e : Λ = Λ') (x : N.algebra Λ) : - a.β Λ' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β Λ x) := by +lemma β_algebraCongr {O O' : K} (e : O = O') (x : N.algebra O) : + a.β O' (N.algebraCongr e x) = N.algebraCongr (by rw [e]) (a.β O x) := by subst e; simp variable (N) in -/-- The **identity covariance**: the identity site permutation with the identity local - `*`-isomorphisms (transported along `Λ = σ_id Λ`). -/ +/-- The **identity covariance**: the identity region automorphism with the identity local + `*`-isomorphisms. -/ def id : N.Covariance where - σ := Equiv.refl sites - β Λ := N.algebraCongr (by simp) - β_incl h x := N.incl_algebraCongr _ _ h _ x + σ := OrderIso.refl K + map_orthogonal_iff _ _ := Iff.rfl + β _ := StarAlgEquiv.refl + β_incl _ _ := rfl -/-- **Composition of covariances**: apply `b`, then `a`. The site permutations compose; the local - `*`-isomorphisms compose and are transported along the region-map functoriality - `(σ_a ∘ σ_b) Λ = σ_a (σ_b Λ)`. -/ +/-- **Composition of covariances**: apply `b`, then `a`. The region automorphisms compose, and + the local `*`-isomorphisms compose along them. -/ def comp (a b : N.Covariance) : N.Covariance where σ := b.σ.trans a.σ - β Λ := ((b.β Λ).trans (a.β (Λ.map b.σ.toEmbedding))).trans - (N.algebraCongr (by simp [Finset.map_map, Equiv.trans_toEmbedding])) + map_orthogonal_iff O₁ O₂ := + (a.map_orthogonal_iff (O₁ := b.σ O₁) (O₂ := b.σ O₂)).trans + (b.map_orthogonal_iff (O₁ := O₁) (O₂ := O₂)) + β O := (b.β O).trans (a.β (b.σ O)) β_incl h x := by simp only [StarAlgEquiv.trans_apply] - rw [b.β_incl h, a.β_incl (Finset.map_subset_map.mpr h)] - exact N.incl_algebraCongr _ _ _ _ _ + rw [b.β_incl h] + exact a.β_incl (b.σ.monotone h) ((b.β _) x) -/-- The **inverse covariance**: the inverse site permutation with the inverse local - `*`-isomorphisms, transported along the region-map functoriality `σ⁻¹σ Λ = Λ`. -/ +/-- The **inverse covariance**: the inverse region automorphism with the inverse local + `*`-isomorphisms, transported along `σ(σ⁻¹O) = O`. -/ def inv (a : N.Covariance) : N.Covariance where σ := a.σ.symm - β Λ := (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by - simp [Finset.map_map]).symm).trans - (a.β (Λ.map a.σ.symm.toEmbedding)).symm + map_orthogonal_iff O₁ O₂ := by + rw [← a.map_orthogonal_iff, a.σ.apply_symm_apply, a.σ.apply_symm_apply] + β O := (N.algebraCongr (a.σ.apply_symm_apply O).symm).trans (a.β (a.σ.symm O)).symm β_incl h x := by simp only [StarAlgEquiv.trans_apply] - rw [N.incl_algebraCongr _ _ h (Finset.map_subset_map.mpr (Finset.map_subset_map.mpr h)), - a.β_symm_incl] + rw [N.incl_algebraCongr _ _ h (a.σ.monotone (a.σ.symm.monotone h)), a.β_symm_incl] -@[simp] lemma id_β_apply (Λ : Finset sites) (x : N.algebra Λ) : - (Covariance.id N).β Λ x = - N.algebraCongr (show Λ = Λ.map (Equiv.refl sites).toEmbedding by simp) x := +@[simp] lemma id_β_apply (O : K) (x : N.algebra O) : (Covariance.id N).β O x = x := rfl -@[simp] lemma comp_β_apply (a b : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : - (a.comp b).β Λ x = N.algebraCongr (show (Λ.map b.σ.toEmbedding).map a.σ.toEmbedding - = Λ.map (b.σ.trans a.σ).toEmbedding by simp [Finset.map_map, Equiv.trans_toEmbedding]) - (a.β (Λ.map b.σ.toEmbedding) (b.β Λ x)) := +@[simp] lemma comp_β_apply (a b : N.Covariance) (O : K) (x : N.algebra O) : + (a.comp b).β O x = a.β (b.σ O) (b.β O x) := rfl -@[simp] lemma inv_β_apply (a : N.Covariance) (Λ : Finset sites) (x : N.algebra Λ) : - (Covariance.inv a).β Λ x = (a.β (Λ.map a.σ.symm.toEmbedding)).symm - (N.algebraCongr (show (Λ.map a.σ.symm.toEmbedding).map a.σ.toEmbedding = Λ by - simp [Finset.map_map]).symm x) := +@[simp] lemma inv_β_apply (a : N.Covariance) (O : K) (x : N.algebra O) : + (Covariance.inv a).β O x = (a.β (a.σ.symm O)).symm + (N.algebraCongr (a.σ.apply_symm_apply O).symm x) := rfl -@[simp] lemma region_id (Λ : Finset sites) : (Covariance.id N).region Λ = Λ := by - simp [region, Covariance.id] +@[simp] lemma region_id (O : K) : (Covariance.id N).region O = O := + rfl -@[simp] lemma region_comp (a b : N.Covariance) (Λ : Finset sites) : - (a.comp b).region Λ = a.region (b.region Λ) := by - simp [region, Covariance.comp, Finset.map_map, Equiv.trans_toEmbedding] +@[simp] lemma region_comp (a b : N.Covariance) (O : K) : + (a.comp b).region O = a.region (b.region O) := + rfl lemma id_comp (a : N.Covariance) : (Covariance.id N).comp a = a := by - refine Covariance.ext ?_ fun Λ x e => ?_ - · simp [Covariance.comp, Covariance.id] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, id_β_apply] - erw [algebraCongr_trans] - rfl + refine Covariance.ext ?_ fun O x e => ?_ + · exact OrderIso.ext rfl + · exact N.algebraCongr_self e _ lemma comp_id (a : N.Covariance) : a.comp (Covariance.id N) = a := by - refine Covariance.ext ?_ fun Λ x e => ?_ - · simp [Covariance.comp, Covariance.id] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply, id_β_apply] - erw [a.β_algebraCongr, algebraCongr_trans] - rfl + refine Covariance.ext ?_ fun O x e => ?_ + · exact OrderIso.ext rfl + · exact N.algebraCongr_self e _ lemma comp_assoc (a b c : N.Covariance) : (a.comp b).comp c = a.comp (b.comp c) := by - refine Covariance.ext ?_ fun Λ x e => ?_ - · simp [Covariance.comp, Equiv.trans_assoc] - · rw [algebraCongr_eq_iff] - simp only [comp_β_apply] - erw [a.β_algebraCongr, algebraCongr_trans, algebraCongr_trans, algebraCongr_trans] - rfl + refine Covariance.ext ?_ fun O x e => ?_ + · exact OrderIso.ext rfl + · exact N.algebraCongr_self e _ lemma inv_comp (a : N.Covariance) : (Covariance.inv a).comp a = Covariance.id N := by - refine Covariance.ext ?_ fun Λ x e => ?_ - · simp [Covariance.comp, Covariance.inv, Covariance.id, Equiv.self_trans_symm] + refine Covariance.ext ?_ fun O x e => ?_ + · exact OrderIso.ext (funext fun O => a.σ.symm_apply_apply O) · rw [algebraCongr_eq_iff] simp only [comp_β_apply, inv_β_apply, id_β_apply] - erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply, algebraCongr_trans, - algebraCongr_trans] - · rfl - · simp [Finset.map_map] + erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply] + rfl /-- The covariances of a local net form a **group** under composition, with `Covariance.id` the unit and `Covariance.inv` the inverse. -/ @@ -193,6 +189,23 @@ lemma one_def : (1 : N.Covariance) = Covariance.id N := rfl /-- The group inverse is the inverse covariance. -/ lemma inv_def (a : N.Covariance) : a⁻¹ = a.inv := rfl +/-! ### Lattice covariances from site permutations -/ + +/-- Build a covariance of a lattice net (`K = Finset sites`) from a **site permutation**: the + induced region automorphism is `Λ ↦ Λ.map σ`, which preserves disjointness. This recovers the + site-permutation covariances of spin-system nets (Naaijkens 2012 §3.2); conversely, every + covariance of a lattice net arises this way, since an order automorphism of `Finset sites` + preserves atoms (singletons) and is therefore induced by a permutation of the sites. -/ +def ofSitePerm {sites : Type*} {N : LocalNet (Finset sites)} (σ : sites ≃ sites) + (β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding)) + (β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), + β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x)) : + N.Covariance where + σ := { toEquiv := σ.finsetCongr, map_rel_iff' := Finset.map_subset_map } + map_orthogonal_iff _ _ := Finset.disjoint_map _ + β := β + β_incl h x := β_incl h x + end Covariance end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index e261ad8..b6b3ad1 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -1,81 +1,156 @@ module - - public import Mathlib.Analysis.CStarAlgebra.Classes public import Mathlib.Order.DirectedInverseSystem /-! # Local nets of C⋆-algebras -This file contains the abstract **local net** data: finite regions are assigned local C⋆-algebras, -with functorial isotony embeddings and locality. It deliberately stops at the net-level axioms; -in particular, additivity/generation axioms (e.g. `𝔄(Λ₁ ∪ Λ₂)` being generated by the images of -`𝔄(Λ₁)` and `𝔄(Λ₂)`, as in tensor-product spin-system nets) are intentionally out of scope here -and belong to concrete instantiations. +This file contains the abstract **local net** data in Haag–Kastler form: the regions form an +abstract *causal index set* — a partially ordered set `K` (in the literature, the open bounded +regions of spacetime ordered by inclusion) equipped with a causal orthogonality relation +`O₁ ⟂ O₂` (`CausalOrthogonality`, abstracting spacelike separation) — and each region is assigned +a local C⋆-algebra, with functorial isotony embeddings and locality. Lattice (quantum spin system) +nets are the instance `K = Finset sites` with `⟂ = Disjoint`; nothing in this file assumes +directedness, so non-directed index sets (wedges, spacelike cones) are also in scope. -The quasi-local algebra built from a net lives in `LocalNet.QuasiLocalAlgebra`; covariance data and -its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. +The file deliberately stops at the net-level axioms; in particular, additivity/generation axioms +(e.g. `𝔄(O₁ ⊔ O₂)` being generated by the images of `𝔄(O₁)` and `𝔄(O₂)`, as in tensor-product +spin-system nets) are intentionally out of scope here and belong to concrete instantiations. + +The quasi-local algebra built from a net lives in `LocalNet.QuasiLocalAlgebra` (and requires the +index set to be directed); covariance data and its action live in `LocalNet.Covariance` / +`LocalNet.QuasiLocalAlgebra`. -/ @[expose] public section -/-- A **local net of C⋆-algebras** over the finite regions of a site set `sites`: the assignment - `Λ ↦ 𝔄(Λ)` together with isotony embeddings `incl : 𝔄(Λ) →⋆ₐ[ℂ] 𝔄(Λ')` for `Λ ⊆ Λ'`, +/-! ### Causal index sets -/ + +/-- A **causal orthogonality relation** on an index set of regions: `O₁ ⟂ O₂` abstracts causal + (spacelike) disjointness of regions, the relation under which the Haag–Kastler locality axiom + applies. It is symmetric and hereditary under shrinking regions. + + Of the causal-index-set axiomatizations in the literature (Roberts; Guido–Longo–Roberts–Verch) + this class keeps only symmetry and heredity — the minimal core needed for locality, the + quasi-local algebra, and the split property. The existence of causal complements + (`∀ O₁, ∃ O₂, O₁ ⟂ O₂`), needed for DHR sector theory, is intentionally not required. + + The relation is *not* required to be irreflexive: `O ⟂ O` legitimately holds for degenerate + regions (e.g. the empty lattice region) and forces `𝔄(O)` to be commutative. For Minkowski + double cones one instantiates `⟂` with spacelike separation — note this is *not* set + disjointness (disjoint timelike-separated regions are not causally orthogonal), which is why + the relation is carried as data rather than derived from the order. -/ +class CausalOrthogonality (K : Type*) [Preorder K] where + /-- The causal orthogonality relation `O₁ ⟂ O₂` on regions. -/ + Orthogonal : K → K → Prop + /-- Causal orthogonality is symmetric. -/ + orthogonal_symm : ∀ ⦃O₁ O₂ : K⦄, Orthogonal O₁ O₂ → Orthogonal O₂ O₁ + /-- Causal orthogonality is hereditary under shrinking the left region. -/ + orthogonal_mono_left : ∀ ⦃O₀ O₁ O₂ : K⦄, O₀ ≤ O₁ → Orthogonal O₁ O₂ → Orthogonal O₀ O₂ + +namespace CausalOrthogonality + +/-- `O₁ ⟂ O₂` : the regions `O₁` and `O₂` are causally orthogonal (spacelike separated). + + The token `⟂` is also used globally by Mathlib for `Submodule.IsOrtho` at precedence 50; + this scoped notation is declared at the same precedence so that the two coexist by + type-directed disambiguation. -/ +scoped infixl:50 " ⟂ " => CausalOrthogonality.Orthogonal + +variable {K : Type*} [Preorder K] [CausalOrthogonality K] + +/-- Causal orthogonality is symmetric (dot-notation form). -/ +theorem Orthogonal.symm {O₁ O₂ : K} (h : O₁ ⟂ O₂) : O₂ ⟂ O₁ := + orthogonal_symm h + +/-- Causal orthogonality is hereditary under shrinking the left region. -/ +theorem Orthogonal.mono_left {O₀ O₁ O₂ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⟂ O₂) : O₀ ⟂ O₂ := + orthogonal_mono_left h₀ h + +/-- Causal orthogonality is hereditary under shrinking the right region. -/ +theorem Orthogonal.mono_right {O₁ O₂ O₃ : K} (h₀ : O₃ ≤ O₂) (h : O₁ ⟂ O₂) : O₁ ⟂ O₃ := + (h.symm.mono_left h₀).symm + +/-- Causal orthogonality is hereditary under shrinking both regions. -/ +theorem Orthogonal.mono {O₁' O₁ O₂' O₂ : K} (h₁ : O₁' ≤ O₁) (h₂ : O₂' ≤ O₂) (h : O₁ ⟂ O₂) : + O₁' ⟂ O₂' := + (h.mono_left h₁).mono_right h₂ + +end CausalOrthogonality + +open scoped CausalOrthogonality + +/-- On the finite regions of a lattice of sites, causal orthogonality is plain set disjointness: + a lattice net is kinematical (equal-time), so "spacelike separated" degenerates to "disjoint in + space" (Naaijkens 2012 §3.4). -/ +instance {α : Type*} : CausalOrthogonality (Finset α) where + Orthogonal := Disjoint + orthogonal_symm _ _ h := h.symm + orthogonal_mono_left _ _ _ h₀ h := h.mono_left h₀ + +/-- A **local net of C⋆-algebras** over a causal index set `K` — a partially ordered set of + regions with a causal orthogonality relation `⟂` (`CausalOrthogonality`): the assignment + `O ↦ 𝔄(O)` together with isotony embeddings `incl : 𝔄(O) →⋆ₐ[ℂ] 𝔄(O')` for `O ≤ O'`, functorial (`incl_refl`/`incl_trans`) and local (`locality`). This is the Haag–Kastler net - structure for a lattice of sites, *without* the injectivity requirement on the isotony + structure over an abstract index set, *without* the injectivity requirement on the isotony embeddings; the literature's net (Naaijkens 2012 §3.4) is `LocalNet` together with the - `Faithful` class, which carries that requirement. -/ -structure LocalNet (sites : Type*) [DecidableEq sites] where - /-- The local C⋆-algebra `𝔄(Λ)` assigned to a finite region. The axioms force `𝔄(∅)` to be - commutative (instantiate `locality` at `Λ₁ = Λ₂ = Λ = ∅`) but do *not* force it to be - trivial: the literature's `𝔄(∅) = ℂ·1` is not required and must be imposed by a concrete - instantiation when needed. -/ - algebra : Finset sites → Type* + `Faithful` class, which carries that requirement. Lattice nets are the instance + `K = Finset sites` with `⟂ = Disjoint`. -/ +structure LocalNet (K : Type*) [PartialOrder K] [CausalOrthogonality K] where + /-- The local C⋆-algebra `𝔄(O)` assigned to a region. For any self-orthogonal region `O ⟂ O` + (e.g. the empty lattice region) the axioms force `𝔄(O)` to be commutative (instantiate + `locality` at `O₁ = O₂ = O`) but do *not* force it to be trivial: the literature's + `𝔄(∅) = ℂ·1` is not required and must be imposed by a concrete instantiation when needed. -/ + algebra : K → Type* /-- Each local algebra is a (complex) C⋆-algebra. -/ - [algebraCStar : ∀ Λ, CStarAlgebra (algebra Λ)] - /-- **Isotony**: for `Λ ⊆ Λ'` an inclusion of local algebras as a unital `*`-homomorphism. -/ - incl : ∀ {Λ Λ' : Finset sites}, Λ ⊆ Λ' → (algebra Λ →⋆ₐ[ℂ] algebra Λ') - /-- The identity inclusion `Λ ⊆ Λ` acts as the identity. -/ - incl_refl : ∀ {Λ : Finset sites} (x : algebra Λ), incl (Finset.Subset.refl Λ) x = x + [algebraCStar : ∀ O, CStarAlgebra (algebra O)] + /-- **Isotony**: for `O ≤ O'` an inclusion of local algebras as a unital `*`-homomorphism. -/ + incl : ∀ {O O' : K}, O ≤ O' → (algebra O →⋆ₐ[ℂ] algebra O') + /-- The identity inclusion `O ≤ O` acts as the identity. -/ + incl_refl : ∀ {O : K} (x : algebra O), incl (le_refl O) x = x /-- **Functoriality**: the inclusions compose, so the net is a directed system. -/ - incl_trans : ∀ {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (x : algebra Λ₁), + incl_trans : ∀ {O₁ O₂ O₃ : K} (h₁₂ : O₁ ≤ O₂) (h₂₃ : O₂ ≤ O₃) (x : algebra O₁), incl h₂₃ (incl h₁₂ x) = incl (h₁₂.trans h₂₃) x - /-- **Locality** (microcausality): observables localised in *disjoint* regions commute inside - any common larger region. For a lattice net this is locality *in space* — the kinematical - (equal-time) analogue of relativistic Einstein causality, with spatial disjointness in place - of spacelike separation (Naaijkens 2012 §3.4). -/ - locality : ∀ {Λ₁ Λ₂ Λ : Finset sites} (h₁ : Λ₁ ⊆ Λ) (h₂ : Λ₂ ⊆ Λ), - Disjoint Λ₁ Λ₂ → ∀ (x : algebra Λ₁) (y : algebra Λ₂), - Commute (incl h₁ x) (incl h₂ y) + /-- **Locality** (microcausality, Einstein causality): observables localised in causally + orthogonal regions commute inside any common larger region. -/ + locality : ∀ {O₁ O₂ O : K} (h₁ : O₁ ≤ O) (h₂ : O₂ ≤ O), O₁ ⟂ O₂ → + ∀ (x : algebra O₁) (y : algebra O₂), Commute (incl h₁ x) (incl h₂ y) namespace LocalNet attribute [instance] algebraCStar -variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) +section SemilatticeSup -/-- Smart constructor for `LocalNet` taking locality only inside the canonical union region - `Λ₁ ∪ Λ₂`: given `incl_trans`, commutation there pushes forward along - `incl : 𝔄(Λ₁ ∪ Λ₂) →⋆ₐ[ℂ] 𝔄(Λ)` to any common superregion `Λ`, so the union case is - equivalent to the general `locality` field. -/ -def mk' (algebra : Finset sites → Type*) [algebraCStar : ∀ Λ, CStarAlgebra (algebra Λ)] - (incl : ∀ {Λ Λ' : Finset sites}, Λ ⊆ Λ' → (algebra Λ →⋆ₐ[ℂ] algebra Λ')) - (incl_refl : ∀ {Λ : Finset sites} (x : algebra Λ), incl (Finset.Subset.refl Λ) x = x) - (incl_trans : ∀ {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁₂ : Λ₁ ⊆ Λ₂) (h₂₃ : Λ₂ ⊆ Λ₃) (x : algebra Λ₁), +variable {K : Type*} [SemilatticeSup K] [CausalOrthogonality K] + +/-- Smart constructor for `LocalNet` over a join-semilattice of regions, taking locality only + inside the canonical join region `O₁ ⊔ O₂`: given `incl_trans`, commutation there pushes + forward along `incl : 𝔄(O₁ ⊔ O₂) →⋆ₐ[ℂ] 𝔄(O)` to any common superregion `O`, so the join case + is equivalent to the general `locality` field. For lattice nets (`K = Finset sites`) the join + is the union of regions. -/ +def mk' (algebra : K → Type*) [algebraCStar : ∀ O, CStarAlgebra (algebra O)] + (incl : ∀ {O O' : K}, O ≤ O' → (algebra O →⋆ₐ[ℂ] algebra O')) + (incl_refl : ∀ {O : K} (x : algebra O), incl (le_refl O) x = x) + (incl_trans : ∀ {O₁ O₂ O₃ : K} (h₁₂ : O₁ ≤ O₂) (h₂₃ : O₂ ≤ O₃) (x : algebra O₁), incl h₂₃ (incl h₁₂ x) = incl (h₁₂.trans h₂₃) x) - (locality_union : ∀ {Λ₁ Λ₂ : Finset sites}, Disjoint Λ₁ Λ₂ → - ∀ (x : algebra Λ₁) (y : algebra Λ₂), - Commute (incl Finset.subset_union_left x) (incl Finset.subset_union_right y)) : - LocalNet sites where + (locality_sup : ∀ {O₁ O₂ : K}, O₁ ⟂ O₂ → + ∀ (x : algebra O₁) (y : algebra O₂), + Commute (incl le_sup_left x) (incl le_sup_right y)) : + LocalNet K where algebra := algebra incl := incl incl_refl := incl_refl incl_trans := incl_trans - locality h₁ h₂ hdisj x y := by - have h := (locality_union hdisj x y).map (incl (Finset.union_subset h₁ h₂)) + locality h₁ h₂ hortho x y := by + have h := (locality_sup hortho x y).map (incl (sup_le h₁ h₂)) rwa [incl_trans, incl_trans] at h +end SemilatticeSup + +variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] (N : LocalNet K) + /-- The net forms a directed system of `*`-algebras: the isotony embeddings compose and the identity inclusion is the identity. -/ instance directedSystem : @@ -95,37 +170,37 @@ non-degeneracy condition). The quasi-local C⋆-norm built from this hypothesis §3.4), so a faithful local net — `LocalNet` together with `Faithful` — is the literature's net. Carried as a typeclass rather than a structure field so algebraic constructions can state the non-degeneracy hypothesis only where they need it. -/ -class Faithful {sites : Type*} [DecidableEq sites] (N : LocalNet sites) : Prop where +class Faithful {K : Type*} [PartialOrder K] [CausalOrthogonality K] (N : LocalNet K) : Prop where /-- Every isotony embedding of the net is injective. -/ - incl_injective : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ'), Function.Injective (N.incl h) + incl_injective : ∀ {O O' : K} (h : O ≤ O'), Function.Injective (N.incl h) /-! ### Region-equality transport -/ /-- Transport a local algebra along an equality of regions, as a `*`-isomorphism. Used to identify local algebras whose regions are propositionally equal. -/ -def algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') : N.algebra Λ ≃⋆ₐ[ℂ] N.algebra Λ' := by +def algebraCongr {O O' : K} (h : O = O') : N.algebra O ≃⋆ₐ[ℂ] N.algebra O' := by subst h; exact StarAlgEquiv.refl /-- The isotony embeddings are natural with respect to the region-equality transport. -/ -lemma incl_algebraCongr {Λ₁ Λ₂ Λ₁' Λ₂' : Finset sites} (e₁ : Λ₁ = Λ₁') (e₂ : Λ₂ = Λ₂') - (h : Λ₁ ⊆ Λ₂) (h' : Λ₁' ⊆ Λ₂') (x : N.algebra Λ₁) : +lemma incl_algebraCongr {O₁ O₂ O₁' O₂' : K} (e₁ : O₁ = O₁') (e₂ : O₂ = O₂') + (h : O₁ ≤ O₂) (h' : O₁' ≤ O₂') (x : N.algebra O₁) : N.algebraCongr e₂ (N.incl h x) = N.incl h' (N.algebraCongr e₁ x) := by subst e₁; subst e₂; rfl /-- Transports along composable region equalities compose. -/ -@[simp] lemma algebraCongr_trans {Λ₁ Λ₂ Λ₃ : Finset sites} (h₁ : Λ₁ = Λ₂) (h₂ : Λ₂ = Λ₃) - (x : N.algebra Λ₁) : +@[simp] lemma algebraCongr_trans {O₁ O₂ O₃ : K} (h₁ : O₁ = O₂) (h₂ : O₂ = O₃) + (x : N.algebra O₁) : N.algebraCongr h₂ (N.algebraCongr h₁ x) = N.algebraCongr (h₁.trans h₂) x := by subst h₁; subst h₂; rfl /-- A transport along a reflexive region equality is the identity. -/ -@[simp] lemma algebraCongr_self {Λ : Finset sites} (h : Λ = Λ) (x : N.algebra Λ) : +@[simp] lemma algebraCongr_self {O : K} (h : O = O) (x : N.algebra O) : N.algebraCongr h x = x := by rw [Subsingleton.elim h rfl]; rfl /-- Cancelling a transport against a target value moves it to the other side. -/ -lemma algebraCongr_eq_iff {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) - (y : N.algebra Λ') : N.algebraCongr h x = y ↔ x = N.algebraCongr h.symm y := by +lemma algebraCongr_eq_iff {O O' : K} (h : O = O') (x : N.algebra O) + (y : N.algebra O') : N.algebraCongr h x = y ↔ x = N.algebraCongr h.symm y := by subst h; simp end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean index 413c41e..bf6afbd 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean @@ -9,14 +9,17 @@ public import QuantumSystem.ForMathlib.Topology.Algebra.CStarCompletion # The quasi-local algebra of a local net The **algebra of local observables** and the **quasi-local C⋆-algebra** of an abstract local net -`LocalNet`. These constructions apply to *any* local net. +`LocalNet`. These constructions apply to any local net over a *directed* causal index set +(`IsDirectedOrder`, with a region to start from, `Nonempty`): directedness is what makes the +union of the local algebras an algebra. Lattice nets (`K = Finset sites`) are directed by unions +with the empty region as base point. -* `LocalNet.quasiLocalAlgebra` is the algebraic inductive limit `‾⋃_Λ 𝔄(Λ)` of the local algebras +* `LocalNet.quasiLocalAlgebra` is the algebraic inductive limit `‾⋃_O 𝔄(O)` of the local algebras along the isotony embeddings, with cocone `ιLocal`, exhaustion (`exists_ιLocal`) and locality - (`ιLocal_commute_of_disjoint`). + (`ιLocal_commute_of_orthogonal`). * For a `Faithful` net the connecting maps are isometric, so the algebra of local observables carries a C⋆-norm whose completion `LocalNet.quasiLocalCStarAlgebra` is the AQFT quasi-local - algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2), with dense local + algebra `𝔄 = ‾⋃_O 𝔄(O)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2), with dense local embeddings `ιLocalCStar`. A `LocalNet.Covariance` (defined in `LocalNet.Covariance`) acts on these algebras: its per-region @@ -31,11 +34,14 @@ observables, which is functorial and is shown `ℂ`-linear and `*`-preserving namespace LocalNet -variable {sites : Type*} [DecidableEq sites] (N : LocalNet sites) +open scoped CausalOrthogonality + +variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] +variable (N : LocalNet K) /-! ### Algebra of local observables -These constructions apply to any abstract local net. +These constructions apply to any abstract local net over a directed causal index set. -/ /-- The **algebra of local observables** of the net: the algebraic inductive limit of the local @@ -43,61 +49,57 @@ These constructions apply to any abstract local net. noncomputable abbrev quasiLocalAlgebra : Type _ := DirectLimit N.algebra (fun _ _ h => N.incl h) +omit [Nonempty K] in /-- Componentwise behaviour of the involution on the algebra of local observables. The `Star`, `StarRing`, `Algebra ℂ` and `StarModule ℂ` instances come from the general - direct-limit constructions, since each `algebra Λ` is a `ℂ`-`*`-algebra and `incl` is a + direct-limit constructions, since each `algebra O` is a `ℂ`-`*`-algebra and `incl` is a `*`-algebra homomorphism. -/ -@[simp] lemma star_mk {Λ : Finset sites} (X : N.algebra Λ) : - star (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨Λ, star X⟩⟧ := rfl +@[simp] lemma star_mk {O : K} (X : N.algebra O) : + star (⟦⟨O, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨O, star X⟩⟧ := rfl -/-- The canonical embedding `𝔄(Λ) ↪ 𝔄_loc` of a local algebra into the algebra of local +/-- The canonical embedding `𝔄(O) ↪ 𝔄_loc` of a local algebra into the algebra of local observables, as a unital ring homomorphism (the cocone of the inductive limit). -/ -noncomputable def ιLocal (Λ : Finset sites) : - N.algebra Λ →+* N.quasiLocalAlgebra := - DirectLimit.Ring.of N.algebra (fun _ _ h => N.incl h) Λ - -/-- Compatibility of the cocone with the isotony embeddings: including `X` from `Λ` into the - larger region `Λ'` and then into `𝔄_loc` is the same as including `X` directly. -/ -@[simp] lemma ιLocal_incl {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (X : N.algebra Λ) : - N.ιLocal Λ' (N.incl h X) = N.ιLocal Λ X := +noncomputable def ιLocal (O : K) : + N.algebra O →+* N.quasiLocalAlgebra := + DirectLimit.Ring.of N.algebra (fun _ _ h => N.incl h) O + +/-- Compatibility of the cocone with the isotony embeddings: including `X` from `O` into the + larger region `O'` and then into `𝔄_loc` is the same as including `X` directly. -/ +@[simp] lemma ιLocal_incl {O O' : K} (h : O ≤ O') (X : N.algebra O) : + N.ιLocal O' (N.incl h X) = N.ιLocal O X := DirectLimit.Ring.of_f (G := N.algebra) (f := fun _ _ h => N.incl h) h X /-- The cocone is a `*`-homomorphism: it intertwines the local and quasi-local involutions. -/ -@[simp] lemma ιLocal_star {Λ : Finset sites} (X : N.algebra Λ) : - N.ιLocal Λ (star X) = star (N.ιLocal Λ X) := +@[simp] lemma ιLocal_star {O : K} (X : N.algebra O) : + N.ιLocal O (star X) = star (N.ιLocal O X) := (star_mk (N := N) X).symm /-- The cocone of the inductive limit absorbs the region-equality transport. -/ -@[simp] lemma ιLocal_algebraCongr {Λ Λ' : Finset sites} (h : Λ = Λ') (x : N.algebra Λ) : - N.ιLocal Λ' (N.algebraCongr h x) = N.ιLocal Λ x := by +@[simp] lemma ιLocal_algebraCongr {O O' : K} (h : O = O') (x : N.algebra O) : + N.ιLocal O' (N.algebraCongr h x) = N.ιLocal O x := by subst h; rfl /-- **Exhaustion**: every element of the algebra of local observables is the image of a local - observable from some finite region — the union of the local algebras is the whole limit. -/ + observable from some region — the union of the local algebras is the whole limit. -/ theorem exists_ιLocal (z : N.quasiLocalAlgebra) : - ∃ (Λ : Finset sites) (X : N.algebra Λ), z = N.ιLocal Λ X := by + ∃ (O : K) (X : N.algebra O), z = N.ιLocal O X := by induction z using DirectLimit.induction with - | _ Λ X => exact ⟨Λ, X, rfl⟩ - -/-- **Locality in the algebra of local observables**: observables localised in disjoint regions - commute inside `𝔄_loc`. Lifts the net's `locality` along the ring-hom cocone. -/ -theorem ιLocal_commute_of_disjoint {Λ₁ Λ₂ : Finset sites} (hd : Disjoint Λ₁ Λ₂) - (X : N.algebra Λ₁) (Y : N.algebra Λ₂) : - Commute (N.ιLocal Λ₁ X) (N.ιLocal Λ₂ Y) := by - have h1 : N.ιLocal Λ₁ X - = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_left X) := - (N.ιLocal_incl Finset.subset_union_left X).symm - have h2 : N.ιLocal Λ₂ Y - = N.ιLocal (Λ₁ ∪ Λ₂) (N.incl Finset.subset_union_right Y) := - (N.ιLocal_incl Finset.subset_union_right Y).symm - rw [h1, h2] - exact (N.locality Finset.subset_union_left Finset.subset_union_right hd X Y).map - (N.ιLocal (Λ₁ ∪ Λ₂)) + | _ O X => exact ⟨O, X, rfl⟩ + +/-- **Locality in the algebra of local observables**: observables localised in causally orthogonal + regions commute inside `𝔄_loc`. Pushes both observables into a directed upper bound of the two + regions and lifts the net's `locality` along the ring-hom cocone. -/ +theorem ιLocal_commute_of_orthogonal {O₁ O₂ : K} (hd : O₁ ⟂ O₂) + (X : N.algebra O₁) (Y : N.algebra O₂) : + Commute (N.ιLocal O₁ X) (N.ιLocal O₂ Y) := by + obtain ⟨O, h₁, h₂⟩ := directed_of (· ≤ ·) O₁ O₂ + rw [← N.ιLocal_incl h₁ X, ← N.ιLocal_incl h₂ Y] + exact (N.locality h₁ h₂ hd X Y).map (N.ιLocal O) /-! ### Faithful nets and the quasi-local C⋆-algebra For a faithful net the connecting maps are isometric, so the algebra of local observables carries -a C⋆-norm whose completion is the quasi-local C⋆-algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)`. +a C⋆-norm whose completion is the quasi-local C⋆-algebra `𝔄 = ‾⋃_O 𝔄(O)`. -/ section CStar @@ -109,56 +111,57 @@ variable [N.Faithful] noncomputable instance : NormedRing N.quasiLocalAlgebra := DirectLimit.cstarNormedRing (fun _ _ h => Faithful.incl_injective h) -@[simp] lemma norm_mk {Λ : Finset sites} (X : N.algebra Λ) : - ‖(⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl +@[simp] lemma norm_mk {O : K} (X : N.algebra O) : + ‖(⟦⟨O, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl /-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ noncomputable instance : NormedAlgebra ℂ N.quasiLocalAlgebra where norm_smul_le c x := by induction x using DirectLimit.induction with - | _ Λ X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X + | _ O X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X /-- `star` is isometric on the algebra of local observables. -/ instance : NormedStarGroup N.quasiLocalAlgebra where norm_star_le x := by induction x using DirectLimit.induction with - | _ Λ X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le + | _ O X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le /-- The C⋆-identity holds on the algebra of local observables. -/ instance : CStarRing N.quasiLocalAlgebra where norm_mul_self_le x := by induction x using DirectLimit.induction with - | _ Λ X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] + | _ O X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] exact CStarRing.norm_mul_self_le X /-- The **quasi-local C⋆-algebra** of a faithful net: the completion of the algebra of local - observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_Λ 𝔄(Λ)`. -/ + observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_O 𝔄(O)`. -/ noncomputable abbrev quasiLocalCStarAlgebra : Type _ := UniformSpace.Completion N.quasiLocalAlgebra noncomputable example : CStarAlgebra N.quasiLocalCStarAlgebra := inferInstance -/-- The canonical embedding `𝔄(Λ) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, +/-- The canonical embedding `𝔄(O) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ -noncomputable def ιLocalCStar (Λ : Finset sites) : - N.algebra Λ → N.quasiLocalCStarAlgebra := - (↑) ∘ N.ιLocal Λ +noncomputable def ιLocalCStar (O : K) : + N.algebra O → N.quasiLocalCStarAlgebra := + (↑) ∘ N.ιLocal O /-- The local algebras are dense in the quasi-local C⋆-algebra: every element is a norm-limit of local observables. -/ theorem denseRange_iUnion_ιLocalCStar : - Dense (⋃ Λ : Finset sites, Set.range (N.ιLocalCStar Λ)) := by + Dense (⋃ O : K, Set.range (N.ιLocalCStar O)) := by refine UniformSpace.Completion.denseRange_coe.mono ?_ rintro _ ⟨z, rfl⟩ - obtain ⟨Λ, X, rfl⟩ := N.exists_ιLocal z - exact Set.mem_iUnion.2 ⟨Λ, X, rfl⟩ + obtain ⟨O, X, rfl⟩ := N.exists_ιLocal z + exact Set.mem_iUnion.2 ⟨O, X, rfl⟩ -/-- **Locality in the quasi-local C⋆-algebra**: observables localised in disjoint regions commute - inside `𝔄`. Transports `ιLocal_commute_of_disjoint` along the completion coercion. -/ -theorem ιLocalCStar_commute_of_disjoint {Λ₁ Λ₂ : Finset sites} (hd : Disjoint Λ₁ Λ₂) - (X : N.algebra Λ₁) (Y : N.algebra Λ₂) : - Commute (N.ιLocalCStar Λ₁ X) (N.ιLocalCStar Λ₂ Y) := - (N.ιLocal_commute_of_disjoint hd X Y).map UniformSpace.Completion.coeRingHom +/-- **Locality in the quasi-local C⋆-algebra**: observables localised in causally orthogonal + regions commute inside `𝔄`. Transports `ιLocal_commute_of_orthogonal` along the completion + coercion. -/ +theorem ιLocalCStar_commute_of_orthogonal {O₁ O₂ : K} (hd : O₁ ⟂ O₂) + (X : N.algebra O₁) (Y : N.algebra O₂) : + Commute (N.ιLocalCStar O₁ X) (N.ιLocalCStar O₂ Y) := + (N.ιLocal_commute_of_orthogonal hd X Y).map UniformSpace.Completion.coeRingHom end CStar @@ -168,18 +171,18 @@ variable {N} (a : N.Covariance) /-! ### The induced covariance action -/ -/-- The **covariance action** `β_a ⟦⟨Λ, X⟩⟧ = ⟦⟨σΛ, β_Λ X⟩⟧` of a covariance on the algebra of local +/-- The **covariance action** `β_a ⟦⟨O, X⟩⟧ = ⟦⟨σO, β_O X⟩⟧` of a covariance on the algebra of local observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra - (fun Λ => (N.ιLocal (a.region Λ)).comp (a.β Λ).toAlgEquiv.toAlgHom.toRingHom) - (fun Λ Λ' h X => by - change N.ιLocal (a.region Λ') (a.β Λ' (N.incl h X)) = N.ιLocal (a.region Λ) (a.β Λ X) + (fun O => (N.ιLocal (a.region O)).comp (a.β O).toAlgEquiv.toAlgHom.toRingHom) + (fun O O' h X => by + change N.ιLocal (a.region O') (a.β O' (N.incl h X)) = N.ιLocal (a.region O) (a.β O X) rw [a.β_incl h] exact N.ιLocal_incl _ _) -@[simp] lemma quasiLocalCovariance_mk {Λ : Finset sites} (X : N.algebra Λ) : - a.quasiLocalCovariance (⟦⟨Λ, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region Λ, a.β Λ X⟩⟧ := +@[simp] lemma quasiLocalCovariance_mk {O : K} (X : N.algebra O) : + a.quasiLocalCovariance (⟦⟨O, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region O, a.β O X⟩⟧ := rfl /-- The covariance action of the identity covariance is the identity: `β_{id} = id`. -/ @@ -187,7 +190,7 @@ noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalA (Covariance.id N).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with - | _ Λ X => rw [quasiLocalCovariance_mk, RingHom.id_apply]; exact N.ιLocal_algebraCongr _ X + | _ O X => rw [quasiLocalCovariance_mk, RingHom.id_apply]; rfl /-- **Functoriality of the covariance action**: composing covariances composes their actions, `β_{a∘b} = β_a ∘ β_b`. -/ @@ -195,9 +198,9 @@ noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalA (a.comp b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with - | _ Λ X => + | _ O X => simp only [RingHom.comp_apply, quasiLocalCovariance_mk] - exact N.ιLocal_algebraCongr _ _ + rfl /-- The covariance action sends the unit covariance to the identity: `β_1 = id`. -/ @[simp] lemma quasiLocalCovariance_one : @@ -215,7 +218,7 @@ lemma quasiLocalCovariance_mul (a b : N.Covariance) : lemma quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : a.quasiLocalCovariance (c • z) = c • a.quasiLocalCovariance z := by induction z using DirectLimit.induction with - | _ Λ X => + | _ O X => rw [DirectLimit.smul_def, quasiLocalCovariance_mk, quasiLocalCovariance_mk, DirectLimit.smul_def, map_smul] rfl @@ -225,7 +228,7 @@ lemma quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : lemma quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : a.quasiLocalCovariance (star z) = star (a.quasiLocalCovariance z) := by induction z using DirectLimit.induction with - | _ Λ X => + | _ O X => rw [star_mk, quasiLocalCovariance_mk, quasiLocalCovariance_mk, star_mk, map_star] rfl @@ -280,7 +283,7 @@ variable [N.Faithful] lemma quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : ‖a.quasiLocalCovariance z‖ = ‖z‖ := by induction z using DirectLimit.induction with - | _ Λ X => + | _ O X => rw [quasiLocalCovariance_mk, norm_mk, norm_mk] exact StarAlgEquiv.norm_map _ X From 71e9c27517fc3af6e11e7d1bb4c8935d7f092439 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 15:01:41 +0000 Subject: [PATCH 067/113] feat: add generated_mono for von Neumann algebras Co-Authored-By: Claude Fable 5 --- .../ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean index 1af10e0..33e16d0 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -147,6 +147,10 @@ lemma generated_le {s : Set (H →L[ℂ] H)} {M : VonNeumannAlgebra H} have h2 := commutant_le h1 rwa [VonNeumannAlgebra.commutant_commutant, VonNeumannAlgebra.commutant_commutant] at h2 +/-- The generated von Neumann algebra is monotone in the generating set. -/ +lemma generated_mono {s t : Set (H →L[ℂ] H)} (h : s ⊆ t) : generated s ≤ generated t := + generated_le fun _ hx => SetLike.mem_coe.mpr (mem_generated_of_mem (h hx)) + /-! ### Unitary conjugation of a von Neumann algebra -/ variable {H' : Type*} [NormedAddCommGroup H'] [InnerProductSpace ℂ H'] [CompleteSpace H'] From 83bb16e1a03a9e1078ff08eec6aa25624e22f004 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 15:04:24 +0000 Subject: [PATCH 068/113] refactor: restate split tensor decomposition in inclusion form Replace the commuting-pair hypotheses A1 <= N <= A2' by the Doplicher-Longo inclusion form A <= N <= B, concluding that A lands in the left tensor factor and B' in the right one. The docstrings now cite Doplicher-Longo for split inclusions and Buchholz for the AQFT split property instead of calling the commuting-pair condition 'the split property'; the old form is recovered by taking B := A2'. Co-Authored-By: Claude Fable 5 --- .../VonNeumannAlgebra/StructureTheorem.lean | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean index 3a72219..a662db6 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean @@ -56,8 +56,10 @@ carries the matrix unit `e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨ `U N U⋆ = B(ℓ²(F)) ⊗̄ 1`, with commutant companion `conj_spatialEquiv_commutant_eq_vnTensorRight`. * `VonNeumannAlgebra.IsFactor.exists_spatial_tensorDecomposition` — the existence headline. * `VonNeumannAlgebra.IsFactor.exists_split_tensorDecomposition` — the split tensor decomposition: - for an intermediate type I factor `A₁ ≤ N ≤ A₂'`, the same `U` sends `A₁` into `B(ℓ²(F)) ⊗̄ 1` - and `A₂` into `1 ⊗̄ B(eH)`. + for an inclusion `A ≤ B` of von Neumann algebras with intermediate type I factor `A ≤ N ≤ B` — + a *split inclusion* in the sense of Doplicher–Longo (see + `VonNeumannAlgebra.IsSplitInclusion`) — the same `U` sends `A` into `B(ℓ²(F)) ⊗̄ 1` and the + commutant `B′` into `1 ⊗̄ B(eH)`. -/ @[expose] public section @@ -481,31 +483,28 @@ theorem OrthEquivFam.conj_spatialEquiv_commutant_eq_vnTensorRight (hF : OrthEqui rw [← VonNeumannAlgebra.conj_commutant, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, vnTensorLeft_commutant] -/-- **Split inclusion (left factor).** Any von Neumann subalgebra `A₁ ≤ N` of the type I factor `N` -is carried by the spatial isomorphism into the left tensor factor: `U A₁ U⋆ ≤ B(ℓ²(F)) ⊗̄ 1`. This +/-- **Left factor absorption.** Any von Neumann subalgebra `A ≤ N` of the type I factor `N` +is carried by the spatial isomorphism into the left tensor factor: `U A U⋆ ≤ B(ℓ²(F)) ⊗̄ 1`. This is monotonicity of spatial conjugation composed with `U N U⋆ = vnTensorLeft`. -/ lemma OrthEquivFam.conj_spatialEquiv_le_vnTensorLeft (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] - {A₁ : VonNeumannAlgebra H} (h₁ : A₁ ≤ N) : - VonNeumannAlgebra.conj (hF.spatialEquiv htop) A₁ ≤ vnTensorLeft := + {A : VonNeumannAlgebra H} (h₁ : A ≤ N) : + VonNeumannAlgebra.conj (hF.spatialEquiv htop) A ≤ vnTensorLeft := (VonNeumannAlgebra.conj_mono _ h₁).trans_eq (hF.conj_spatialEquiv_eq_vnTensorLeft he htop) -/-- **Split inclusion (right factor).** Any von Neumann algebra `A₂` whose commutant contains `N` -(equivalently `A₂ ⊆ N'`) is carried by the spatial isomorphism into the right tensor factor: -`U A₂ U⋆ ≤ 1 ⊗̄ B(eH)`. The hypothesis `N ≤ A₂'` is the split-property condition; taking commutants -turns it into `A₂ ≤ N'`, and monotonicity composed with `U N' U⋆ = vnTensorRight` finishes. -/ +/-- **Right factor absorption.** For any von Neumann algebra `B` containing `N`, the commutant +`B′` is carried by the spatial isomorphism into the right tensor factor: `U B′ U⋆ ≤ 1 ⊗̄ B(eH)`. +Taking commutants in `N ≤ B` gives `B′ ≤ N′`, and monotonicity composed with +`U N′ U⋆ = vnTensorRight` finishes. -/ lemma OrthEquivFam.conj_spatialEquiv_le_vnTensorRight (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) [Nonempty F] [DecidableEq F] [CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H))] - {A₂ : VonNeumannAlgebra H} (h₂ : N ≤ A₂′) : - VonNeumannAlgebra.conj (hF.spatialEquiv htop) A₂ ≤ vnTensorRight := by - have hA₂ : A₂ ≤ N′ := by - have h := VonNeumannAlgebra.commutant_le h₂ - rwa [VonNeumannAlgebra.commutant_commutant] at h - exact (VonNeumannAlgebra.conj_mono _ hA₂).trans_eq + {B : VonNeumannAlgebra H} (h₂ : N ≤ B) : + VonNeumannAlgebra.conj (hF.spatialEquiv htop) B′ ≤ vnTensorRight := + (VonNeumannAlgebra.conj_mono _ (VonNeumannAlgebra.commutant_le h₂)).trans_eq (hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop) omit [CompleteSpace H] in @@ -547,22 +546,29 @@ theorem IsFactor.exists_spatial_tensorDecomposition {N : VonNeumannAlgebra H} exact ⟨F, hF.spatialEquiv htop, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop⟩ -/-- **Split tensor decomposition (Yngvason §5.1 (38)→(39)).** Suppose an intermediate type I factor -`N ⊆ B(H)` with minimal projection `e` is sandwiched between two von Neumann algebras, -`A₁ ≤ N ≤ A₂'` — the *split property* for the pair `(A₁, A₂)`. Then there is a spatial isomorphism -`U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` simultaneously tensor-splitting both algebras: `A₁` lands in the left -factor `B(ℓ²(F)) ⊗̄ 1` and `A₂` lands in the right factor `1 ⊗̄ B(eH)`, with `N` and its commutant -identified exactly. The existence of such an intermediate type I factor `N` is the -model-dependent split-property input; everything downstream of it is proved here. -/ +/-- **Split tensor decomposition (Yngvason §5.1 (38)→(39)).** Suppose an inclusion `A ≤ B` of von +Neumann algebras admits an intermediate factor `N ⊆ B(H)` with minimal projection `e` — that is, +`A ≤ N ≤ B` with `N` type I. The existence of such an `N` is precisely what makes `A ≤ B` a +*split inclusion* in the sense of Doplicher–Longo (*Standard and split inclusions of von Neumann +algebras*, Invent. Math. 75, 1984); the named form of that definition, `IsSplitInclusion`, and its +consequences live in `QuantumSystem.Algebra.VonNeumannAlgebra.SplitInclusion`. In AQFT the split +inclusions of interest are `𝓡(O₁) ≤ 𝓡(O₂)` for properly contained regions — the *split property* +of a local net (Buchholz, *Product states for local algebras*, Comm. Math. Phys. 36, 1974). + +The conclusion: there is a spatial isomorphism `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` simultaneously +tensor-splitting the inclusion — `A` lands in the left factor `B(ℓ²(F)) ⊗̄ 1` and the commutant +`B′` lands in the right factor `1 ⊗̄ B(eH)`, with `N` and its commutant identified exactly. The +commuting-pair form of this statement — `A₁ ≤ N ≤ A₂′` for a pair `(A₁, A₂)` — is recovered by +instantiating `B := A₂′`. -/ theorem IsFactor.exists_split_tensorDecomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) - {A₁ A₂ : VonNeumannAlgebra H} (h₁ : A₁ ≤ N) (h₂ : N ≤ A₂′) : + {A B : VonNeumannAlgebra H} (h₁ : A ≤ N) (h₂ : N ≤ B) : ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), VonNeumannAlgebra.conj U N = vnTensorLeft ∧ VonNeumannAlgebra.conj U N′ = vnTensorRight ∧ - VonNeumannAlgebra.conj U A₁ ≤ vnTensorLeft ∧ - VonNeumannAlgebra.conj U A₂ ≤ vnTensorRight := by + VonNeumannAlgebra.conj U A ≤ vnTensorLeft ∧ + VonNeumannAlgebra.conj U B′ ≤ vnTensorRight := by haveI := he.nontrivial obtain ⟨F, hF, htop⟩ := hN.exists_orthEquivFam_top he haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range From 952e4d1492b5c6a9c2ca9f5112d14dc107a2ded2 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 15:05:46 +0000 Subject: [PATCH 069/113] feat: add split inclusions of von Neumann algebras IsSplitInclusion A B holds when a type I factor interpolates A <= M <= B, following Doplicher-Longo (Invent. Math. 75, 1984). Includes the basic monotonicity API and the split tensor decomposition inherited from the type I structure theorem. Co-Authored-By: Claude Fable 5 --- .../VonNeumannAlgebra/SplitInclusion.lean | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean new file mode 100644 index 0000000..11f819c --- /dev/null +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean @@ -0,0 +1,89 @@ +module + +public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI + +/-! +# Split inclusions of von Neumann algebras + +An inclusion `A ≤ B` of von Neumann algebras on a Hilbert space is **split** when some type I +factor `M` interpolates: `A ≤ M ≤ B`. This is the definition of Doplicher–Longo, *Standard and +split inclusions of von Neumann algebras* (Invent. Math. 75, 1984) §1; the notion originates in +the analysis of local algebras by Buchholz, *Product states for local algebras* (Comm. Math. +Phys. 36, 1974), where the interpolating type I factor is what produces normal product states +across a commuting pair. The AQFT *split property* — this predicate applied to the inclusions +`𝓡(O₁) ≤ 𝓡(O₂)` of local von Neumann algebras of properly contained regions — lives at the net +level in `QuantumSystem.Algebra.LocalNet.SplitProperty`. + +The structural content of a split inclusion is the tensor decomposition +`IsSplitInclusion.exists_tensorDecomposition`: a spatial isomorphism `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` +carrying `A` into the tensor factor `B(ℓ²(F)) ⊗̄ 1` and the commutant `B′` into `1 ⊗̄ B(eH)`. It +is inherited from the type I structure theorem +(`QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem`). + +## Main definitions and results + +* `VonNeumannAlgebra.IsSplitInclusion A B` — some type I factor `M` satisfies `A ≤ M ≤ B`. +* `VonNeumannAlgebra.IsSplitInclusion.le` / `mono` — a split inclusion is an inclusion, and + splitness survives shrinking `A` and enlarging `B`. +* `VonNeumannAlgebra.IsSplitInclusion.exists_tensorDecomposition` — the split tensor + decomposition of the inclusion. +-/ + +@[expose] public section + +namespace VonNeumannAlgebra + +open HilbertTensor + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- **Split inclusion of von Neumann algebras** (Doplicher–Longo). An inclusion `A ≤ B` is +*split* when some type I factor `M` interpolates: `A ≤ M ≤ B`. The containment `A ≤ B` is not +part of the definition, since it follows (`IsSplitInclusion.le`). -/ +def IsSplitInclusion (A B : VonNeumannAlgebra H) : Prop := + ∃ M : VonNeumannAlgebra H, IsTypeIFactor M ∧ A ≤ M ∧ M ≤ B + +/-- A split inclusion is in particular an inclusion. -/ +lemma IsSplitInclusion.le {A B : VonNeumannAlgebra H} (h : IsSplitInclusion A B) : A ≤ B := + let ⟨_, _, h₁, h₂⟩ := h + h₁.trans h₂ + +/-- Splitness is preserved by shrinking the smaller algebra and enlarging the larger one. -/ +lemma IsSplitInclusion.mono {A A' B B' : VonNeumannAlgebra H} (hA : A' ≤ A) (hB : B ≤ B') + (h : IsSplitInclusion A B) : IsSplitInclusion A' B' := + let ⟨M, hM, h₁, h₂⟩ := h + ⟨M, hM, hA.trans h₁, h₂.trans hB⟩ + +/-- Any inclusion sandwiching a type I factor is split. -/ +lemma IsTypeIFactor.isSplitInclusion_of_le_of_le {M A B : VonNeumannAlgebra H} + (hM : IsTypeIFactor M) (h₁ : A ≤ M) (h₂ : M ≤ B) : IsSplitInclusion A B := + ⟨M, hM, h₁, h₂⟩ + +/-- A type I factor splits in itself: `IsSplitInclusion M M`. Consequently the reflexive +instances of the AQFT split property (`O₁ = O₂`) require the local algebras themselves to be +type I factors. -/ +lemma IsTypeIFactor.isSplitInclusion_self {M : VonNeumannAlgebra H} (hM : IsTypeIFactor M) : + IsSplitInclusion M M := + hM.isSplitInclusion_of_le_of_le le_rfl le_rfl + +/-- **Split tensor decomposition.** A split inclusion `A ≤ M ≤ B` is spatially tensor-split: +there is a linear isometric equivalence `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` (with `e` a minimal projection +of the interpolating type I factor `M`) under which `M` becomes exactly the tensor factor +`B(ℓ²(F)) ⊗̄ 1` and `M′` the factor `1 ⊗̄ B(eH)`, so that `A` lands in the left factor and the +commutant `B′` in the right factor. This is the inclusion-form structural consequence of the +split property (Doplicher–Longo; Buchholz), inherited from +`IsFactor.exists_split_tensorDecomposition`. -/ +theorem IsSplitInclusion.exists_tensorDecomposition {A B : VonNeumannAlgebra H} + (h : IsSplitInclusion A B) : + ∃ (M : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ℂ] H)) + (U : H ≃ₗᵢ[ℂ] HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), + IsMinimalProjection M e ∧ A ≤ M ∧ M ≤ B ∧ + VonNeumannAlgebra.conj U M = vnTensorLeft ∧ + VonNeumannAlgebra.conj U M′ = vnTensorRight ∧ + VonNeumannAlgebra.conj U A ≤ vnTensorLeft ∧ + VonNeumannAlgebra.conj U B′ ≤ vnTensorRight := by + obtain ⟨M, ⟨hMf, e, he⟩, h₁, h₂⟩ := h + obtain ⟨F, U, hM, hM', hA, hB⟩ := hMf.exists_split_tensorDecomposition he h₁ h₂ + exact ⟨M, e, F, U, he, h₁, h₂, hM, hM', hA, hB⟩ + +end VonNeumannAlgebra From b73ca0cc075c0c8fc0080a42669012b49deb5246 Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 15:06:34 +0000 Subject: [PATCH 070/113] feat: add star and isotony lemmas for the dense local embedding Co-Authored-By: Claude Fable 5 --- QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean index bf6afbd..834a9ce 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean @@ -146,6 +146,17 @@ noncomputable def ιLocalCStar (O : K) : N.algebra O → N.quasiLocalCStarAlgebra := (↑) ∘ N.ιLocal O +/-- The dense embedding is compatible with the isotony embeddings: including into a larger + region first does not change the image in the quasi-local C⋆-algebra. -/ +@[simp] lemma ιLocalCStar_incl {O O' : K} (h : O ≤ O') (X : N.algebra O) : + N.ιLocalCStar O' (N.incl h X) = N.ιLocalCStar O X := + congrArg _ (N.ιLocal_incl h X) + +/-- The dense embedding is a `*`-map: it intertwines the local and quasi-local involutions. -/ +@[simp] lemma ιLocalCStar_star {O : K} (X : N.algebra O) : + N.ιLocalCStar O (star X) = star (N.ιLocalCStar O X) := by + simp [ιLocalCStar] + /-- The local algebras are dense in the quasi-local C⋆-algebra: every element is a norm-limit of local observables. -/ theorem denseRange_iUnion_ιLocalCStar : From 8cdebb4abc6c976d913b53ac31adf29fa86fdf2d Mon Sep 17 00:00:00 2001 From: suzuki Date: Mon, 20 Jul 2026 15:28:33 +0000 Subject: [PATCH 071/113] feat: add the split property of a local net Define the local von Neumann algebras R(O) = pi(A(O))'' of a region in a representation of the quasi-local C*-algebra, with isotony and locality, and the split property of the net (Buchholz; Doplicher-Longo): for every properly contained pair O1 << O2, a type I factor interpolates between R(O1) and R(O2). Proper containment is carried by a new ProperContainment class on the causal index set, axiomatising containment, monotonicity and a causal collar, with a thickening-based constructor for lattice regions. The tensor splitting of each pair follows by applying IsSplitInclusion.exists_tensorDecomposition to SplitProperty.isSplitInclusion. The entropy files' forward references to the split net are aligned with the new module. Co-Authored-By: Claude Fable 5 --- QuantumSystem.lean | 2 + .../Algebra/LocalNet/SplitProperty.lean | 211 ++++++++++++++++++ .../Analysis/Entropy/MutualInformation.lean | 7 +- .../Analysis/Entropy/StrongSubadditivity.lean | 7 +- 4 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 QuantumSystem/Algebra/LocalNet/SplitProperty.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 5c94abf..16db151 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -20,10 +20,12 @@ public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful public import QuantumSystem.Algebra.LocalNet.Covariance public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra +public import QuantumSystem.Algebra.LocalNet.SplitProperty public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Algebra.VonNeumannAlgebra.Basic public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition +public import QuantumSystem.Algebra.VonNeumannAlgebra.SplitInclusion public import QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem public import QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI diff --git a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean new file mode 100644 index 0000000..f058d9a --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean @@ -0,0 +1,211 @@ +module + +public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra +public import QuantumSystem.Algebra.CStarAlgebra.Representation +public import QuantumSystem.Algebra.VonNeumannAlgebra.SplitInclusion + +/-! +# The split property of a local net + +The **split property** of a local net, in the form of Buchholz (*Product states for local +algebras*, Comm. Math. Phys. 36, 1974) and Doplicher–Longo (*Standard and split inclusions of +von Neumann algebras*, Invent. Math. 75, 1984): fix a representation `π` of the quasi-local +C⋆-algebra on a Hilbert space and form the **local von Neumann algebras** + + `𝓡(O) = π(𝔄(O))″` (`LocalNet.localVonNeumannAlgebra`); + +the net has the split property when, for every properly contained pair of regions `O₁ ⋐ O₂`, the +inclusion `𝓡(O₁) ≤ 𝓡(O₂)` is a split inclusion — some type I factor interpolates +(`VonNeumannAlgebra.IsSplitInclusion`). + +Proper containment `⋐` (`ProperContainment`) is the abstract form of the geometric relation +"the closure of `O₁` lies in the interior of `O₂`" of the QFT literature; on a causal index set +it is model-dependent geometric input, like the causal orthogonality `⟂` itself. The class only +axiomatises necessary conditions (containment, monotonicity, and a causal collar inside the outer +region); it is *not* a complete axiomatisation of properness — e.g. on lattice regions, where the +empty region is orthogonal to everything, plain containment `⊆` also satisfies the axioms — so +the split property is always relative to the chosen `⋐`. Unlike `CausalOrthogonality (Finset α)`, +there is no canonical `ProperContainment` instance on lattice regions: a genuine collar needs a +metric or graph structure on the sites, supplied e.g. through `ProperContainment.ofThicken`. + +Because the quasi-local algebra requires a directed index set, this formulation states the split +property for directed `K` only (Buchholz's double-cone setting); split inclusions of local +algebras over non-directed families (e.g. wedges) can still be stated pointwise through +`VonNeumannAlgebra.IsSplitInclusion`. The representation is not assumed nondegenerate — for +degenerate representations the property can hold trivially, as in the literature, and substantive +downstream theorems impose nondegeneracy or cyclicity where they need it. + +## Main definitions and results + +* `ProperContainment` — the proper-containment relation `O₁ ⋐ O₂` on a causal index set. +* `LocalNet.localVonNeumannAlgebra` — the local von Neumann algebra `𝓡(O) = π(𝔄(O))″` of a + region in a representation of the quasi-local algebra, with isotony + (`localVonNeumannAlgebra_mono`) and locality + (`localVonNeumannAlgebra_le_commutant_of_orthogonal`). +* `LocalNet.SplitProperty` — the split property of the net in the representation. +* `LocalNet.SplitProperty.isSplitInclusion` — the split inclusion of a properly contained pair; + Buchholz's tensor splitting between properly separated regions follows by applying + `VonNeumannAlgebra.IsSplitInclusion.exists_tensorDecomposition` to it. +-/ + +@[expose] public section + +open scoped CausalOrthogonality + +/-- **Proper containment of regions**: the abstract form of the relation `O₁ ⋐ O₂` ("the closure + of `O₁` lies in the interior of `O₂`") under which the split property of a local net is + stated. This is model-dependent geometric input on the causal index set, like `⟂` itself. + + The axioms are necessary conditions, not a complete axiomatisation of properness: containment, + monotonicity under shrinking the inner and enlarging the outer region, and a **causal collar** + — the outer region contains a region causally orthogonal to the inner one + (`exists_orthogonal_of_properlyContained`). On the Haag–Kastler index set of nonempty double + cones the collar axiom expresses genuine properness; on index sets with a region orthogonal + to everything (such as the empty lattice region) it is weaker, and plain containment also + satisfies the axioms — the split property is therefore always relative to the chosen `⋐`. -/ +class ProperContainment (K : Type*) [Preorder K] [CausalOrthogonality K] where + /-- The proper-containment relation `O₁ ⋐ O₂` on regions. -/ + ProperlyContained : K → K → Prop + /-- Proper containment implies containment. -/ + le_of_properlyContained : ∀ ⦃O₁ O₂ : K⦄, ProperlyContained O₁ O₂ → O₁ ≤ O₂ + /-- Proper containment survives shrinking the inner region and enlarging the outer one. -/ + properlyContained_mono : ∀ ⦃O₀ O₁ O₂ O₃ : K⦄, O₀ ≤ O₁ → ProperlyContained O₁ O₂ → O₂ ≤ O₃ → + ProperlyContained O₀ O₃ + /-- **Causal collar**: a properly containing region contains a region causally orthogonal to + the inner one. -/ + exists_orthogonal_of_properlyContained : ∀ ⦃O₁ O₂ : K⦄, ProperlyContained O₁ O₂ → + ∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ + +namespace ProperContainment + +/-- `O₁ ⋐ O₂` : the region `O₁` is properly contained in `O₂`. -/ +scoped infixl:50 " ⋐ " => ProperContainment.ProperlyContained + +variable {K : Type*} [Preorder K] [CausalOrthogonality K] [ProperContainment K] + +/-- Proper containment implies containment (dot-notation form). -/ +theorem ProperlyContained.le {O₁ O₂ : K} (h : O₁ ⋐ O₂) : O₁ ≤ O₂ := + le_of_properlyContained h + +/-- Proper containment survives shrinking the inner region and enlarging the outer one + (dot-notation form). -/ +theorem ProperlyContained.mono {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) (h₃ : O₂ ≤ O₃) : + O₀ ⋐ O₃ := + properlyContained_mono h₀ h h₃ + +/-- The causal collar of a proper containment (dot-notation form). -/ +theorem ProperlyContained.exists_orthogonal {O₁ O₂ : K} (h : O₁ ⋐ O₂) : + ∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ := + exists_orthogonal_of_properlyContained h + +/-- Proper containment of lattice regions from a **thickening operator** (e.g. the + `r`-neighbourhood for a metric or graph structure on the sites): `Λ₁ ⋐ Λ₂` iff the + thickening of `Λ₁` still lies in `Λ₂`. The causal collar is the genuine one, + `Λ₂ \ thicken Λ₁`. -/ +@[reducible] def ofThicken {α : Type*} [DecidableEq α] (thicken : Finset α → Finset α) + (subset_thicken : ∀ Λ, Λ ⊆ thicken Λ) (thicken_mono : Monotone thicken) : + ProperContainment (Finset α) where + ProperlyContained Λ₁ Λ₂ := thicken Λ₁ ⊆ Λ₂ + le_of_properlyContained _ _ h := (subset_thicken _).trans h + properlyContained_mono _ _ _ _ h₀ h h₃ := ((thicken_mono h₀).trans h).trans h₃ + exists_orthogonal_of_properlyContained Λ₁ Λ₂ _ := + ⟨Λ₂ \ thicken Λ₁, Finset.sdiff_subset, + Finset.disjoint_sdiff.mono_left (subset_thicken Λ₁)⟩ + +end ProperContainment + +namespace LocalNet + +open scoped ProperContainment VonNeumannAlgebra + +section LocalAlgebras + +variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] +variable (N : LocalNet K) [N.Faithful] + +/-- The **local von Neumann algebra** `𝓡(O) = π(𝔄(O))″` of a region in a representation of the + quasi-local C⋆-algebra: the von Neumann algebra generated by the image of the local algebra. + The generating set is star-closed (`𝔄(O)` is star-closed, and the embedding and `π` are + `*`-maps), so `VonNeumannAlgebra.generated` — which symmetrizes in general — is literally the + double commutant `π(𝔄(O))″` here. Since `π` is a possibly non-unital `*`-homomorphism, + `𝓡(O)` always contains `1` even when `π(𝔄(O))` does not, matching the `″` convention. -/ +noncomputable def localVonNeumannAlgebra (R : CStarRep N.quasiLocalCStarAlgebra) (O : K) : + VonNeumannAlgebra R.H := + VonNeumannAlgebra.generated (Set.range fun a : N.algebra O => R.π (N.ιLocalCStar O a)) + +/-- Local observables are represented inside the local von Neumann algebra of their region. -/ +lemma π_ιLocalCStar_mem_localVonNeumannAlgebra (R : CStarRep N.quasiLocalCStarAlgebra) (O : K) + (a : N.algebra O) : R.π (N.ιLocalCStar O a) ∈ N.localVonNeumannAlgebra R O := + VonNeumannAlgebra.mem_generated_of_mem ⟨a, rfl⟩ + +/-- **Isotony** of the local von Neumann algebras: `O ≤ O'` gives `𝓡(O) ≤ 𝓡(O')`. -/ +lemma localVonNeumannAlgebra_mono (R : CStarRep N.quasiLocalCStarAlgebra) {O O' : K} + (h : O ≤ O') : N.localVonNeumannAlgebra R O ≤ N.localVonNeumannAlgebra R O' := by + refine VonNeumannAlgebra.generated_mono ?_ + rintro _ ⟨a, rfl⟩ + exact ⟨N.incl h a, by simp⟩ + +/-- **Locality** of the local von Neumann algebras: causally orthogonal regions have commuting + algebras, `𝓡(O₁) ≤ 𝓡(O₂)′`. Einstein causality survives the double commutant. -/ +lemma localVonNeumannAlgebra_le_commutant_of_orthogonal (R : CStarRep N.quasiLocalCStarAlgebra) + {O₁ O₂ : K} (hd : O₁ ⟂ O₂) : + N.localVonNeumannAlgebra R O₁ ≤ (N.localVonNeumannAlgebra R O₂)′ := by + have key : VonNeumannAlgebra.generated + (Set.range fun a : N.algebra O₁ => R.π (N.ιLocalCStar O₁ a)) + ≤ VonNeumannAlgebra.commutantSet + (Set.range fun b : N.algebra O₂ => R.π (N.ιLocalCStar O₂ b)) := by + refine VonNeumannAlgebra.generated_le ?_ + rintro _ ⟨a, rfl⟩ + rw [SetLike.mem_coe, VonNeumannAlgebra.mem_commutantSet_iff] + rintro _ ⟨b, rfl⟩ + refine ⟨(N.ιLocalCStar_commute_of_orthogonal hd.symm b a).map R.π, ?_⟩ + have hb : star (R.π (N.ιLocalCStar O₂ b)) = R.π (N.ιLocalCStar O₂ (star b)) := by + rw [← map_star, N.ιLocalCStar_star] + rw [hb] + exact (N.ιLocalCStar_commute_of_orthogonal hd.symm (star b) a).map R.π + exact key.trans_eq (VonNeumannAlgebra.commutant_generated _).symm + +/-- **The split property** of a local net in a representation `π` of the quasi-local C⋆-algebra + (Buchholz; Doplicher–Longo): for every properly contained pair of regions `O₁ ⋐ O₂`, some + type I factor interpolates between the local von Neumann algebras, + `𝓡(O₁) ≤ M ≤ 𝓡(O₂)`. This is genuinely model-dependent input — it fails for nets without + the requisite phase-space (nuclearity) behaviour — and it is relative to the chosen proper + containment `⋐` (see `ProperContainment`). -/ +def SplitProperty [ProperContainment K] (R : CStarRep N.quasiLocalCStarAlgebra) : Prop := + ∀ ⦃O₁ O₂ : K⦄, O₁ ⋐ O₂ → + VonNeumannAlgebra.IsSplitInclusion + (N.localVonNeumannAlgebra R O₁) (N.localVonNeumannAlgebra R O₂) + +end LocalAlgebras + +section SplitConsequences + +variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] +variable [ProperContainment K] {N : LocalNet K} [N.Faithful] +variable {R : CStarRep N.quasiLocalCStarAlgebra} + +/-- The split property extends to enlarged pairs: if `O₀ ≤ O₁ ⋐ O₂ ≤ O₃` then the inclusion + `𝓡(O₀) ≤ 𝓡(O₃)` is split as well. -/ +lemma SplitProperty.isSplitInclusion_of_le_of_le (hs : N.SplitProperty R) + {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) (h₃ : O₂ ≤ O₃) : + VonNeumannAlgebra.IsSplitInclusion + (N.localVonNeumannAlgebra R O₀) (N.localVonNeumannAlgebra R O₃) := + hs (h.mono h₀ h₃) + +/-- **Buchholz's tensor splitting between properly separated regions**, in split-inclusion form: + under the split property, every properly contained pair `O₁ ⋐ O₂` yields the split inclusion + `𝓡(O₁) ≤ 𝓡(O₂)`, whose full tensor splitting — a unitary `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` carrying + `𝓡(O₁)` into the tensor factor `B(ℓ²(F)) ⊗̄ 1` and the dual algebra `𝓡(O₂)′` into + `1 ⊗̄ B(eH)`, with the interpolating type I factor and its commutant identified exactly — is + obtained by applying `VonNeumannAlgebra.IsSplitInclusion.exists_tensorDecomposition` to the + conclusion. (The instantiated existential is deliberately not restated here: spelling it out + over `R.H` forces the elaborator to unfold the quasi-local algebra inside `R`'s type, while + consuming the general statement through this corollary is cheap.) -/ +theorem SplitProperty.isSplitInclusion (hs : N.SplitProperty R) {O₁ O₂ : K} (h : O₁ ⋐ O₂) : + VonNeumannAlgebra.IsSplitInclusion + (N.localVonNeumannAlgebra R O₁) (N.localVonNeumannAlgebra R O₂) := + hs h + +end SplitConsequences + +end LocalNet diff --git a/QuantumSystem/Analysis/Entropy/MutualInformation.lean b/QuantumSystem/Analysis/Entropy/MutualInformation.lean index d2e765e..9cd6694 100644 --- a/QuantumSystem/Analysis/Entropy/MutualInformation.lean +++ b/QuantumSystem/Analysis/Entropy/MutualInformation.lean @@ -12,9 +12,10 @@ product index type `n × m`: `D(ρ_AB ‖ ρ_A ⊗ ρ_B) = -S(ρ_AB) + S(ρ_A) + S(ρ_B)`. -It is representation-free; the analytic core reused both by the direct proof -(`Analysis/Entropy/StrongSubadditivity.lean`) and, via transport, by the abstract split-net -proof (`Analysis/Entropy/SplitSSA.lean`). +It is representation-free; the analytic core reused by the direct proof +(`Analysis/Entropy/StrongSubadditivity.lean`) and, via transport, by the planned split-net proof +(`Analysis/Entropy/SplitSSA.lean`, not yet formalised — the split property it rests on is +`LocalNet.SplitProperty`). -/ @[expose] public section diff --git a/QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean b/QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean index 4c0a9b4..4e3358b 100644 --- a/QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean +++ b/QuantumSystem/Analysis/Entropy/StrongSubadditivity.lean @@ -16,9 +16,10 @@ finite-dimensional quantum-information argument 2. the data-processing inequality `Matrix.relativeEntropy_channel_le` for the trace-out-`C` channel `Matrix.QuantumChannel.traceOutC`. -The AQFT companion — the same inequality stated representation-free over an abstract operator- -algebraic split net with nested regions — is `LocalNet.Split.vonNeumannEntropy_SSA` -(`SplitSSA.lean`), which transports this result to the net. +The AQFT companion — the same inequality stated over a local net with nested regions, using the +split property `LocalNet.SplitProperty` (`Algebra/LocalNet/SplitProperty.lean`) — is the planned +`LocalNet.SplitProperty.vonNeumannEntropy_SSA` (`Analysis/Entropy/SplitSSA.lean`, not yet +formalised), which will transport this result to the net. ## Main results From d9ab94ff515823b0a384c61336b0c03ddb1e5c22 Mon Sep 17 00:00:00 2001 From: suzuki Date: Thu, 13 Aug 2026 14:58:23 +0000 Subject: [PATCH 072/113] chore: npm audit fix --- package-lock.json | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca1d422..5cf6a33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -600,9 +600,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "dev": true, "funding": [ { @@ -784,10 +784,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" From 7ea5d7570810f0de3e30689b5bde7b3aac1e0069 Mon Sep 17 00:00:00 2001 From: suzuki Date: Fri, 14 Aug 2026 13:14:39 +0000 Subject: [PATCH 073/113] chore: remove unriped skills --- .claude/skills/grill-formalization/SKILL.md | 79 ---- .claude/skills/ingest-paper/SKILL.md | 75 ---- .../ingest-paper/references/conversion.md | 74 --- .../skills/ingest-paper/scripts/convert.py | 420 ------------------ 4 files changed, 648 deletions(-) delete mode 100644 .claude/skills/grill-formalization/SKILL.md delete mode 100644 .claude/skills/ingest-paper/SKILL.md delete mode 100644 .claude/skills/ingest-paper/references/conversion.md delete mode 100644 .claude/skills/ingest-paper/scripts/convert.py diff --git a/.claude/skills/grill-formalization/SKILL.md b/.claude/skills/grill-formalization/SKILL.md deleted file mode 100644 index 1f47f20..0000000 --- a/.claude/skills/grill-formalization/SKILL.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -name: grill-formalization -description: Grill a formalization plan against the paper and AGENTS.md before any Lean is written — statement fidelity, abstraction level, deferred hypotheses, Mathlib reuse, proof order. -disable-model-invocation: true ---- - -# grill-formalization - -Interview the user relentlessly about a formalization plan until every decision -that would become permanent sediment in the Lean development is settled — -*before* any tactic is typed. This is a relentless interview aimed at one target: -the plan to formalize an ingested paper. - -Run this after `ingest-paper` has left a navigable `references//INDEX.md`. -Read that substrate and `AGENTS.md` first; every recommendation you make is -grounded in the paper's actual content and the project's working principles, not -in what Mathlib happens to make easy. - -## Survey first - -Before any question, map the ground you will plan on — a phase that only -understands the architecture, never decides. Read the Lean sources the plan will -touch and write down the existing **structures, typeclasses, and interfaces** -already in play: what each provides, what it assumes, how a new development must -fit them. The grill runs against this written map. - -Ground every line in the **Lean source and mathematical fact** — never in -comments, docstrings, or `.md` notes, which drift. Label each as **fact** (read -off the code, or a proven/standard result) or **inference** (suspected, not yet -verified), and keep the two visibly apart. This discipline holds for the whole -skill. - -*Done when:* the architecture map is written and every line is tagged fact or -inference. - -## The grill loop - -Walk down the design tree below, one axis at a time, resolving dependencies in -order. For each question: - -- Ask **one** question and wait for the answer — multiple at once is bewildering. -- Provide your **recommended** answer, grounded and labelled per *Survey first*. -- If the codebase or the paper answers it, **explore instead of asking** — read - `references//`, grep the Lean sources, and use lean-lsp search - (`lean_leansearch`, `lean_loogle`, `lean_local_search`) to check whether an API - already exists. Never invent a plausible-looking lemma name; search, then - report what you found. - -## The design tree - -Grill these decisions in order — later axes depend on earlier ones. Each rule -lives in `AGENTS.md`; read it there, never restate it here. - -1. **Statement fidelity** → *Abstraction first* -2. **Abstraction first** → *Abstraction first* -3. **Deferred hypotheses** → *Prove what is provable; do not defer it* -4. **Mathlib reuse vs. build** → *Project Layout* -5. **Proof skeleton & dependency order** → *Think before coding* -6. **Definition of done** → *Goal-driven verification*, *Prohibited Tokens* - -## Output - -When every axis is settled, write the plan in this format: - -- **Mathematical statement** — the result to formalize, stated in mathematics. -- **Lean statement** — the `theorem` planned for it: the abstract interface, then - its concrete instantiation. -- **Data structures** — the structures / typeclasses the statement and proof need. -- **Hypotheses** — each hypothesis required, justified as model-dependent vs - proven-in-plan (axis 3). -- **Equivalence check** — the points to confirm the Lean statement says *exactly* - the mathematical one. Name where the two could silently diverge — implicit - coercions, hidden finiteness / nonemptiness, quantifier order, hypotheses - weakened to fit Mathlib — and how each is settled, separating what is verified - from what is still inference. - -*Done when:* the plan follows the format above, the Lean statement is argued -equivalent to the mathematical one, and no hypothesis survives axis 3 without -being either proven-in-plan or justified as a model-dependent input. diff --git a/.claude/skills/ingest-paper/SKILL.md b/.claude/skills/ingest-paper/SKILL.md deleted file mode 100644 index d90321e..0000000 --- a/.claude/skills/ingest-paper/SKILL.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -name: ingest-paper -description: Convert a paper or lecture-note PDF into agent-navigable Markdown under references//, as the groundwork for interrogating its formalization plan. -disable-model-invocation: true ---- - -# ingest-paper - -Turn a PDF (paper, lecture notes) into Markdown + extracted images + a filled -`INDEX.md` that an agent can navigate across sessions — the durable substrate a -formalization plan gets grilled against afterwards. - -This skill stops at a navigable document. It does **not** plan or formalize; the -last step hands off to `/grill-formalization`. The structured sections it fills -(Main results, Load-bearing assumptions) **record** what the paper states — they -never judge formalizability or classify hypotheses; that judgement belongs to -`/grill-formalization`. - -## Steps - -1. **Resolve the source.** Pull the PDF URL or local path from the request. If - several are present, process the one the user names; ask only when ambiguous. - *Done when:* you hold exactly one URL or existing local `.pdf` path. - -2. **Run the converter.** From the project root: - - ```bash - uv run .claude/skills/ingest-paper/scripts/convert.py "" - ``` - - Add a flag only when the default fails: `--ocr` (scanned PDF, output came out - nearly empty), `--slug ` (override the derived slug), `--output-dir - ` (override the `references/` root). Other flags and runtime - prerequisites live in `references/conversion.md` — read it only if the - command errors or the layout needs tweaking. - *Done when:* the script prints its JSON summary (`slug`, `output_dir`, - `index_path`, `page_count`, `image_count`, `sectioned`) and exits 0. - -3. **Fill the INDEX.md scaffold.** The script leaves four `` blocks. - Read `content.md` (or the `sections/*.md` files) and replace **all four**: - - **Summary** — 3–5 sentences: what this document is and why a formalization - agent would consult it. From the actual content, not the title. - - **Key concepts** — bullet list an agent would grep for. **Every bullet - starts with a `` `backtick-identifier` ``** naming the concept, then a short - gloss. Omit the section only for pure-prose documents with no greppable - terminology. - - **Main results** — the results this document targets for formalization, - recorded as a **dependency DAG** so the proof skeleton survives. List the - headline theorems **and** the intermediate lemmas/propositions they rest on, - so every edge resolves. **Every bullet starts with a - `` `backtick-identifier` ``** (the candidate Lean name), then a one-line - *mathematical* statement and a pointer to where it lives (`sections/NN-*.md` - or `content.md#anchor`), followed by a `depends on:` line referencing other - nodes, `` `assumption-id` ``s, and external results as `[cited: ...]` (Mathlib - reuse candidates). Drop the `depends on:` line for a leaf with no stated - dependencies. Record what the paper states; do **not** judge formalizability - or proof order. - - **Load-bearing assumptions** — the hypotheses the Main results depend on, - recorded **neutrally** from the paper. **Every bullet starts with a - `` `backtick-identifier` ``** (referenced from the Main-results `depends on:` - lines), then the assumption and which result(s) rely on it. Do **not** - classify model-dependent vs provable — that is `/grill-formalization`'s call. - Omit only if the document states no explicit hypotheses. - *Done when:* no `` marker remains anywhere in `INDEX.md`, every - Key-concepts, Main-results, and Load-bearing-assumptions bullet (in the - sections that are present) begins with a backtick identifier, and every - Main-results `depends on:` reference resolves to a node/assumption id in the - document or a `[cited: ...]` external result. - -4. **Hand off to planning.** Report the `INDEX.md` path and any caveats (OCR - skipped, document split into `sections/`, no images found) — do not paste the - summary into chat. Then tell the user the substrate is ready and the next move - is `/grill-formalization`, which reads Main results and Load-bearing - assumptions to stress-test the formalization plan against the paper. - *Done when:* the user has the INDEX path and the `/grill-formalization` pointer. diff --git a/.claude/skills/ingest-paper/references/conversion.md b/.claude/skills/ingest-paper/references/conversion.md deleted file mode 100644 index c10e247..0000000 --- a/.claude/skills/ingest-paper/references/conversion.md +++ /dev/null @@ -1,74 +0,0 @@ -# Conversion reference - -Read this only when the `convert.py` command errors, the output layout needs -tweaking, or you are debugging a bad conversion. The happy path needs nothing -here. - -## Output contract - -Everything lands under `//` (default `references//`, -which this project keeps in `.gitignore`): - -``` -references// -├── INDEX.md # metadata frontmatter + Summary + Key concepts + Contents (you fill 2 sections) -├── content.md # present when page count <= max-pages-per-section (default 20) -├── sections/ # present instead of content.md when pages > threshold AND the PDF has top-level headings -│ ├── 01-.md -│ └── ... -├── assets/ # only images actually referenced from the Markdown, rewritten as assets/... -│ └── image_*.jpg -└── mineru-raw/ # only when --keep-raw is passed; debugging artefacts, not for agents -``` - -`INDEX.md` frontmatter carries `title`, `source`, `pages`, `slug`, `assets`. -`content.md`/`sections/` and `assets/` are read directly by any later agent -without re-running the conversion. - -## All flags - -- `--output-dir <dir>` — parent of `<slug>/`. Default `references/`. -- `--slug <name>` — override the derived slug. arXiv IDs are auto-preserved - (`arxiv-2202.03357`); other sources slugify the filename. -- `--max-pages-per-section N` — split threshold (default 20). Leave alone unless - asked. -- `--ocr` — MinerU OCR mode for scanned PDFs. Default `auto` picks text - extraction when a text layer exists. OCR adds minutes — confirm before using. -- `--keep-raw` — keep MinerU's auxiliary outputs (middle.json, layout.pdf, etc.) - under `mineru-raw/`. Several MB; off by default. - -## Runtime prerequisites - -- **`uv`** on `PATH`. The script is stdlib-only but runs under `uv run` for - invocation hygiene. -- **`mineru` CLI** on `PATH`. One-off install: `uv tool install "mineru[all]"` - (~4 GB of packages + model weights on first run; cached afterwards). -- **Disk + memory.** Budget ~4 GB for the tool environment; per-paper runtime - memory peaks at 3–4 GB. -- **GPU (optional).** When `nvidia-smi` reports a working GPU the script switches - MinerU to its `hybrid-auto-engine` backend (much faster on formula - recognition). Otherwise it silently uses CPU `pipeline`. No flag needed. - -## Failure modes - -- **Download error** — script exits non-zero; ask the user for a local path. -- **Scanned PDF (no text layer)** — output Markdown is nearly empty; re-run with - `--ocr` after confirming with the user. -- **>20 pages but no top-level headings** — falls back to a single `content.md`. - Intentional; do not hand-split. -- **Very large docs (>100 pages)** — first-run CPU conversion takes several - minutes; warn the user so they do not cancel. -- **Parallel runs on CPU** — MinerU's per-task timeout makes concurrent - conversions fail. Convert one PDF at a time; a single paper runs ~30–40 min on - CPU. - -## Why MinerU - -MinerU's `pipeline` backend decodes every formula (display and inline) to LaTeX -on CPU in minutes and preserves equation numbers via `\tag{...}`. Docling was -dropped earlier: its formula VLM emitted `<!-- formula-not-decoded -->` by -default and the opt-in path was GPU-bound and unusable on CPU. The script shells -out to the `mineru` CLI rather than importing its Python API (more stable, lighter -dependency graph). The agent — not the script — writes Summary and Key concepts, -because summarization and identifier extraction are judgement calls a heuristic -would get wrong often enough to harm. diff --git a/.claude/skills/ingest-paper/scripts/convert.py b/.claude/skills/ingest-paper/scripts/convert.py deleted file mode 100644 index ff32080..0000000 --- a/.claude/skills/ingest-paper/scripts/convert.py +++ /dev/null @@ -1,420 +0,0 @@ -#!/usr/bin/env python3 -# /// script -# requires-python = ">=3.10" -# dependencies = [] -# /// -"""Convert a PDF into agent-friendly Markdown + image assets using MinerU. - -Produces under ``<output-dir>/<slug>/``: - -- ``INDEX.md`` Metadata, ToC, and scaffolded Summary / Key concepts / - Main results / Load-bearing assumptions sections that the caller - (Claude) fills in after reading the content. -- ``content.md`` Full Markdown (if total pages <= max-pages-per-section). -- ``sections/`` Split Markdown files (if total pages exceed the threshold and - the document has top-level ``#`` / ``## `` headings to split on). -- ``assets/`` Images referenced from the Markdown. - -This script is a thin post-processor around the MinerU CLI. MinerU's -``pipeline`` backend runs entirely on CPU and, unlike Docling's formula VLM, -decodes mathematical formulas into LaTeX in a few minutes per paper. We gave -up on Docling in iteration-6 after its formula VLM crawled on CPU. - -Usage: - uv run convert.py <pdf-url-or-path> [--output-dir DIR] [--slug SLUG] - [--max-pages-per-section N] [--ocr] - [--keep-raw] - -Prerequisite: - ``mineru`` must be on PATH. One-off install: - uv tool install "mineru[all]" -""" - -from __future__ import annotations - -import argparse -import json -import re -import shutil -import subprocess -import sys -import tempfile -import urllib.parse -import urllib.request -from pathlib import Path - - -def slugify(text: str) -> str: - """Lowercase, ASCII-friendly filesystem slug, capped at 60 chars.""" - text = text.lower().strip() - text = re.sub(r"[^\w\s-]", "", text, flags=re.UNICODE) - text = re.sub(r"[\s_-]+", "-", text) - return text[:60].strip("-") or "document" - - -def derive_slug(source: str) -> str: - """Pick a readable slug from a URL or local path.""" - m = re.search(r"arxiv\.org/(?:pdf|abs)/([\w.-]+?)(?:v\d+)?(?:\.pdf)?(?:[?#]|$)", source) - if m: - return f"arxiv-{m.group(1)}" - if source.startswith(("http://", "https://")): - parsed = urllib.parse.urlparse(source) - basename = Path(parsed.path).stem or parsed.netloc - return slugify(basename) - return slugify(Path(source).stem) - - -def normalise_pdf_url(url: str) -> str: - """Rewrite arxiv ``abs/`` URLs to their ``pdf/`` counterparts.""" - m = re.match(r"^(https?://arxiv\.org)/abs/([\w.-]+?)(?:v\d+)?/?$", url) - if m: - return f"{m.group(1)}/pdf/{m.group(2)}" - return url - - -def download_pdf(url: str, dest: Path) -> None: - req = urllib.request.Request(url, headers={"User-Agent": "pdf-to-knowledge/1.0"}) - with urllib.request.urlopen(req, timeout=120) as response, dest.open("wb") as out: - while chunk := response.read(65536): - out.write(chunk) - - -def _heading_level(line: str) -> int: - """Return the Markdown heading level (1..6) of ``line``, or 0 if not a heading.""" - m = re.match(r"^(#{1,6}) \S", line) - return len(m.group(1)) if m else 0 - - -def split_markdown_by_top_headings(md: str) -> list[tuple[str, str]]: - """Split Markdown at its top-most heading level. Returns ``[(title, body), ...]``.""" - has_h1 = any(_heading_level(line) == 1 for line in md.splitlines()) - split_level = 1 if has_h1 else 2 - - sections: list[tuple[str, str]] = [] - current_title: str | None = None - current_body: list[str] = [] - for line in md.splitlines(keepends=True): - if _heading_level(line.rstrip("\n")) == split_level: - if current_title is not None: - sections.append((current_title, "".join(current_body))) - current_title = line.lstrip("#").strip() - current_body = [line] - else: - if current_title is None: - current_title = "front-matter" - current_body = [] - current_body.append(line) - if current_title is not None: - sections.append((current_title, "".join(current_body))) - return sections - - -def extract_document_title(md: str, fallback: str) -> str: - """Return the first heading (any level) in ``md``, or ``fallback``.""" - for line in md.splitlines(): - m = re.match(r"^#{1,6} (.+)", line) - if m: - return m.group(1).strip() - return fallback - - -def _github_anchor(heading: str) -> str: - """Compute a GitHub-style Markdown anchor for a heading.""" - slug = heading.strip().lower() - slug = re.sub(r"[^\w\s-]", "", slug, flags=re.UNICODE) - slug = re.sub(r"\s+", "-", slug) - return slug.strip("-") - - -def extract_toc_headings(md: str, max_entries: int = 20) -> list[tuple[int, str]]: - """Extract H2/H3 headings from ``md`` for navigation.""" - entries: list[tuple[int, str]] = [] - for line in md.splitlines(): - m = re.match(r"^(##{1,2}) (.+)", line) - if m: - level = len(m.group(1)) - title = m.group(2).strip() - entries.append((level, title)) - if len(entries) >= max_entries: - break - return entries - - -def _flat_toc_for_content(md: str) -> list[str]: - """Build ToC Markdown lines for the single-file ``content.md`` case.""" - lines = ["- [Full content](content.md)"] - for level, title in extract_toc_headings(md): - indent = " " if level == 2 else " " - anchor = _github_anchor(title) - lines.append(f"{indent}- [{title}](content.md#{anchor})") - return lines - - -def _has_gpu() -> bool: - """Detect an NVIDIA GPU via ``nvidia-smi``. Returns False on any error. - - MinerU's `hybrid-auto-engine` backend uses GPU when available and is - dramatically faster than `pipeline` for the formula-recognition stage. - Falls back to CPU `pipeline` cleanly when `nvidia-smi` is absent. - """ - if shutil.which("nvidia-smi") is None: - return False - try: - result = subprocess.run( - ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], - capture_output=True, - text=True, - timeout=5, - ) - except (subprocess.TimeoutExpired, OSError): - return False - return result.returncode == 0 and bool(result.stdout.strip()) - - -def run_mineru(pdf_path: Path, output_base: Path, ocr: bool) -> tuple[Path, Path, Path]: - """Invoke the MinerU CLI. Returns (md_path, images_dir, content_list_json).""" - if shutil.which("mineru") is None: - print( - "[error] 'mineru' not found on PATH. Install with: " - "uv tool install \"mineru[all]\"", - file=sys.stderr, - ) - sys.exit(3) - - method = "ocr" if ocr else "auto" - # Auto-select backend: hybrid-auto-engine uses GPU when available and - # can be >5x faster for formula-heavy papers; pipeline is CPU-only. - backend = "hybrid-auto-engine" if _has_gpu() else "pipeline" - print(f"[info] MinerU backend: {backend}", file=sys.stderr) - cmd = [ - "mineru", - "-p", str(pdf_path), - "-o", str(output_base), - "-b", backend, - "-l", "en", - "-m", method, - ] - print(f"[info] Running: {' '.join(cmd)}", file=sys.stderr) - subprocess.run(cmd, check=True) - - name = pdf_path.stem - auto_dir = output_base / name / "auto" - md_path = auto_dir / f"{name}.md" - images_dir = auto_dir / "images" - content_list_json = auto_dir / f"{name}_content_list.json" - if not md_path.is_file(): - print(f"[error] MinerU did not produce {md_path}", file=sys.stderr) - sys.exit(4) - return md_path, images_dir, content_list_json - - -def page_count_from_content_list(content_list_json: Path) -> int: - """Read max ``page_idx`` from MinerU's content_list.json and return page count.""" - try: - data = json.loads(content_list_json.read_text(encoding="utf-8")) - except Exception: - return 0 - max_idx = 0 - for item in data: - idx = item.get("page_idx") - if isinstance(idx, int): - max_idx = max(max_idx, idx) - return max_idx + 1 if data else 0 - - -_IMAGE_REF = re.compile(r"!\[[^\]]*\]\(images/([^)]+)\)") - - -def rewrite_and_collect_image_refs(md: str) -> tuple[str, set[str]]: - """Rewrite ``images/...`` references to ``assets/...`` and return referenced names.""" - referenced: set[str] = set() - - def _sub(match: re.Match) -> str: - name = match.group(1) - referenced.add(name) - return match.group(0).replace("images/", "assets/", 1) - - return _IMAGE_REF.sub(_sub, md), referenced - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("source", help="PDF URL or local path") - parser.add_argument( - "--output-dir", - default="references", - help="Parent directory; output is placed under <output-dir>/<slug>/", - ) - parser.add_argument("--slug", default=None, help="Override the auto-derived slug") - parser.add_argument( - "--max-pages-per-section", - type=int, - default=20, - help="Split into sections/ if the document exceeds this many pages (default: 20)", - ) - parser.add_argument( - "--ocr", - action="store_true", - help="Use MinerU's OCR method (for scanned PDFs). Default is 'auto'.", - ) - parser.add_argument( - "--keep-raw", - action="store_true", - help=( - "Keep MinerU's raw auxiliary outputs (middle.json, layout.pdf, span.pdf, " - "model.json, content_list_v2.json) under <output-dir>/<slug>/mineru-raw/. " - "Off by default — they are debugging artefacts unsuitable for agents." - ), - ) - args = parser.parse_args() - - source: str = args.source - slug = args.slug or derive_slug(source) - output_root = Path(args.output_dir).expanduser().resolve() - output_dir = output_root / slug - output_dir.mkdir(parents=True, exist_ok=True) - assets_dir = output_dir / "assets" - - # Resolve input to a local path. - if source.startswith(("http://", "https://")): - fetch_url = normalise_pdf_url(source) - tmpdir = Path(tempfile.mkdtemp(prefix="pdf-to-knowledge-")) - pdf_path = tmpdir / f"{slug}.pdf" - print(f"[info] Downloading {fetch_url}", file=sys.stderr) - download_pdf(fetch_url, pdf_path) - else: - pdf_path = Path(source).expanduser().resolve() - if not pdf_path.exists(): - print(f"[error] Not found: {pdf_path}", file=sys.stderr) - return 2 - - # Run MinerU into a fresh scratch directory so we fully own the layout. - mineru_scratch = Path(tempfile.mkdtemp(prefix="mineru-")) - md_path, images_src, content_list_json = run_mineru( - pdf_path, mineru_scratch, ocr=args.ocr - ) - - page_count = page_count_from_content_list(content_list_json) - print(f"[info] Pages: {page_count}", file=sys.stderr) - - md_text = md_path.read_text(encoding="utf-8") - md_text, referenced_images = rewrite_and_collect_image_refs(md_text) - - # Copy referenced images only — MinerU occasionally extracts formula clips - # that are not referenced from the Markdown; keeping them clutters agents. - image_count = 0 - if referenced_images and images_src.is_dir(): - assets_dir.mkdir(exist_ok=True) - for name in referenced_images: - src = images_src / name - if src.is_file(): - shutil.copy(src, assets_dir / name) - image_count += 1 - - # Optionally keep MinerU's raw auxiliary outputs for debugging. - if args.keep_raw: - raw_dir = output_dir / "mineru-raw" - raw_dir.mkdir(exist_ok=True) - for aux in md_path.parent.iterdir(): - if aux.name == md_path.name or aux == images_src: - continue - if aux.is_file(): - shutil.copy(aux, raw_dir / aux.name) - - # Clean up the scratch tree now that we have what we need. - shutil.rmtree(mineru_scratch, ignore_errors=True) - - # Write content.md / sections/ based on page count. - content_md = output_dir / "content.md" - title = extract_document_title(md_text, slug.replace("-", " ").title()) - - sectioned = False - toc_lines: list[str] = [] - if page_count > args.max_pages_per_section: - parts = split_markdown_by_top_headings(md_text) - real_parts = [(t, b) for t, b in parts if t != "front-matter" or b.strip()] - if len(real_parts) > 1: - sections_dir = output_dir / "sections" - sections_dir.mkdir(exist_ok=True) - for i, (section_title, body) in enumerate(real_parts, start=1): - sec_slug = slugify(section_title) - sec_file = sections_dir / f"{i:02d}-{sec_slug}.md" - sec_file.write_text(body, encoding="utf-8") - toc_lines.append(f"- [{section_title}](sections/{sec_file.name})") - sectioned = True - else: - content_md.write_text(md_text, encoding="utf-8") - toc_lines.extend(_flat_toc_for_content(md_text)) - else: - content_md.write_text(md_text, encoding="utf-8") - toc_lines.extend(_flat_toc_for_content(md_text)) - - # Scaffold INDEX.md (Claude fills Summary / Key concepts / Main results / - # Load-bearing assumptions per SKILL.md step 3). - index = [ - "---", - f"title: {json.dumps(title, ensure_ascii=False)}", - f"source: {json.dumps(source, ensure_ascii=False)}", - f"pages: {page_count}", - f"slug: {slug}", - f"assets: {image_count}", - "---", - "", - f"# {title}", - "", - "## Summary", - "", - "<!-- TODO: 3-5 sentence summary of what this document covers and why a", - " coding agent would consult it. Fill in after reading the content. -->", - "", - "## Key concepts", - "", - "<!-- TODO: Bullet list of identifiers an agent would grep for. Each bullet", - " MUST start with a `backtick-quoted` identifier — this drives the", - " cross-document concept index. Omit the section if no greppable", - " terminology exists (e.g. pure prose papers). -->", - "", - "## Main results", - "", - "<!-- TODO: The results this document targets for formalization, recorded as a", - " dependency DAG so the proof skeleton survives. Include the headline", - " theorems AND the intermediate lemmas/propositions they rest on, so every", - " edge resolves. Each bullet:", - " - `result-id` — one-line MATHEMATICAL statement (sections/NN-*.md#anchor)", - " depends on: `other-result-id`, `assumption-id`, [cited: Author Year, Thm N]", - " `assumption-id` points at a Load-bearing-assumptions bullet; [cited: ...]", - " names an external result (a Mathlib-reuse candidate). Drop the `depends on:`", - " line for a leaf with no stated dependencies. Record what the paper states;", - " do not judge formalizability or proof order — that is grill-formalization's", - " job. -->", - "", - "## Load-bearing assumptions", - "", - "<!-- TODO: The hypotheses the Main results depend on, recorded NEUTRALLY from", - " the paper. Each bullet starts with a `backtick-identifier` (referenced from", - " the Main-results `depends on:` lines), then the assumption and which", - " result(s) rely on it. Do NOT classify model-dependent vs provable —", - " grill-formalization decides that (AGENTS.md: \"Prove what is provable\").", - " Omit only if the document states no explicit hypotheses. -->", - "", - "## Contents", - "", - *toc_lines, - "", - ] - (output_dir / "INDEX.md").write_text("\n".join(index), encoding="utf-8") - - summary = { - "slug": slug, - "output_dir": str(output_dir), - "index_path": str(output_dir / "INDEX.md"), - "page_count": page_count, - "image_count": image_count, - "sectioned": sectioned, - } - print(json.dumps(summary, indent=2, ensure_ascii=False)) - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) From f7669f9771c41e93fa96aafea345bf3cc34854e3 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 13:16:48 +0000 Subject: [PATCH 074/113] chore: remove package.json --- .npmrc | 1 - package-lock.json | 1420 --------------------------------------------- package.json | 13 - 3 files changed, 1434 deletions(-) delete mode 100644 .npmrc delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/.npmrc b/.npmrc deleted file mode 100644 index cffe8cd..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -save-exact=true diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 5cf6a33..0000000 --- a/package-lock.json +++ /dev/null @@ -1,1420 +0,0 @@ -{ - "name": "quantum-system", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "quantum-system", - "devDependencies": { - "@commitlint/cli": "20.2.0", - "@commitlint/config-conventional": "20.2.0", - "lefthook": "2.0.11" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@commitlint/cli": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.2.0.tgz", - "integrity": "sha512-l37HkrPZ2DZy26rKiTUvdq/LZtlMcxz+PeLv9dzK9NzoFGuJdOQyYU7IEkEQj0pO++uYue89wzOpZ0hcTtoqUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/format": "^20.2.0", - "@commitlint/lint": "^20.2.0", - "@commitlint/load": "^20.2.0", - "@commitlint/read": "^20.2.0", - "@commitlint/types": "^20.2.0", - "tinyexec": "^1.0.0", - "yargs": "^17.0.0" - }, - "bin": { - "commitlint": "cli.js" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/config-conventional": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.2.0.tgz", - "integrity": "sha512-MsRac+yNIbTB4Q/psstKK4/ciVzACHicSwz+04Sxve+4DW+PiJeTjU0JnS4m/oOnulrXYN+yBPlKaBSGemRfgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.2.0", - "conventional-changelog-conventionalcommits": "^7.0.2" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/config-validator": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.2.0.tgz", - "integrity": "sha512-SQCBGsL9MFk8utWNSthdxd9iOD1pIVZSHxGBwYIGfd67RTjxqzFOSAYeQVXOu3IxRC3YrTOH37ThnTLjUlyF2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.2.0", - "ajv": "^8.11.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/ensure": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.2.0.tgz", - "integrity": "sha512-+8TgIGv89rOWyt3eC6lcR1H7hqChAKkpawytlq9P1i/HYugFRVqgoKJ8dhd89fMnlrQTLjA5E97/4sF09QwdoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.2.0", - "lodash.camelcase": "^4.3.0", - "lodash.kebabcase": "^4.1.1", - "lodash.snakecase": "^4.1.1", - "lodash.startcase": "^4.4.0", - "lodash.upperfirst": "^4.3.1" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/execute-rule": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", - "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/format": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.2.0.tgz", - "integrity": "sha512-PhNoLNhxpfIBlW/i90uZ3yG3hwSSYx7n4d9Yc+2FAorAHS0D9btYRK4ZZXX+Gm3W5tDtu911ow/eWRfcRVgNWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.2.0", - "chalk": "^5.3.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/is-ignored": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.2.0.tgz", - "integrity": "sha512-Lz0OGeZCo/QHUDLx5LmZc0EocwanneYJUM8z0bfWexArk62HKMLfLIodwXuKTO5y0s6ddXaTexrYHs7v96EOmw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.2.0", - "semver": "^7.6.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/lint": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.2.0.tgz", - "integrity": "sha512-cQEEB+jlmyQbyiji/kmh8pUJSDeUmPiWq23kFV0EtW3eM+uAaMLMuoTMajbrtWYWQpPzOMDjYltQ8jxHeHgITg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/is-ignored": "^20.2.0", - "@commitlint/parse": "^20.2.0", - "@commitlint/rules": "^20.2.0", - "@commitlint/types": "^20.2.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/load": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.2.0.tgz", - "integrity": "sha512-iAK2GaBM8sPFTSwtagI67HrLKHIUxQc2BgpgNc/UMNme6LfmtHpIxQoN1TbP+X1iz58jq32HL1GbrFTCzcMi6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/config-validator": "^20.2.0", - "@commitlint/execute-rule": "^20.0.0", - "@commitlint/resolve-extends": "^20.2.0", - "@commitlint/types": "^20.2.0", - "chalk": "^5.3.0", - "cosmiconfig": "^9.0.0", - "cosmiconfig-typescript-loader": "^6.1.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "lodash.uniq": "^4.5.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/message": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.0.0.tgz", - "integrity": "sha512-gLX4YmKnZqSwkmSB9OckQUrI5VyXEYiv3J5JKZRxIp8jOQsWjZgHSG/OgEfMQBK9ibdclEdAyIPYggwXoFGXjQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/parse": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.2.0.tgz", - "integrity": "sha512-LXStagGU1ivh07X7sM+hnEr4BvzFYn1iBJ6DRg2QsIN8lBfSzyvkUcVCDwok9Ia4PWiEgei5HQjju6xfJ1YaSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.2.0", - "conventional-changelog-angular": "^7.0.0", - "conventional-commits-parser": "^5.0.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/read": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.2.0.tgz", - "integrity": "sha512-+SjF9mxm5JCbe+8grOpXCXMMRzAnE0WWijhhtasdrpJoAFJYd5UgRTj/oCq5W3HJTwbvTOsijEJ0SUGImECD7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/top-level": "^20.0.0", - "@commitlint/types": "^20.2.0", - "git-raw-commits": "^4.0.0", - "minimist": "^1.2.8", - "tinyexec": "^1.0.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/resolve-extends": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.2.0.tgz", - "integrity": "sha512-KVoLDi9BEuqeq+G0wRABn4azLRiCC22/YHR2aCquwx6bzCHAIN8hMt3Nuf1VFxq/c8ai6s8qBxE8+ZD4HeFTlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/config-validator": "^20.2.0", - "@commitlint/types": "^20.2.0", - "global-directory": "^4.0.1", - "import-meta-resolve": "^4.0.0", - "lodash.mergewith": "^4.6.2", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/rules": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.2.0.tgz", - "integrity": "sha512-27rHGpeAjnYl/A+qUUiYDa7Yn1WIjof/dFJjYW4gA1Ug+LUGa1P0AexzGZ5NBxTbAlmDgaxSZkLLxtLVqtg8PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/ensure": "^20.2.0", - "@commitlint/message": "^20.0.0", - "@commitlint/to-lines": "^20.0.0", - "@commitlint/types": "^20.2.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/to-lines": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-20.0.0.tgz", - "integrity": "sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/top-level": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.0.0.tgz", - "integrity": "sha512-drXaPSP2EcopukrUXvUXmsQMu3Ey/FuJDc/5oiW4heoCfoE5BdLQyuc7veGeE3aoQaTVqZnh4D5WTWe2vefYKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^7.0.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@commitlint/types": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.2.0.tgz", - "integrity": "sha512-KTy0OqRDLR5y/zZMnizyx09z/rPlPC/zKhYgH8o/q6PuAjoQAKlRfY4zzv0M64yybQ//6//4H1n14pxaLZfUnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/conventional-commits-parser": "^5.0.0", - "chalk": "^5.3.0" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@types/conventional-commits-parser": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.2.tgz", - "integrity": "sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", - "dev": true, - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", - "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", - "dev": true, - "license": "ISC", - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/conventional-commits-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-text-path": "^2.0.0", - "JSONStream": "^1.3.5", - "meow": "^12.0.1", - "split2": "^4.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.mjs" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cosmiconfig-typescript-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", - "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "jiti": "^2.6.1" - }, - "engines": { - "node": ">=v18" - }, - "peerDependencies": { - "@types/node": "*", - "cosmiconfig": ">=9", - "typescript": ">=5" - } - }, - "node_modules/dargs": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", - "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/find-up": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", - "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^7.2.0", - "path-exists": "^5.0.0", - "unicorn-magic": "^0.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/git-raw-commits": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", - "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dargs": "^8.0.0", - "meow": "^12.0.1", - "split2": "^4.0.0" - }, - "bin": { - "git-raw-commits": "cli.mjs" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/global-directory": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", - "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "4.1.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "text-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "license": "MIT" - }, - "node_modules/JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "dependencies": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - }, - "bin": { - "JSONStream": "bin.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/lefthook": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook/-/lefthook-2.0.11.tgz", - "integrity": "sha512-/91k4dt9MRNkzeSr1iMjNi/z8dNuh+XvNfXrWA6PV+M1ZxiNY6uN6bGnr13n+j7N89f4h7YWBhCqhzhK33M5cA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "lefthook": "bin/index.js" - }, - "optionalDependencies": { - "lefthook-darwin-arm64": "2.0.11", - "lefthook-darwin-x64": "2.0.11", - "lefthook-freebsd-arm64": "2.0.11", - "lefthook-freebsd-x64": "2.0.11", - "lefthook-linux-arm64": "2.0.11", - "lefthook-linux-x64": "2.0.11", - "lefthook-openbsd-arm64": "2.0.11", - "lefthook-openbsd-x64": "2.0.11", - "lefthook-windows-arm64": "2.0.11", - "lefthook-windows-x64": "2.0.11" - } - }, - "node_modules/lefthook-darwin-arm64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-darwin-arm64/-/lefthook-darwin-arm64-2.0.11.tgz", - "integrity": "sha512-RfpdcJJQXstdgDiIBDRffncayKiXx+0LyMUCunIxDEO2JMXPpYK2hIdpUU0rkitzptAADchG7u1OXJ31rrtIAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/lefthook-darwin-x64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-darwin-x64/-/lefthook-darwin-x64-2.0.11.tgz", - "integrity": "sha512-D013UNKQa4FKgpxDMqdaU109U2/Pidtrt9CobQoq8te4eGUglcwxMzuYVTgaYnenz0FgKxSfVaCZsZgwqeMWqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/lefthook-freebsd-arm64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-2.0.11.tgz", - "integrity": "sha512-mgfNqG1tiJkCuGNwPG0LEfnAHGJA+Qzl6KidOtX/Zhxmj/sM+6hxiP4LOeEAhCnaZF5kuPtQgbFzShFHc2BK6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/lefthook-freebsd-x64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-freebsd-x64/-/lefthook-freebsd-x64-2.0.11.tgz", - "integrity": "sha512-rnHOlQbJfLGCibr7yHM44kPNgf/tFpEbj/cWVHRhjRdbgYSCAjJk0uKd/EVo3v/vjfId2na0AhWbLvO/aY3wQQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/lefthook-linux-arm64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-linux-arm64/-/lefthook-linux-arm64-2.0.11.tgz", - "integrity": "sha512-1XjDo2/4fM0TbJBwxZh8w+WMOFueg9oYHkryM8vc3vp8wTajdWBazg1K37JIS3FUco3tcOs+eWHQg0ekVjpWoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/lefthook-linux-x64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-linux-x64/-/lefthook-linux-x64-2.0.11.tgz", - "integrity": "sha512-OKOcfEvozXhO7+y2xgUzvc2kkqfhluql/sjQSzd8Ka+iK3hM4KCfbfgYx9q61Pjr34a0+i03cuH5DF2dlq/rrg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/lefthook-openbsd-arm64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-2.0.11.tgz", - "integrity": "sha512-n1KEx196M3SKaWVNTQXGgxzBsiYAsdAy6Of6I6TAZwPhG7yoRrKGkQrhOlPgMzYl36udG1Lk4D+mfY9T0oOUYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/lefthook-openbsd-x64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-openbsd-x64/-/lefthook-openbsd-x64-2.0.11.tgz", - "integrity": "sha512-WAEtKpYUVvuJMVLA38IBoaPnTNSiaEzvUYxjTBlYTLHJwn7HC2GG6P1cnvoua8rfxb9/Bfi7C3D3IPa9VmB33Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/lefthook-windows-arm64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-windows-arm64/-/lefthook-windows-arm64-2.0.11.tgz", - "integrity": "sha512-HBqW1qfAnmmbpet7gSWatB6H5YIFdGxCqzolMCLwY/0o8oPFiMwdNE5RGp5JMmhZdz/h3XlbaUlIhnxoW8dk5g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/lefthook-windows-x64": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/lefthook-windows-x64/-/lefthook-windows-x64-2.0.11.tgz", - "integrity": "sha512-e5TYmV5cBZfRrhPVFCqjauegLI5CjdAd8exyAbMzGHkiwp3ZK145Su/pntgEP3d+ayS9mpgYPJmXYOSL7WHlyg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.startcase": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", - "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.upperfirst": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", - "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", - "dev": true, - "license": "MIT" - }, - "node_modules/meow": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", - "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-extensions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", - "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unicorn-magic": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", - "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 235d230..0000000 --- a/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "quantum-system", - "devDependencies": { - "@commitlint/cli": "20.2.0", - "@commitlint/config-conventional": "20.2.0", - "lefthook": "2.0.11" - }, - "commitlint": { - "extends": [ - "@commitlint/config-conventional" - ] - } -} From 0aff811acc209aaa6680cc6ab51925004ffc9b5c Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 13:28:56 +0000 Subject: [PATCH 075/113] chore: migrate commit message linting to commitizen Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- .devcontainer/devcontainer.json | 2 +- .gitignore | 1 + .python-version | 1 + AGENTS.md | 6 +- lefthook.yml | 2 +- pyproject.toml | 15 ++ uv.lock | 425 ++++++++++++++++++++++++++++++++ 7 files changed, 449 insertions(+), 3 deletions(-) create mode 100644 .python-version create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7cb3f10..84b5133 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,7 @@ }, "ghcr.io/thamaji/devcontainer-features/gitleaks:latest": {} }, - "onCreateCommand": "rm -rf .lake/ && lake exe cache get && npm ci", + "onCreateCommand": "rm -rf .lake/ && lake exe cache get && uv sync && uv run lefthook install", "mounts": [ "source=lean-project-commandhistory,target=/commandhistory,type=volume" ], diff --git a/.gitignore b/.gitignore index 015090f..5eca900 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.lake +.venv/ node_modules/ lefthook-local.yml diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/AGENTS.md b/AGENTS.md index f11ebe5..c3f3188 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -90,12 +90,16 @@ The following tokens are strictly prohibited, grouped by reason. ## Commit Style -`lefthook` + `commitlint` enforce this; the accepted vocabulary is: +`lefthook` + `commitizen` (`cz check`, configured in `pyproject.toml`) enforce this; the accepted +vocabulary is: - Conventional Commits: `feat` / `fix` / `chore` / `docs` / `refactor` / `test` / `perf`. - Lowercase type, colon, imperative subject. Example: `feat: add GNS faithfulness lemma`. - One logical change per commit. +The hook runs the stock `cz_conventional_commits` schema, which also accepts `build` / `ci` / +`style` / `revert` / `bump`; the list above is the deliberately narrower project convention. + ## Style Guidelines The Mathlib contribute templates are authoritative; the bullets below distill what actually comes up during edits. diff --git a/lefthook.yml b/lefthook.yml index b9837d9..e1f727a 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -5,7 +5,7 @@ commit-msg: commands: "lint commit message": - run: npx commitlint --edit {1} + run: uv run cz check --commit-msg-file {1} # Scan for secrets in staged files pre-commit: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..182f3b0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[project] +name = "quantum-system" +version = "0.1.0" +description = "Development environment for quantum system" +requires-python = ">=3.13" +dependencies = [] + +[dependency-groups] +dev = [ + "commitizen>=4.17.0", + "lefthook>=2.1.10", +] + +[tool.commitizen] +name = "cz_conventional_commits" diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..3743243 --- /dev/null +++ b/uv.lock @@ -0,0 +1,425 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "argcomplete" +version = "3.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/6f/5a73f04007ca950701765949209f068da628bd11f9c2da287278ce91e0ee/argcomplete-3.7.2.tar.gz", hash = "sha256:aad8b69a0b9969edb62db0d1752354c0d50717b10e0cbb00e2a958381b9fc6b9", size = 74473, upload-time = "2026-08-06T04:53:21.662Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl", hash = "sha256:6029205678bdd9c1c728a155f5f9ecf5812393f969eef58807641a2bc2aa5b19", size = 43294, upload-time = "2026-08-06T04:53:20.246Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/31/4971872b3ed8715346231fb6eb4da8fcba65a4143c189db151ee28a2812b/charset_normalizer-3.5.0.tar.gz", hash = "sha256:49bd5feb59b0bf3cbf6ebcf4352e371c95b9da9bacd4449f8b64d0ad2c10a26e", size = 169295, upload-time = "2026-08-12T14:35:31.624Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/be/cc7b7b6fc41984902c0d31b06f5d9297e67705c1dae9352608e5540fad09/charset_normalizer-3.5.0-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:5c23fa4f6eccdd601949cb00f3988c01d64e671d8faba356397971077022e144", size = 211050, upload-time = "2026-08-12T14:32:47.81Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ae/e3ec8f17313609f43f7b323012fdb1ee37b83432277ca4eceba83e00366c/charset_normalizer-3.5.0-cp313-cp313-android_24_x86_64.whl", hash = "sha256:07f6f42b5a6325df35b458004fb5f9f29bf502d89287a33c7cdef3590e31de0f", size = 222768, upload-time = "2026-08-12T14:32:49.027Z" }, + { url = "https://files.pythonhosted.org/packages/c5/50/9f9c0d7ccc1512d49e27a0e7c12c58ec71dfe91698fa4326f058c33e1f1b/charset_normalizer-3.5.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8efc3f1563ed431882dd0dc0411b5f8ace1b1b89074981deaf6bd8af77dbe1bc", size = 193907, upload-time = "2026-08-12T14:32:50.414Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1d/cfe7b745ef7f4c3b7214581955b5a0869ba2ac551a58fc11036281ae167c/charset_normalizer-3.5.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:368eb2fc9482158b3a3386e8f01fa61f479c968e9a19ceab8f0188b86b312991", size = 197135, upload-time = "2026-08-12T14:32:51.605Z" }, + { url = "https://files.pythonhosted.org/packages/28/55/30fafdcfca9ba616bc394240545e4cd52f4f66dea43ded81b7d2d5274fde/charset_normalizer-3.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:826a295a039178479a325be1ae60eded1f0b10f7dda749df59e2440de8f61d64", size = 339892, upload-time = "2026-08-12T14:32:52.82Z" }, + { url = "https://files.pythonhosted.org/packages/f4/08/bdca5fc2bdc36ee443673dc7d12b23885a5a7b282bef85a1a4c3b325b40e/charset_normalizer-3.5.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70ff1c16eb0eb5ee6bb12739292347f981a5ba764cc4df1bc2e69b0405d4ac3b", size = 239439, upload-time = "2026-08-12T14:32:54.058Z" }, + { url = "https://files.pythonhosted.org/packages/d1/9e/506c8d7a7722bba7c8cdd78c1b5ef23bda92bfbe0b3e28ea84673d519a0f/charset_normalizer-3.5.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3cfdab178a4add5483e26a9bb1c16d8018ccf39b4be7a3aea6c3979e6828f2ee", size = 227896, upload-time = "2026-08-12T14:32:55.326Z" }, + { url = "https://files.pythonhosted.org/packages/0d/1a/dd828f2b1d6f4bf10821b9a74d866be05ffcdbfcddfc501d6fe6428762a7/charset_normalizer-3.5.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6083d10a846218502d664375b9448508d9fa580bd834567423156c6abfbe899d", size = 262548, upload-time = "2026-08-12T14:32:56.484Z" }, + { url = "https://files.pythonhosted.org/packages/be/81/196d26f6bd78b93e0d451b69082a71027ceeddd4b0be9170b81bb038f824/charset_normalizer-3.5.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0f211c21aa316cb6e2662e54a1194633a79d98a50a876addacfce7ba5b34b09f", size = 259986, upload-time = "2026-08-12T14:32:57.661Z" }, + { url = "https://files.pythonhosted.org/packages/3a/6a/5b964a1eb0f9075ecd45083eeb21aaec215334f98bac3d400302ea73875d/charset_normalizer-3.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b08ebf9488c7ff5eff038e48e6ea938178dfd9dcc8598b5ca941e4ae27b20be", size = 249853, upload-time = "2026-08-12T14:32:59.123Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b4/aee3a9d82edd0e931091ef3e9f03e46491ae3590e96e998d0975dadbe17c/charset_normalizer-3.5.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c95450fce59f00c6d08eff6572ec2e736e5054c9450253afd5748f8416f2eb9", size = 244217, upload-time = "2026-08-12T14:33:00.341Z" }, + { url = "https://files.pythonhosted.org/packages/22/3e/33f72ca11c1b619b220fd9f35905ebd171cbd0e0470f2357e467b9e861ee/charset_normalizer-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5780a29823e1d2bec69b7a104ead4195a43f3e97782efaedbf1f79a0157af715", size = 241307, upload-time = "2026-08-12T14:33:01.589Z" }, + { url = "https://files.pythonhosted.org/packages/78/27/6029dccba958621c7f3a65136f87c5512d712aef9e890f09512cc171bd03/charset_normalizer-3.5.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:054420b5db984971d886e5e4e2c37c760ae6682aedbd066687ff0949d9ed5f08", size = 233305, upload-time = "2026-08-12T14:33:02.866Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/691c967be459153fe9faf49bf78bc95639ef8bf6dd008f38cc6389a349eb/charset_normalizer-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d016dc857136c726958102c3b8a3986acdc65ace6fbf12cfdc09cc4bfa2935b2", size = 263465, upload-time = "2026-08-12T14:33:04.166Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2d/9202221be5c90b2a835924191e362690ed8dc8c7d6606100c2bd03fe0f8c/charset_normalizer-3.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f2ce3d39fb4a9d674e6639dd5d3146b2e273475d2260f10163228d66fc04433d", size = 245060, upload-time = "2026-08-12T14:33:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9a/298772fd0a0cbccadf36451a1cd7eef4b66a11e99b4a7f6fafc47cc62c75/charset_normalizer-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:a5613a3a82c974227bde18f03409e30c467f8065cb56d822e3eb83708a5f223d", size = 261091, upload-time = "2026-08-12T14:33:06.475Z" }, + { url = "https://files.pythonhosted.org/packages/82/3b/1a11fe66e555dbe2f5714ade6ba74fa29edc9155d9cf1001d4d6ed096aa7/charset_normalizer-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fded2e82ff082e5d8e017e2ddcc1411bd8cb83b8585097fc401ef574f756b888", size = 251857, upload-time = "2026-08-12T14:33:07.784Z" }, + { url = "https://files.pythonhosted.org/packages/17/fc/73b817e8af3f1d25ec5cf458d405abba5a144cf9812238a61530f5eac186/charset_normalizer-3.5.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:8f006866047c6ec4b627ec144b1e0bbc7427cb31fd7c08d19897d0ac9032af3d", size = 139745, upload-time = "2026-08-12T14:33:09.123Z" }, + { url = "https://files.pythonhosted.org/packages/b3/fb/ddb66303c86f7dc5043a457dad9fa82b4d6d0cb97094f9bcdde21693fd58/charset_normalizer-3.5.0-cp313-cp313-win32.whl", hash = "sha256:196e270c4e80827b5072eed7d6aa661d133afada94fe366669f9609e718d305e", size = 177217, upload-time = "2026-08-12T14:33:10.305Z" }, + { url = "https://files.pythonhosted.org/packages/fb/88/6018cc8d76ea2b7cb02918f37e23e86c261d1a102713d7e88d2cfb8b211c/charset_normalizer-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:72982d9958a42f8132bf2d6b90214ed66477295ef1188731f98ae3511c6eeb5a", size = 198896, upload-time = "2026-08-12T14:33:11.51Z" }, + { url = "https://files.pythonhosted.org/packages/20/2e/04c0bbfc8d9abf91959f7a3d207d45cbf63a8116984caae2381890019bb5/charset_normalizer-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:0b373bab0b867b68b8eb249da9478cab9181a42993437cd2f5dba5fb0b4fbd1b", size = 179193, upload-time = "2026-08-12T14:33:12.726Z" }, + { url = "https://files.pythonhosted.org/packages/43/14/d098868dac5ff27e0258f548b1c74c6484be528384965d8fcf8fc6a4011d/charset_normalizer-3.5.0-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:d95244906ed69d0f79f190893c65e336c15959003e21449256dc05c001b52ea2", size = 211664, upload-time = "2026-08-12T14:33:14.153Z" }, + { url = "https://files.pythonhosted.org/packages/e7/da/a944b32a46601ae5a4c3499e8d64ecd14fe82313f00da74dcdf00273a0b4/charset_normalizer-3.5.0-cp314-cp314-android_24_x86_64.whl", hash = "sha256:d788e2ded0c4c47efa4d73cfe59eaf975ee32f425219873d2cb3e3fbaa00f636", size = 224375, upload-time = "2026-08-12T14:33:15.472Z" }, + { url = "https://files.pythonhosted.org/packages/f7/db/eabb5996be2f529744755e7b2fc9396eff4a64961f034e7fd49d54b9afb2/charset_normalizer-3.5.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:f9f91d3e8382900f3a68fa0ce94294479de9cd2de6bc0c70acd0f0dfd511836b", size = 194364, upload-time = "2026-08-12T14:33:16.607Z" }, + { url = "https://files.pythonhosted.org/packages/78/65/4ad3c5be108930310d8003f5602861d5b89f728293b9f09c3a4837f7ba10/charset_normalizer-3.5.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d54625cbf4e6b60bf0639728cb8b4cb541e340f6d7cafae5806051a40ddf4c45", size = 197643, upload-time = "2026-08-12T14:33:17.88Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8fee3201b98d52289be60a775797d69be05a04fb6cfb48c1587dad33e649/charset_normalizer-3.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:1f99a8c3a1da5d955edbad18208b3d627bdd54c48a6e739fa877bdca98c686d6", size = 341384, upload-time = "2026-08-12T14:33:19.239Z" }, + { url = "https://files.pythonhosted.org/packages/a7/dd/9e757101d1f76c35c0643684ba499ac3a181fb2b264c68174bf727d627e8/charset_normalizer-3.5.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf1e75dc07a3850b53d1e5f75e04d3ae12afe56284be7821771eaa2466350c73", size = 241637, upload-time = "2026-08-12T14:33:20.619Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e4/7857023015400bc4aa0a82fbcca29fa2dc7ec25f971a130764cb2dc7a589/charset_normalizer-3.5.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ac5a9cc079c67d75f4ddf343276031879eadbb333d1bb231cce297b8d7b9aae8", size = 226170, upload-time = "2026-08-12T14:33:21.773Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ae/8b52935b304f7b6bbf33151ed2b75266b09aa4b6f8f04230d948885b2577/charset_normalizer-3.5.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0dfe83c1b4d00abbf433998117a14f56a5c2bc68226c0d331709eed0d1ce539b", size = 265093, upload-time = "2026-08-12T14:33:22.999Z" }, + { url = "https://files.pythonhosted.org/packages/dc/78/6e838f6bb059f2c0afc60a4e7f294252f043c254656ad4114c50302cae4d/charset_normalizer-3.5.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e4e8fa586df2208ef040684751345f10f503834a757c9a74ecd19c1a2f9b1ccd", size = 262789, upload-time = "2026-08-12T14:33:24.214Z" }, + { url = "https://files.pythonhosted.org/packages/c2/08/189b27e51fddc9d6b3695331da0e31792c1d88b953ad854e57f06e9b2cc8/charset_normalizer-3.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:82cc5835997ec78afe293a192e385099355770a7db94b2fb1239d36b32796f1c", size = 250580, upload-time = "2026-08-12T14:33:25.707Z" }, + { url = "https://files.pythonhosted.org/packages/ac/55/64854e99b25841f83e8e37d9df2f3d1f96f693439f80e5fabd542a7e47ab/charset_normalizer-3.5.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:19e52bda45086df8a4be4bb5910af6f5d9d3b538c78712c8ae09ef10b85bf458", size = 245008, upload-time = "2026-08-12T14:33:26.971Z" }, + { url = "https://files.pythonhosted.org/packages/4f/01/7720c904fa635d4260b4dced6029cf3d298c57b26741365d5a8d28c54043/charset_normalizer-3.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3418edd0ecb72a0a3861cf72f31be0ad9b7fe338ce2b58fb5cc80b9aeb792700", size = 243892, upload-time = "2026-08-12T14:33:28.237Z" }, + { url = "https://files.pythonhosted.org/packages/70/50/7bfcb327631d4870c720872b548745f6ec8baa044d51c21b5d1d32ac4e3a/charset_normalizer-3.5.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:125ee619611019471b177c70bc3e9d4cda9fad7e01d93523501d3b188df0193a", size = 230996, upload-time = "2026-08-12T14:33:29.511Z" }, + { url = "https://files.pythonhosted.org/packages/24/51/40c45d6d940c04005ed721aa54bdebf1ebb2930f8a2ae537e8d60484fb27/charset_normalizer-3.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a3ad0e3da22852533858663848608f3f24c0d35e5cde415a4903476f2b4c88ec", size = 265834, upload-time = "2026-08-12T14:33:30.689Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d4/ef7a227ef89d215b47f9df79c3966610b17faa13bb2f236989207a631622/charset_normalizer-3.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:4ebebb410bc517e1d284c52a123e82704b21e4e7e26a21ebecf7439d0647b8a3", size = 245544, upload-time = "2026-08-12T14:33:31.859Z" }, + { url = "https://files.pythonhosted.org/packages/37/a9/a4ca9156964ded61c7718eba410ce11be2fd2b263fda4bcf08367b6578cd/charset_normalizer-3.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:91f9f7c151e772acebe489eaec96e96a2877202d7dd144e3f96b8676881715a0", size = 264110, upload-time = "2026-08-12T14:33:33.13Z" }, + { url = "https://files.pythonhosted.org/packages/38/6a/838364bb8702229c6e5f8b23f80ff0f052a12dfaf3113a12fd6acbe92a44/charset_normalizer-3.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:401ea6e7af9e7852ed818f64714b579c1935482049670847ca3bd7ba45dc63fb", size = 252303, upload-time = "2026-08-12T14:33:34.98Z" }, + { url = "https://files.pythonhosted.org/packages/9c/5f/d88032edce951f499a2321cf7ae0d35a043c74be12bc22d81084cc7afbcc/charset_normalizer-3.5.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:f7496aed56b06325a1ad419c5bf23c6dd042558e874f71dd1b958f3e255f3053", size = 139964, upload-time = "2026-08-12T14:33:36.195Z" }, + { url = "https://files.pythonhosted.org/packages/37/ae/1c4a46b6b00d1c34d2ee355ef99ad6173674166800d1af0f05f85028d513/charset_normalizer-3.5.0-cp314-cp314-win32.whl", hash = "sha256:606a86c1c3196f3738de39a67a7490bbd61cb31c0e0436070bd0c6a48170b38e", size = 179790, upload-time = "2026-08-12T14:33:37.356Z" }, + { url = "https://files.pythonhosted.org/packages/01/51/f94dcf34fa8eba48c1fb89b6490a5f1426e19488fe5f38aac6c648c99057/charset_normalizer-3.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:ec6c464cf45867f66a2273e2214d9199a8fbad5cb95ca0fd45f6a2fe1d9d2cf4", size = 203723, upload-time = "2026-08-12T14:33:38.639Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ba/91d386870b5d9e4b0d8c4034f63877cc2e47b99c81ef05f3e6d42bf9a53f/charset_normalizer-3.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:dc28949de1bb5f7f30a46f15d74ce7ac5aaa63e03c5de04d68f571c7423af834", size = 183423, upload-time = "2026-08-12T14:33:39.899Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c9/534ecb17b7fb95f9052c4a44cf316316a27d4a8f73e8475ff55e778dcdd7/charset_normalizer-3.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:68b7e84ae8239a94f8d2c8f3f3a3a81bcde54805ec8f42a34de927d155688ec6", size = 368967, upload-time = "2026-08-12T14:33:41.093Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/ad7c3242d7fe55cd55126c22c65cb1b49779782cdf8932fd01d12232d86a/charset_normalizer-3.5.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:58ca5dc0a0ef99f2801ec0574214c978e9574055bc783830bbb6e7433218609f", size = 239478, upload-time = "2026-08-12T14:33:42.428Z" }, + { url = "https://files.pythonhosted.org/packages/7e/62/77f0b850048e430fc350ec58876b0c020f5c8d0d3956fd1a4d6ae2fa292f/charset_normalizer-3.5.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6c57af4084c10cb3286688d65e4c654190ff5edcbc2411d08cdca0a8a44c59a1", size = 227036, upload-time = "2026-08-12T14:33:43.635Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ba/47d951e1a51dddbaad0a1410baf49fb1d897ceb00281568f1183b79bce9a/charset_normalizer-3.5.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1619a3cc174a7e3963dd34348e6fceb6e50db0ddeb0031bd7c73a58286454fa", size = 260772, upload-time = "2026-08-12T14:33:44.96Z" }, + { url = "https://files.pythonhosted.org/packages/b0/61/8c7ff4c81b2a88271126acf4b83ab3e31f6d63868b0f01d331eaa0f9cb67/charset_normalizer-3.5.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1328cc57dd4372be1265f68232cee890e087416e3e6e93e6ffb32c2bad4d36a4", size = 259273, upload-time = "2026-08-12T14:33:46.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/fd/36129689be08dc287b951306946657ff70d76e287dd57018861f86d0e474/charset_normalizer-3.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:06f4fb62a9139bef056b8b2da6773c94c2f259f90e4b8e53b166f3d0372d7cf6", size = 248086, upload-time = "2026-08-12T14:33:47.54Z" }, + { url = "https://files.pythonhosted.org/packages/cf/f8/bcae67f994c8fd31dda445e5ebf84045823c31443fe46f0e9ee6aca99aa0/charset_normalizer-3.5.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:478650a70a750d75d5add401606c77f77069c32e4ba2c9131dc6cee566962ca0", size = 242671, upload-time = "2026-08-12T14:33:48.746Z" }, + { url = "https://files.pythonhosted.org/packages/61/92/0472cdad1061c2f0e4d3aee29973eb6e81bb8fe256ff2860cf115b15f1c9/charset_normalizer-3.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48920bf6fe83eb2226756ac623fa54940487154eb18f80889d5735cf234965c0", size = 241311, upload-time = "2026-08-12T14:33:50.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/89/04a03de5d27c77c624d9fcf6287073754bd438df1b58cb7d030c57c2824d/charset_normalizer-3.5.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:168a0cb536b5123a77bc42ecf5e0bf6f923d0d9ae43c42a14eb0677c19ac6c19", size = 229898, upload-time = "2026-08-12T14:33:51.523Z" }, + { url = "https://files.pythonhosted.org/packages/42/a2/639c4278adcb7ed1f4db608dd9ac19b6774fa2285a96b1c0bdb9c124ccbd/charset_normalizer-3.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f278e131afa96a3622cef9211c406ea2ad1b68eb06f8837cd443684a40e0ae50", size = 262852, upload-time = "2026-08-12T14:33:52.924Z" }, + { url = "https://files.pythonhosted.org/packages/9d/95/02e34c97bedfd0c5574efb9179c850591acc7f967ba039ed8dd29d332b73/charset_normalizer-3.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d6100f877d2ed95f0856a3fde25334153add94bf2224c43f45f88e7039262aaa", size = 242913, upload-time = "2026-08-12T14:33:54.18Z" }, + { url = "https://files.pythonhosted.org/packages/a3/64/0946aeab6462dad9f160a50dfb4704d3f58a5ee708f085abc2105fbbff0c/charset_normalizer-3.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:4c440122e1ea68b1f8b44a631ebf49c39180f6869b1da22d76e8a724208ec6e9", size = 257938, upload-time = "2026-08-12T14:33:55.802Z" }, + { url = "https://files.pythonhosted.org/packages/79/77/36787d41ead124746506a4425c729f4f17c68280af8a6a5baa0a598cae86/charset_normalizer-3.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e5f834965c2fe589837bac1002e07e25734ff70381903ccd95b3d649e22bfa40", size = 249467, upload-time = "2026-08-12T14:33:57.081Z" }, + { url = "https://files.pythonhosted.org/packages/65/10/d9f6c5589cd24198d4ce6cd2948191c18e657272f433e5a00d258d9f5c22/charset_normalizer-3.5.0-cp314-cp314t-win32.whl", hash = "sha256:076cf9d3f3c7e410295c09d96355cf3b1bcae74990034d80e4371e20fe1ba4c6", size = 190624, upload-time = "2026-08-12T14:33:58.449Z" }, + { url = "https://files.pythonhosted.org/packages/6c/81/43e0584a802051a22c725795ebe1df78263abc7de858eef6cdc9b36637e9/charset_normalizer-3.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3288a560dc3114d5d2ebe309b1ef43f8af355eafe25856832415c2a8196c9db3", size = 215902, upload-time = "2026-08-12T14:33:59.753Z" }, + { url = "https://files.pythonhosted.org/packages/30/f3/af6a1160fef0eac4510d035241e11eccf78e5350e4cd4de79e79fe02a5e5/charset_normalizer-3.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a284c36b9c6616bf0a8aa4aabba668a0c75ba65ccf40a79868aeaa69ad996897", size = 193452, upload-time = "2026-08-12T14:34:01.017Z" }, + { url = "https://files.pythonhosted.org/packages/42/a4/dee470afb7a55c4f78b6fef37306c51fed17ebf94dbe530798c91d394350/charset_normalizer-3.5.0-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:c38d1e9bc2073b0984d2099ea647fd7f6c0d8f83a1e14e0cd32926f16e4c44ce", size = 341595, upload-time = "2026-08-12T14:34:02.4Z" }, + { url = "https://files.pythonhosted.org/packages/6a/32/9c3126dc429c6d9d7f79c52681a7c4453ed20a26267c9a8275d7ab620aba/charset_normalizer-3.5.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9f45186390aee4d1f26f723c615b67df346766c3b16df000d84d6e374f06757", size = 242177, upload-time = "2026-08-12T14:34:03.741Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9d/5b616a887301ff4cc0916b39ba44257390d3da80deeed6e8b6f2f26b14a8/charset_normalizer-3.5.0-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f0fde5e5100c735b2274ab898f0742a5dcde492796296cfbe7e0ad6a4cd1a396", size = 236730, upload-time = "2026-08-12T14:34:04.991Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/d6d3e70be93ebe5fabef65e4c7ac113e1d1705cbaeb5fb72467e713aca17/charset_normalizer-3.5.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d00e18e7bbf47e332ab63903d18bae31efc701b1d8cca0382b97784a621fc44", size = 265158, upload-time = "2026-08-12T14:34:06.235Z" }, + { url = "https://files.pythonhosted.org/packages/30/e7/3f1fafa87e2643257474f9c4eec609f2193a61d907dce7dd4f3f2390ebd5/charset_normalizer-3.5.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b81980668800dd1c69faad8aea6e85a8cee0e13bcd3bba7671695ff16260293", size = 262931, upload-time = "2026-08-12T14:34:07.511Z" }, + { url = "https://files.pythonhosted.org/packages/0a/df/ebeb224a949d91829e5e114c6b64372a3c792b00762a9e951ce416f3a32d/charset_normalizer-3.5.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bb3e0d1345b9c0fe73673ea656375f38a78ec679c2edeae0c24800f04798a85", size = 251388, upload-time = "2026-08-12T14:34:08.949Z" }, + { url = "https://files.pythonhosted.org/packages/a0/64/9a6ce2e7acc5cf1b4636f78f82e89ff581e06a0216a40678b28bd4d832c4/charset_normalizer-3.5.0-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2401f7671242e921e604f609d429f6b282ea4ca787a6ffd22ed7372011ddb9d1", size = 251821, upload-time = "2026-08-12T14:34:10.138Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b1/6e69b8056f615e5ccff6b91ca16db2d47922251f016821a300c115267fef/charset_normalizer-3.5.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:96720f2aeed3434bc48f4d52fbad64ecc820cfed88915d664780ed9ba09ede78", size = 244507, upload-time = "2026-08-12T14:34:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/0f/34/02c15d6a0aa6b934dcdc136b111da63ae857b9fd51cf5505b0736337c2eb/charset_normalizer-3.5.0-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:c455829625df983f716cbaecbba77f2d1dc2e0e0ed1638c059cece15a279344b", size = 240951, upload-time = "2026-08-12T14:34:12.991Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/0fe893d3e1c7d111280bd6c4bd4c1e431487a1124a1bcbce78dfeda3a3a8/charset_normalizer-3.5.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:c41b067eddcfa5ee6b1169c287605be7fb6b0ea22bba6474c5bb978a668def4f", size = 266162, upload-time = "2026-08-12T14:34:14.232Z" }, + { url = "https://files.pythonhosted.org/packages/55/ea/eca03527307670f5d102c295671a800c404ca958cf94fefd10fc963a72f0/charset_normalizer-3.5.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:e31786a947b136329bfdc458c82c06d4ec539b4a4436b7da4df4aafc9902ee80", size = 251835, upload-time = "2026-08-12T14:34:15.48Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/fee5633081e595fe9e191df6f215106c791ad596eddf5e41e39b8ea0f2e2/charset_normalizer-3.5.0-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:c5c6d47a865147e0ae3322ce92e7fb52ba3169d94b447deda56897ea2aa6fac9", size = 264314, upload-time = "2026-08-12T14:34:16.679Z" }, + { url = "https://files.pythonhosted.org/packages/cf/fb/17f47ae6ca35b562fb6e6f4b05f7aec6034217353eb4a23aaa3566dc7340/charset_normalizer-3.5.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:c75191e3c8052045179646cb40e280800a4e0bdfda34d9c949c2f268d44e80e4", size = 253194, upload-time = "2026-08-12T14:34:17.975Z" }, + { url = "https://files.pythonhosted.org/packages/59/88/f2b0f7ebb92493e925889ff29239b3b0073ffafd91230dbfc69e5cf9389c/charset_normalizer-3.5.0-cp315-cp315-win32.whl", hash = "sha256:83b62410bd36bb1178a7d563e2ee0cf21eb1c980c912ab99c2c78f06227f1731", size = 179800, upload-time = "2026-08-12T14:34:19.409Z" }, + { url = "https://files.pythonhosted.org/packages/e2/f0/afb5bfdea52fd943b1960403847a276b8e900c6e4cd6a38752321b4eda64/charset_normalizer-3.5.0-cp315-cp315-win_amd64.whl", hash = "sha256:e3b9eaa99a6d8c9ace4cd303915947ef55088d4cd87c6676874f98c5c03aa040", size = 203726, upload-time = "2026-08-12T14:34:20.656Z" }, + { url = "https://files.pythonhosted.org/packages/fc/71/219783eb691aa2ec879c0e521afdfe2b826f9678eed51b9c039d03e0db2b/charset_normalizer-3.5.0-cp315-cp315-win_arm64.whl", hash = "sha256:fec352b793cdc183cc9e7e0b6c10fd7bff38ec54ba44cc43599b9b56f7f3db2e", size = 183428, upload-time = "2026-08-12T14:34:21.975Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d0/14aef3b9f80f2593c039d897e89034635b9eb0eb44b6ce5173bbd79ff338/charset_normalizer-3.5.0-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:c9bde7a960720c8b8e1b5ef7afaa0c9a2f3b55c44abd635b2b29dd066b298e3a", size = 368728, upload-time = "2026-08-12T14:34:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/10/fc/b249466ddbbeffa448b6597631e9091d1f01b5132ff8e7a0e21a6eb72b63/charset_normalizer-3.5.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f8cd1283a9fe6c2065c807e9d5da81afe5e1e004caef39adc0d8ae86dd883698", size = 240925, upload-time = "2026-08-12T14:34:24.504Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b9/c17e72aaa1b3e1ca6c184e8025cf138ed492d01a54f85286ff7d31253a4b/charset_normalizer-3.5.0-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1c010dd86d3f4c4433c9634d33ce8147393b270dfa54f217f965540b8ae8e075", size = 234932, upload-time = "2026-08-12T14:34:25.822Z" }, + { url = "https://files.pythonhosted.org/packages/18/d7/f84ef0966bbe216f71029e34e7fa425a16b1682e2a40265e679dedf2b655/charset_normalizer-3.5.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5e68229977b2dea28e7061c0c0630a23f2f9f6e9c6fb38d77d3d6dbfe3768b74", size = 261733, upload-time = "2026-08-12T14:34:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/3b/73/3e887fa0781a395339355ed934ab6561ceb5bb52574160f070224039c630/charset_normalizer-3.5.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a60773eb5fda796e6e6f76b9c152d270fe59f9788a51a6ff8ba44082d8548ae4", size = 258460, upload-time = "2026-08-12T14:34:28.431Z" }, + { url = "https://files.pythonhosted.org/packages/b3/81/52ebd9849bf9e35d0b21fff115cb6543162a8e1f2f564e8f87121a336b8c/charset_normalizer-3.5.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9419f44e568f7fafcdc0b3b5c766a2364e705a9b34fb8a56b431e0d1f3f4258", size = 249894, upload-time = "2026-08-12T14:34:29.698Z" }, + { url = "https://files.pythonhosted.org/packages/85/f3/9366492b8a5fe0187de282e001d61345740cf79eb4a5f20181d769be02b5/charset_normalizer-3.5.0-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75e243abbb528c1a774390ed71e3f868a9f37b1373442e4bbadd401cfc505ff4", size = 249540, upload-time = "2026-08-12T14:34:30.96Z" }, + { url = "https://files.pythonhosted.org/packages/0b/af/28bb5e5dbd3e67cb9196a62781ac2b6d79492f4fc7a069b6ca7d6d6c8d58/charset_normalizer-3.5.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:54c963ce6404e52255b737e8a06d356fc762d59096ae566203a67cf2b7d050f2", size = 242734, upload-time = "2026-08-12T14:34:32.481Z" }, + { url = "https://files.pythonhosted.org/packages/26/d6/7ccfa62b53b40fc06b2d3504825aa400764740bd10cf248fdc4272441b93/charset_normalizer-3.5.0-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:63ea0cc840c66670183578c2630d138c0e944aeadfc33f25173ee240f5db780d", size = 239580, upload-time = "2026-08-12T14:34:33.916Z" }, + { url = "https://files.pythonhosted.org/packages/0b/82/71c0c9b046697b8da66b3acefa8d5f92d00a9ef433ad7c3522b971d0369a/charset_normalizer-3.5.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:6c06875a1d4a7537bef70f659b55c6b55b9a47ec3ba8f2db610350c2d9915e6e", size = 263281, upload-time = "2026-08-12T14:34:35.333Z" }, + { url = "https://files.pythonhosted.org/packages/d6/01/d027583c869f40ba980c1c76994adbd522c360a6327e72beb44d7c267385/charset_normalizer-3.5.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:4253da1b4456b633651a8d59eb1dc7a8a8fa38241014dd7c217b353e547ae394", size = 250027, upload-time = "2026-08-12T14:34:36.991Z" }, + { url = "https://files.pythonhosted.org/packages/2a/e9/6475d739e0ec8bb1236e06263dc3affaffdf947d8114ad27024932f325da/charset_normalizer-3.5.0-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:f044cb1cf44012184715f46584658993b5fee9344d71c4b0c455a17a299730c0", size = 257547, upload-time = "2026-08-12T14:34:38.277Z" }, + { url = "https://files.pythonhosted.org/packages/a5/60/d1f502fcaa048a2aca3ab80bfef8407659c131e4f1792fa805fec14b4960/charset_normalizer-3.5.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:a17864853f7c518ae7d4b368af98f427f9396805476af40af8698560f09d7d97", size = 251718, upload-time = "2026-08-12T14:34:39.562Z" }, + { url = "https://files.pythonhosted.org/packages/c3/69/76343dcf4381a698807ff8a20d89f66bbdd9f6222b0b17740f77ab764335/charset_normalizer-3.5.0-cp315-cp315t-win32.whl", hash = "sha256:9e726478d7a213847860219d74665a6892a643ac93b8f76580f6cf9ed39996b7", size = 190757, upload-time = "2026-08-12T14:34:41.053Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ea/d18147626a1667cc773c42104ab155a4ca5d6d4d174b7a35e01062213ea5/charset_normalizer-3.5.0-cp315-cp315t-win_amd64.whl", hash = "sha256:d7229a99120c6c2792d96f4857c2648ce5530e93667a2c2388c5ef69a6b84775", size = 215431, upload-time = "2026-08-12T14:34:42.501Z" }, + { url = "https://files.pythonhosted.org/packages/47/21/4869598aae0872d94faa5933918a4fe37ab2c5af9d095786e241f9506fed/charset_normalizer-3.5.0-cp315-cp315t-win_arm64.whl", hash = "sha256:527e28a5e751d9e11369b9c5f9ab35c748eb9c109101920c7deb40d6eadf8d03", size = 193205, upload-time = "2026-08-12T14:34:43.781Z" }, + { url = "https://files.pythonhosted.org/packages/5b/f3/7b523d807cb5e73562ef8acf21d39cdb9d704955327362c781bc3478a73d/charset_normalizer-3.5.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:5a4ee37248dfac25107c758bda99d545ce73e60b44d2dd39e4a2bb9f2831e9f5", size = 330840, upload-time = "2026-08-12T14:34:45.06Z" }, + { url = "https://files.pythonhosted.org/packages/f0/de/fc68978fe78ca97063c96d764e41ff92ca639948f319271e0ff450e577a2/charset_normalizer-3.5.0-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a864bdcacd8bff58bb4845304e031f821a3ec64b2b7259f2d409cd49c9e59ca3", size = 251862, upload-time = "2026-08-12T14:34:46.58Z" }, + { url = "https://files.pythonhosted.org/packages/a9/cb/82b41a0ab7fb1a88065f1d78ad32696ad88ea3fe8e25b8189d08833938de/charset_normalizer-3.5.0-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:84b736e3b391601bc47b86da381c749c0f894e9191aaca9f31f30c2632206df3", size = 239484, upload-time = "2026-08-12T14:34:47.869Z" }, + { url = "https://files.pythonhosted.org/packages/e8/0c/19608b631f4538f908098d4a2d56a8f79a665e27cc58e9d90479761a9227/charset_normalizer-3.5.0-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6abb1f356fb865baeb6ebc3fadd843e9a96fbf49b9adcca55037f3cceccb7438", size = 230602, upload-time = "2026-08-12T14:34:49.265Z" }, + { url = "https://files.pythonhosted.org/packages/29/db/f648eb30e14eba301aed61e11672156f137905c1bdbb530151abe8065943/charset_normalizer-3.5.0-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d366548d2ee28a8cfdcc4296363978cc644a728333be9824d2de4652e83df0a", size = 259208, upload-time = "2026-08-12T14:34:50.632Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e0/ed2c8bdbac484d69614d6993143aeb6cb0f4dd1561c883402517b623c8ef/charset_normalizer-3.5.0-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d672f329ae504ee240eb39b6effb3318aa8e7e8924c0ce8eee5760b3fad98539", size = 253659, upload-time = "2026-08-12T14:34:52.11Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/b4907cb9ec5b521d9d024ced13611240b86ef065c2eb15b3ad2334dc9940/charset_normalizer-3.5.0-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c54036a518748b6c02e666f6d46c3817561998fb904c3be25b56fb4fe3dc5706", size = 248821, upload-time = "2026-08-12T14:34:53.399Z" }, + { url = "https://files.pythonhosted.org/packages/12/b2/e2d1abcfbc05822f0030869efb4e9f8a3658e13b4821796d4b62da917327/charset_normalizer-3.5.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:22a1889f1c9b752c63c36758a0c2145458e3cadb20fced7a0790002e9dd12b26", size = 240271, upload-time = "2026-08-12T14:34:55.09Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f9/4ba127ad610542fa3eabfa41c45bf12d357860a815b3566374ec0188e213/charset_normalizer-3.5.0-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:b7eb3eab5c646d3de7dcb14a7c9caebace5249c5767da39e1761cb1576e521a3", size = 232155, upload-time = "2026-08-12T14:34:56.543Z" }, + { url = "https://files.pythonhosted.org/packages/01/68/40613182366d00bd6dbd5f6c84a926cbd120960e038a8269e9ae7d782762/charset_normalizer-3.5.0-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:2080aa129a28267984cdc902898993d788c995c384e285d0d19199f56760d52e", size = 259674, upload-time = "2026-08-12T14:34:57.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/53/4574a14fa4c9de4a6c9f31725354bfa40b67f653e6d594ce1654f9a41b32/charset_normalizer-3.5.0-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:fd68c825548a611158230e2f9222e210ceb2e3391995c0aa5865cbdf3ab4bd49", size = 246122, upload-time = "2026-08-12T14:34:59.337Z" }, + { url = "https://files.pythonhosted.org/packages/5a/02/bd8030d13d92c058ca7b2b9615bbb3169569e144db64d65c149cd45abf5e/charset_normalizer-3.5.0-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:d8a9316f4da85e937242642b537c6d55d7e9287dd38e5634732f8233932aff45", size = 255221, upload-time = "2026-08-12T14:35:00.71Z" }, + { url = "https://files.pythonhosted.org/packages/77/9d/10ecd3bcbe2666b3d4d4026c97b48f73990682815db516052a1e8f4a31c5/charset_normalizer-3.5.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d90254c8f609338c53ec180fcd4c4f9c16502e238e3fc88ca7fd4c2f38d445b8", size = 253450, upload-time = "2026-08-12T14:35:02.217Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0f/d044c4872c0938a84f87b5027a698c0e61bacfc5c3551a4e749ca9b7bc5c/charset_normalizer-3.5.0-cp37-abi3-win32.whl", hash = "sha256:8b3e9e29b8b07cc461b9ce7768db7693a93979d0dadf22046f6f3555ded2f516", size = 173594, upload-time = "2026-08-12T14:35:03.845Z" }, + { url = "https://files.pythonhosted.org/packages/10/6b/6046773901f1944b9a89436351529811ee958afc7b774563be9d74a6f0c3/charset_normalizer-3.5.0-cp37-abi3-win_amd64.whl", hash = "sha256:0c8953d9d1617794cfc40d81179571c9ba3805dd029623a15c93f1fb70e60a74", size = 198959, upload-time = "2026-08-12T14:35:05.187Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a6/b57708ac92aefc8e8389d51d5178129b81f03196da61ee2c23e687b8178a/charset_normalizer-3.5.0-cp37-abi3-win_arm64.whl", hash = "sha256:562d24ca7797c1af8852994950c2e623a907b201fc4b0ed29e92af173d3828ca", size = 267055, upload-time = "2026-08-12T14:35:06.533Z" }, + { url = "https://files.pythonhosted.org/packages/22/c7/754d09943a616937df61e4ba367c409ded2a987e872972098d51a6fcf73b/charset_normalizer-3.5.0-py3-none-any.whl", hash = "sha256:993dfcbe75a85a3784abb5084f2c41b915767c90546fcc92803cffa28611baea", size = 67943, upload-time = "2026-08-12T14:35:30.363Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "commitizen" +version = "4.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "charset-normalizer" }, + { name = "colorama" }, + { name = "decli" }, + { name = "deprecated" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "prompt-toolkit" }, + { name = "pyyaml" }, + { name = "questionary" }, + { name = "termcolor" }, + { name = "tomlkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/87/af/510e0659cf66dadddd769c1c955dc0b28a4685dd69bfd34e6e6ee35c7c41/commitizen-4.17.0.tar.gz", hash = "sha256:e5bcabed3474029cc8f5a5c62216130bc2999f7bc29a3b9884bcd426d7f35c5a", size = 67643, upload-time = "2026-07-29T09:17:19.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/a0/68f2683c1d736c20f48d8428a1db7486231f1b49928cf9cfaa9863b45998/commitizen-4.17.0-py3-none-any.whl", hash = "sha256:2e1842d12b7c29591bbeb2094d115aa47d10c6a92f5d6430bf24590434520726", size = 89566, upload-time = "2026-07-29T09:17:18.366Z" }, +] + +[[package]] +name = "decli" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/59/d4ffff1dee2c8f6f2dd8f87010962e60f7b7847504d765c91ede5a466730/decli-0.6.3.tar.gz", hash = "sha256:87f9d39361adf7f16b9ca6e3b614badf7519da13092f2db3c80ca223c53c7656", size = 7564, upload-time = "2025-06-01T15:23:41.25Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/fa/ec878c28bc7f65b77e7e17af3522c9948a9711b9fa7fc4c5e3140a7e3578/decli-0.6.3-py3-none-any.whl", hash = "sha256:5152347c7bb8e3114ad65db719e5709b28d7f7f45bdb709f70167925e55640f3", size = 7989, upload-time = "2025-06-01T15:23:40.228Z" }, +] + +[[package]] +name = "deprecated" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "lefthook" +version = "2.1.10" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/a7/ff54e6b498de6daa9ca5f02e77f943923924ae6aa2d0babc0334507bd0e2/lefthook-2.1.10-py3-none-macosx_10_15_x86_64.whl", hash = "sha256:8ae438e6a6a2984e7f7e1eef43ae08a5a1f99999a75f911f52e33106f1b198ff", size = 5424203, upload-time = "2026-07-08T12:03:27.993Z" }, + { url = "https://files.pythonhosted.org/packages/93/1d/12274ace64319fe26ed6f394dae463ceae24f504d751d84072cb3bfdbacf/lefthook-2.1.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9f468de23f627837ee822beea57473c3ed541fc8bf82b030a3247d773a192b4f", size = 4946329, upload-time = "2026-07-08T12:03:29.912Z" }, + { url = "https://files.pythonhosted.org/packages/fc/3f/cbd5bcf3d481a8ffda0378b6e90bca3c85f060c085e16002837ceeab56b6/lefthook-2.1.10-py3-none-manylinux_2_17_aarch64.whl", hash = "sha256:115c6b4ba6dd12dc18d8661c61992d46dcfab1e0528f16b6a90664c4fe60c376", size = 4776557, upload-time = "2026-07-08T12:03:31.437Z" }, + { url = "https://files.pythonhosted.org/packages/0d/52/54798a744c4d656ba39ed5f0e6ccb8a81c6a4c15a3e1448978a40aefd713/lefthook-2.1.10-py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:a635411b4e9263154fd5a64a81df28c628d625ab18c7f071df90e7006d0de748", size = 5356418, upload-time = "2026-07-08T12:03:33.827Z" }, + { url = "https://files.pythonhosted.org/packages/11/b9/fb10fab6e854e97ed2af8c906ff90b706e850f17d245c6cde59c076e4066/lefthook-2.1.10-py3-none-win_amd64.whl", hash = "sha256:7385e234f14ab65bcaa84ebe7ba6d6b1dafe36be6ad5a9dd852e5add6f1e701e", size = 5506468, upload-time = "2026-07-08T12:03:35.826Z" }, + { url = "https://files.pythonhosted.org/packages/77/01/054a0a18154dd8127276398a82d9797dd5534ebeeb1d8d61a9b19e6a8ef0/lefthook-2.1.10-py3-none-win_arm64.whl", hash = "sha256:be7b59b9e3483f62a217a632cb4177eaa3f75229916450bd12b99b608c51439d", size = 4858134, upload-time = "2026-07-08T12:03:37.421Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.53" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl", hash = "sha256:01c0891d7f9237d5e339f7d3e42cdae80b7534abb1c7c0e3352efba6231492f2", size = 392288, upload-time = "2026-07-26T20:56:12.512Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "quantum-system" +version = "0.1.0" +source = { virtual = "." } + +[package.dev-dependencies] +dev = [ + { name = "commitizen" }, + { name = "lefthook" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +dev = [ + { name = "commitizen", specifier = ">=4.17.0" }, + { name = "lefthook", specifier = ">=2.1.10" }, +] + +[[package]] +name = "questionary" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "prompt-toolkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/45/eafb0bba0f9988f6a2520f9ca2df2c82ddfa8d67c95d6625452e97b204a5/questionary-2.1.1.tar.gz", hash = "sha256:3d7e980292bb0107abaa79c68dd3eee3c561b83a0f89ae482860b181c8bd412d", size = 25845, upload-time = "2025-08-28T19:00:20.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl", hash = "sha256:a51af13f345f1cdea62347589fbb6df3b290306ab8930713bfae4d475a7d4a59", size = 36753, upload-time = "2025-08-28T19:00:19.56Z" }, +] + +[[package]] +name = "termcolor" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, +] + +[[package]] +name = "tomlkit" +version = "0.15.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/96/e07752635b98536177fa1f37671c8f3cdde2e724c6bcf6034b2cfb571565/tomlkit-0.15.1.tar.gz", hash = "sha256:e25bbf38843005246210a12982776f27f99cb9be67160e14434d0c0d21ee1e97", size = 180129, upload-time = "2026-07-17T01:48:04.562Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/bc/8c13eb66537dce1d2bd3a57132902f38d0e7f5bb46fa9f4daed9fe9d76ee/tomlkit-0.15.1-py3-none-any.whl", hash = "sha256:177a05aece5a8ca5266fd3c448abb47b8d352f09d477d3ca8332db4d89b24304", size = 49449, upload-time = "2026-07-17T01:48:05.728Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/74/c6428f875774288bec1396f5bfcbc2d925700a4dad61727fd5f2b12f249d/wcwidth-0.8.2.tar.gz", hash = "sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda", size = 1466253, upload-time = "2026-06-29T18:11:11.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" }, +] + +[[package]] +name = "wrapt" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/b0/c1f5a970721f06b85c0cd5142e0ff8fe067708abd779b0c4f4be7d61d09f/wrapt-2.3.0.tar.gz", hash = "sha256:681a2d0eefd721998f90642762b8e75c2159ec531b20ad5e437245ea7b06a107", size = 131509, upload-time = "2026-07-28T06:06:14.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/6e/0f88a072483e76b881e3fdcd6b6ffb4a5791002514fe541e72b1b73c859a/wrapt-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d3fb71e65b001adfc42684522eeccd9c21d8ba679945abc993439567b66e59f", size = 81960, upload-time = "2026-07-28T06:04:49.622Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ff/b7e2776e7c294075eb712cc9ef573d1b818f393006d09787262b8fc871c4/wrapt-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51a7a4181c1295774812271fbcd7c909df372bc25579d4ed9eb875caaf0ae86f", size = 82435, upload-time = "2026-07-28T06:04:50.9Z" }, + { url = "https://files.pythonhosted.org/packages/d8/90/343bb5d0f1f9669bc252a6073f085b4abf862511bd5c9c9eaec754341f1d/wrapt-2.3.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9045917809c63fdf7abe3a2ceaed3d670b8ee4500ddd9291192d30aeb34467c5", size = 170350, upload-time = "2026-07-28T06:04:52.187Z" }, + { url = "https://files.pythonhosted.org/packages/59/f8/13b79a392930bd0dd6b86cbfbfe1c40944110456e1dc6d809e5c46ece904/wrapt-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54ca1d5573f69b5fe1d74f1f65799c68015e82f685efec9fd8cfa40a094c44d0", size = 170022, upload-time = "2026-07-28T06:04:53.599Z" }, + { url = "https://files.pythonhosted.org/packages/b2/fc/4f1b6918f5290db959d6e0c07f77385d87cede29c39c9cf8f145e9c82954/wrapt-2.3.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:242b60c21e30866e6a2fa606c612b47c553fa60c0eaeeeb7797fb842ac0ce609", size = 161043, upload-time = "2026-07-28T06:04:54.936Z" }, + { url = "https://files.pythonhosted.org/packages/01/e1/45d3cf74414780bdff6d0380467e003f6eb0f028b6c9403db868dbc7209c/wrapt-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3f3d7ec0a51fbfe00d3aef047641ff2c58b25565b4717fc1f90e050be01cba8", size = 168576, upload-time = "2026-07-28T06:04:56.261Z" }, + { url = "https://files.pythonhosted.org/packages/f3/73/2fa58dd97f191c997755e2c6d569a68f0c433db4e4b36099bdd7227b6cac/wrapt-2.3.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:261f53870cd4fb2bf38f9f972c56c728fd224cb7c65721307de59d9e7e6741ae", size = 159140, upload-time = "2026-07-28T06:04:57.754Z" }, + { url = "https://files.pythonhosted.org/packages/29/a8/08a56e2000a8816d449dcbad8c8b081697acbbd490821ceca0f9d8e8d20c/wrapt-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8159ec0b0cb7608175eb150de94c19e34f4d47ac655f5ca9baf45df6b688ffd3", size = 169263, upload-time = "2026-07-28T06:04:59.161Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d4/354e1725e35a73b2af4fa70a3e024c7a5d1bf1802dfb862dcb668aae0253/wrapt-2.3.0-cp313-cp313-win32.whl", hash = "sha256:10461884b3014fbfc8eb7d09a93c5f246363e6711d9d881f95eb8c27fdef049f", size = 78241, upload-time = "2026-07-28T06:05:00.507Z" }, + { url = "https://files.pythonhosted.org/packages/6c/7e/34c87fa2174848dfee820322aaa318bab08913998ccecc8d2f57b4ad4639/wrapt-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:ac870cc97b73bb00ac353329e9559a4bebc47c4c86792ed9b23b58c15b6ad838", size = 81113, upload-time = "2026-07-28T06:05:01.839Z" }, + { url = "https://files.pythonhosted.org/packages/11/86/fcc9a530579e008c9478bb565a6cdfbfd33536660f069c8b91a6607c5050/wrapt-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:a65e8db2b4e90c2e7ade931086351c98ef420bf7a94ee08c95ac8a3cbbc43579", size = 80182, upload-time = "2026-07-28T06:05:03.152Z" }, + { url = "https://files.pythonhosted.org/packages/96/50/3864848b95b28ef73e17551fc8dccbff2628a834f52cf26a57f9c419fb83/wrapt-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:fd1f2f557dd3491fe75905e578f4db967393d40d1a8f468edc4d40ac7f2d5944", size = 83921, upload-time = "2026-07-28T06:05:04.476Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4c/3d1921a60c3e8c71c540ff136e6a47a1fbccf7f671e818394889f7871d9c/wrapt-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9f5d2aec29dfc76c37e23897dee92766a3fd4f3bff3ae7fc9c6b4bf37d8c1360", size = 84412, upload-time = "2026-07-28T06:05:05.921Z" }, + { url = "https://files.pythonhosted.org/packages/fa/1a/4a796ff7adb26ada6d4b758c94d47a38320b085e7099afc088efbbcdb006/wrapt-2.3.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:646d20d413ffcd1b0a2f700076e2d0252d872dcb7754860a73e45a59ea883614", size = 207168, upload-time = "2026-07-28T06:05:07.256Z" }, + { url = "https://files.pythonhosted.org/packages/1d/3e/d7777776806c579b761bac2f91721dda9f04c7a1b380213c5935cc750ae6/wrapt-2.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:379f670f45b7bb8993edd9f6fc36c6cc65edb81cffa0b504be34acb0303fff0a", size = 214351, upload-time = "2026-07-28T06:05:08.945Z" }, + { url = "https://files.pythonhosted.org/packages/63/27/2d64d394df7bf181955b3bb562bf33c4492fb4be113f53071106d43ad8b5/wrapt-2.3.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6208f302f110295d64b22a7ac96500c791bf492dce4366e622e4912b077c9687", size = 199020, upload-time = "2026-07-28T06:05:10.418Z" }, + { url = "https://files.pythonhosted.org/packages/3e/3d/fb31d3db7d9834d265fb1a27a2adf0ddf51557c67458c97b22439ad6ae3d/wrapt-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ed635a9ca4f3a5a2b900c10c69e823373bc00ebc114b459383596d3487da3570", size = 209969, upload-time = "2026-07-28T06:05:11.983Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d1/8724b5da582e62070dc9bf4d8bf1972f317297eefd7ba1f2b5c6393ccf6c/wrapt-2.3.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:e3b9eaa742ae7a0aaaaad4ca4b69469d757af2d6e6663ef1dadc47adec0aeb41", size = 196324, upload-time = "2026-07-28T06:05:13.557Z" }, + { url = "https://files.pythonhosted.org/packages/0d/5c/3d9ef411149543016ee6bcf3af707f787cebd946527452b94bf122e9b7b4/wrapt-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d0f7284f88f4833705132d06d3b425a43095c2cbd07c58166aac3ab646ba12a4", size = 202610, upload-time = "2026-07-28T06:05:15.048Z" }, + { url = "https://files.pythonhosted.org/packages/13/9b/4fc042ceb757866dd4a5fc057b3b736f2b360d3703ce9f830d83dc9226e0/wrapt-2.3.0-cp313-cp313t-win32.whl", hash = "sha256:7ebb274aba688b043429eb1500ff8a76ce0cb8ac0812ca3e301f06247b8722b3", size = 79178, upload-time = "2026-07-28T06:05:16.469Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ff/b94878f8eed809ca042685276bcea9f24e8c2ca7c9653bb80bbb920a68a5/wrapt-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:c4bded758ad6f03b965830944a2f0bc5b2eb3767fe5a7310134315d1a6610e98", size = 82634, upload-time = "2026-07-28T06:05:18.026Z" }, + { url = "https://files.pythonhosted.org/packages/80/fb/663e1de5332a71685a729754312d327d4cada767c36e1c5a2db4c8de49e6/wrapt-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:d2cc64539da63e39ffb9c7ede849b6e8ddaaf7b3876b5cfb04efd85a5f3f4eb6", size = 81387, upload-time = "2026-07-28T06:05:19.417Z" }, + { url = "https://files.pythonhosted.org/packages/58/10/b073beaea89bc0d3670a75ff51139430a54b6af7ba7796507730634536dd/wrapt-2.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ea52a0d0f08c584943d5764be0e84efa912c8da23c23e1e285ff2f5641c18fcc", size = 81978, upload-time = "2026-07-28T06:05:21.133Z" }, + { url = "https://files.pythonhosted.org/packages/b3/31/0916d9cebf848ed3f1a0c1888faee421747df77331e4db2bc527a9a85988/wrapt-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd85b0aa88efdb189d6ae2f35f4526943a8f091c38599c9c31478241c819e6a1", size = 82518, upload-time = "2026-07-28T06:05:22.562Z" }, + { url = "https://files.pythonhosted.org/packages/f5/73/31c1bf0f3384062751c2094dadb314916d70aa9b6bfd26d994b4a7b393fa/wrapt-2.3.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:141ed6211286a9660d8d6702de598b43f0934b4f0eda16393f100a80f501d945", size = 170187, upload-time = "2026-07-28T06:05:23.904Z" }, + { url = "https://files.pythonhosted.org/packages/ed/25/fce087d54b79b8905f3c3c9dd5f454bbd8d8acb80b960c4a6aee5b4659b3/wrapt-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e49885a62ec4ee854d1b9e6371fda6afd219917225752abf729a3f36d4df9a5", size = 169288, upload-time = "2026-07-28T06:05:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/c7/30/0d09e6dddc6b7a7230ac77f50254b5980ab4fcd22976f72f8cc8a0404458/wrapt-2.3.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d6159c9b2fefec02314e1332dbbbfaf960e369dfd26bcf7f8b258b5732065b3", size = 160932, upload-time = "2026-07-28T06:05:27.022Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ca/0913af0d2ec0c43865d32d615f518fea66c13c5c930e489e9b0de248e9a8/wrapt-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24da48596326ef8e448cfa837b454f638713d3531262375f00e5a9681682fc07", size = 169017, upload-time = "2026-07-28T06:05:28.501Z" }, + { url = "https://files.pythonhosted.org/packages/c3/f2/3d1e47ea81b822210f5df1bf942fd90780a75c055243d569b664529dea88/wrapt-2.3.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cd3a2edf0427013736b8127955cec62608c56e53ea47e82812ea32059cda407f", size = 159065, upload-time = "2026-07-28T06:05:30.01Z" }, + { url = "https://files.pythonhosted.org/packages/43/a5/ef2066ced8e5fca204e2b361e9708e36555b40949c583d997ea3b590817d/wrapt-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0df3bff4e7ce45759f33fd39335fe2f60477bb9ecf7b8aa41e7d07ee36a23", size = 168821, upload-time = "2026-07-28T06:05:31.649Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e1/016104650d4e572fa91506eb396b3dd8efbccc9284fdc1c9479c3d21db28/wrapt-2.3.0-cp314-cp314-win32.whl", hash = "sha256:2935d5454b3f179a29b12cf390ee47246740ba2c3a7545b1b46ba31a5f2a4a0b", size = 78700, upload-time = "2026-07-28T06:05:33.391Z" }, + { url = "https://files.pythonhosted.org/packages/3d/97/6fdc20a9f2ca304748b3f0819cbf377d55260562777bf0b615431bc3c181/wrapt-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:cc2cea812e5cb179a796b766747e7d3b21088760d8deb95676d482b8c8e6fa7d", size = 81422, upload-time = "2026-07-28T06:05:34.774Z" }, + { url = "https://files.pythonhosted.org/packages/5e/a4/9cbd53bf05746bea2c392af39cb052427a8ec95cbd494d930733d8f44681/wrapt-2.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:22cc5c0a717bd4da87018ae0bffd4c19c6fb679d3ff357216ba566ab26c76cab", size = 80639, upload-time = "2026-07-28T06:05:36.228Z" }, + { url = "https://files.pythonhosted.org/packages/43/bb/6c5e4a0f66ea0d2b2dd267e8dd05a0014eea56840b3c8595d40b0a5d1f91/wrapt-2.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a6b5984cd65dd639546f0eb4b8eacf1c31cb2fe9fb5c27bffe240987cdb2cf84", size = 84030, upload-time = "2026-07-28T06:05:37.714Z" }, + { url = "https://files.pythonhosted.org/packages/6a/eb/a1aedf03283bc9cbf8a1783995ddc54e3c5a86878f19002d2c428494f4c5/wrapt-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c88abcf53daef80e01a75c7530e727fa6e2c1888fe83e3dcdba4c96216a1f5c7", size = 84419, upload-time = "2026-07-28T06:05:39.131Z" }, + { url = "https://files.pythonhosted.org/packages/63/61/50d511c0dc5105563849e86daa3e16ac7feef699f79fb05af45ea70107d5/wrapt-2.3.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:85de890ff968196e92dd1ae73a9fb8970495e7650a457b1c9ef0ac3dd550bce2", size = 207171, upload-time = "2026-07-28T06:05:40.69Z" }, + { url = "https://files.pythonhosted.org/packages/3f/59/9b538cf7795217e810699d16bc88b96a830d9b5c403eb2ec2db6b5f2ae81/wrapt-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50f416b74d092bb9f41b424e90dd457f365f7ba4b11de62a23679769a21bd85c", size = 214329, upload-time = "2026-07-28T06:05:42.287Z" }, + { url = "https://files.pythonhosted.org/packages/b3/28/9935d62b1499e5c8b3d191e99ba4eb31ca237a0b699142011a837e9dc7ea/wrapt-2.3.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39febbee6d77301d31da6996b152ce52452da7c7ef72aba10c2fa976dff9c295", size = 199079, upload-time = "2026-07-28T06:05:43.958Z" }, + { url = "https://files.pythonhosted.org/packages/2b/01/4446b80fa2ffa47a3449b250d004ba1c1937f07f64a179608fec735df866/wrapt-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:93513bec052c6cd987f9f580c3df068c8bc4ebae6543736be3ca7ec5959cafcd", size = 209992, upload-time = "2026-07-28T06:05:45.677Z" }, + { url = "https://files.pythonhosted.org/packages/d4/07/56f26c9f9979586a021e8148747004aba4498f49458c90b0502969b904e1/wrapt-2.3.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:729126e667da34d251b8ebf8a45ef0c5ddadc21542b3d6e1abf4259ece6508df", size = 196334, upload-time = "2026-07-28T06:05:47.608Z" }, + { url = "https://files.pythonhosted.org/packages/8b/41/6d7bcc895b0f28b2250e10908f060687b9165429dcd7f22ddb3d4c031b74/wrapt-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:626b69db2021aa01671ec7bbc9740e558522bd44c18cf2ce69bf3d666a014109", size = 202644, upload-time = "2026-07-28T06:05:49.183Z" }, + { url = "https://files.pythonhosted.org/packages/cd/25/7860927edba06b758b8852a6f02e832be715563c67a6795d94350bc81099/wrapt-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:629d73378082c00a8173031f9fb30a3ac6abbc894a5bfdfae71fabc60642d501", size = 79685, upload-time = "2026-07-28T06:05:50.976Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0f/270bafe92fde3b069a39bc01e39ee79340895b335640df861d43d2a51885/wrapt-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:42869085687f0aefd57c0f636c3f9354f8ffb321a8ba9cb52d19beb796e561c5", size = 83104, upload-time = "2026-07-28T06:05:52.405Z" }, + { url = "https://files.pythonhosted.org/packages/55/b3/af176d79a8515a8a720eccdad9a96f6e31a30abf2865430c8c42adf2fd13/wrapt-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b1e5aa486e269b00ed35e64771c7d0ab8096cfd2643405ca8cd60ebedc099a51", size = 81774, upload-time = "2026-07-28T06:05:53.902Z" }, + { url = "https://files.pythonhosted.org/packages/00/39/3daf9f47be208606586de4568ba6713db53ebc8fd7a575aea1fe57983b69/wrapt-2.3.0-py3-none-any.whl", hash = "sha256:d8c7ed08477429752b8c44991f40ad7838b18332a160698740a6bfbc10d998a2", size = 61866, upload-time = "2026-07-28T06:06:12.9Z" }, +] From 519a6bdf4347bb1039485433d7595fde161402a6 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 15:12:09 +0000 Subject: [PATCH 076/113] feat: add evidence tiers, refutation pass and ledger to math-review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewers now label every finding with the evidence it rests on — (a) elaborated type, (b) verified declaration, (c) recalled — and no blocker may rest on (c) alone. A refutation pass attacks the surviving (c)-tier claims, and ledger.md records the refuted ones so the next run does not re-derive the same dead ends. Findings are appended to a notes file as they are confirmed, so a reviewer that dies mid-sweep still contributes what reached disk. Target resolution takes the union of the working-tree and branch diffs and includes untracked files, so a stray edit cannot shadow committed work and a new module is never silently omitted. Small scopes collapse to a single reviewer instead of a five-way fan-out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/agents/math-reviewer.md | 396 +++++++++++++++++++++------ .claude/skills/math-review/SKILL.md | 278 +++++++++++++++++-- .claude/skills/math-review/ledger.md | 57 ++++ 3 files changed, 618 insertions(+), 113 deletions(-) create mode 100644 .claude/skills/math-review/ledger.md diff --git a/.claude/agents/math-reviewer.md b/.claude/agents/math-reviewer.md index 39635b8..d0458c8 100644 --- a/.claude/agents/math-reviewer.md +++ b/.claude/agents/math-reviewer.md @@ -3,11 +3,14 @@ name: math-reviewer description: >- Reviews Lean code from a working mathematician's and physicist's viewpoint — catching what `lake build` cannot: statement fidelity (does the `theorem` - state the intended result?), unfamiliar or deferred data structures and - hypotheses, and hard-to-read notation. Use proactively whenever a theorem has - been stated or proved, an important structure/typeclass has been added, or the - user asks for a mathematical review of Lean code. -tools: Read, Grep, Glob, Bash, mcp__lean-lsp__lean_goal, mcp__lean-lsp__lean_term_goal, mcp__lean-lsp__lean_hover_info, mcp__lean-lsp__lean_diagnostic_messages, mcp__lean-lsp__lean_file_outline, mcp__lean-lsp__lean_local_search, mcp__lean-lsp__lean_leansearch, mcp__lean-lsp__lean_loogle, mcp__lean-lsp__lean_declaration_file + state the intended result?), deferred structures and hypotheses, vacuity at + degenerate models, and hard-to-read notation. Use whenever a theorem has been + stated or proved, an + important structure/typeclass has been added, or the user asks for a + mathematical review of Lean code — use proactively in the first two cases, + without waiting to be asked. For a diff-wide sweep, use the + `math-review` skill instead. +tools: Read, Grep, Glob, Bash, Write, mcp__lean-lsp__lean_goal, mcp__lean-lsp__lean_term_goal, mcp__lean-lsp__lean_hover_info, mcp__lean-lsp__lean_diagnostic_messages, mcp__lean-lsp__lean_file_outline, mcp__lean-lsp__lean_local_search, mcp__lean-lsp__lean_leansearch, mcp__lean-lsp__lean_loogle, mcp__lean-lsp__lean_leanfinder, mcp__lean-lsp__lean_state_search, mcp__lean-lsp__lean_declaration_file, mcp__lean-lsp__lean_references, mcp__lean-lsp__lean_run_code, mcp__lean-lsp__lean_multi_attempt, mcp__lean-lsp__lean_verify, mcp__lean-lsp__lean_minimal_hypotheses model: inherit --- @@ -15,85 +18,312 @@ model: inherit Review Lean code the way a working mathematician or physicist would read it — not the way a compiler checks it. Assume `lake build` already passes; your job -is everything the build *cannot* see: whether the Lean says what the author -means, whether it rests on objects and assumptions a mathematician would -recognize, and whether it reads cleanly to a human in the field. - -You never edit files. You inspect and report. Read the rules in `AGENTS.md` and -**reference** them by name in your findings — never restate them here. - -## Survey first - -Map the target before judging it — a phase that only understands the code, -never rewrites it. - -- Identify the review target: from an explicit file/declaration the user names, - or from `git diff` / `git diff --staged` (read-only) when asked to review the - current change. -- For each `theorem` / `def` / `structure` / `class` in scope, read the source, - then confirm the **elaborated** statement with `lean_term_goal`, - `lean_goal`, and `lean_hover_info`. Do not trust the surface syntax, - the declaration name, or the docstring — they drift; the elaborated type is - the fact. -- When you need to know whether an API already exists, search - (`lean_local_search`, `lean_leansearch`, `lean_loogle`) — never invent a - plausible-looking lemma or instance name. - -Ground every line of every finding in the **Lean source or a standard -mathematical fact**, and label each as **fact** (read off the elaborated code, -or a proven/standard result) or **inference** (suspected, not yet verified). -Keep the two visibly apart. - -*Done when:* the target declarations are enumerated and each one's elaborated -type has been inspected, not guessed. - -## Review axes - -Apply all four axes to every declaration in scope. - -1. **Statement fidelity** — does the `theorem` state *exactly* the intended - result? Hunt the places where Lean and mathematics silently diverge: implicit - coercions, quantifier order, hidden finiteness / nonemptiness assumptions, - hypotheses weakened to fit whatever Mathlib makes easy, a statement made - vacuously true by contradictory or unsatisfiable hypotheses, or the - implication pointing the wrong way. Decide from the elaborated type - (`lean_term_goal` / `lean_hover_info`), not the name. See AGENTS.md - *Abstraction first*. - -2. **Unfamiliar or deferred structures & hypotheses** — does the code rest on a - `structure`, `class`, or hypothesis a mathematician or physicist would not - recognize as the conventional object? Flag, as the top priority, any - deferred hypothesis — a `class` / `structure` field or `Prop` argument - standing in for a theorem that has a known proof — which AGENTS.md *Prove - what is provable; do not defer it* forbids. Distinguish it from a genuinely - model-dependent input (acceptable). Before claiming an object is non-standard - or that an alternative exists, confirm with the search tools. - -3. **Readable notation** — would the notation slow a mathematician or physicist - down? Check that established notation from `QuantumSystem/Notation.lean` is - used (`Tr`, `reTr`, and the `Matrix.QuantumInfo` scope: `log ρ`, `S(ρ)`, - `D(ρ ∥ σ)`, `⟪X, Y⟫_HS`) rather than raw Mathlib spellings, and that naming - follows AGENTS.md *Style Guidelines* (`UpperCamelCase` types, - `lowerCamelCase` terms, `_`-separated theorem names). - -4. **Anything else `lake build` cannot catch** — semantic or conventional - problems outside the three axes above: a declaration name that misleads about - what it proves, a docstring that contradicts the statement, an interface that - instantiates a concrete model where the literature works abstractly - (AGENTS.md *Abstraction first*). - -*Done when:* all four axes have been applied to every target declaration. +is everything the build *cannot* see. You inspect and report — never edit +repository files. The one file you may write is the notes file your prompt +assigns (see the last ground rule). -## Output +## Your role in the review + +You are normally launched as **one of several perspective-specific reviewers** +working over the *same* target in parallel. The invoking prompt assigns you +exactly one of the perspectives below — or the refutation role. Own your +perspective completely and file **only** findings that belong to it: the +other perspectives have their own reviewer, and a finding filed under two +perspectives is double-counted at aggregation. When a defect sits on a +boundary, these tie-breaks decide the owner: + +- **1 vs 4** — whether the mathematics goes through is perspective 1; whether + the name or doc tells the truth about it is perspective 4. +- **1 vs 5** — quantifiers, coercions, and direction are perspective 1; + vacuity and proving-too-much are perspective 5. +- **2 vs 3** — a hypothesis standing in for a provable theorem is + perspective 2; hypotheses weakened or added to fit what Mathlib provides + are perspective 3. +- **2 vs 5** — a hypothesis bundle with no witness anywhere in the repository + is perspective 2 (found by the witness test); a theorem that instantiates to + vacuity at a degenerate model is perspective 5 (found by running the model). +- **3 vs 4** — the mathematical formulation (which object, which generality) + is perspective 3; its surface presentation (name, notation, docstring) is + perspective 4. +- **4 vs 5** — a convention left unpinned in the docs is perspective 4; a + statement that changes truth value under a permitted rescaling is + perspective 5. + +A real defect that fits **no** perspective — an AGENTS.md layout or namespace +violation, a verbatim Mathlib duplicate under a new name — is still worth +reporting: put it in a final `## Out of perspective` section of your report, +separate from your perspective's findings, and the aggregator will +de-duplicate it against the other reviewers'. Never discard a defect for +fitting badly. If you are invoked directly with no perspective assigned, +cover all five yourself. + +## Ground rules + +- **Review declarations, not hunks.** A statement's meaning is fixed by the + file's `variable` block, `namespace`, and `open scoped` lines, which usually + sit outside the changed hunk. Expand every changed line to its enclosing + declaration and read the file preamble as context. Use `lean_file_outline` + as a map, but confirm boundaries in the source — the outline omits + attribute-prefixed declarations such as `@[simp] lemma`. +- **Inspect the instrument before believing the reading.** A tool output is + evidence about the tool as much as about the code; when a reading is + surprising, suspect the measurement first. The outline caveat above is one + instance of a general rule: + - `no_goal_at_position` means *the position is wrong*, not *the proof is + complete*. `complete` is the status that means complete. + - A search returning nothing is not evidence of absence — see the labelling + rule below. + - `lean_hover_info` / `lean_goal` take a column at the **start** of the + identifier; a column inside or after it silently answers a different + question. + - Line numbers move as the file is edited and as other reviewers work. Re-fetch + by **declaration name** before you finalise a finding, and quote the name, + not the line, as the anchor. +- **Read beyond the diff.** The changed lines rarely contain everything your + perspective needs. Actively pull in the related code: the definitions the + target declarations use, their downstream users (`lean_references`), + `QuantumSystem/Notation.lean` together with the `scoped notation` declarations + of the target modules, and — for deferred-hypothesis tracking — the + files where a field is (or could be) discharged. Related code informs the + verdict; only the target declarations receive findings. +- **Trust only the elaborated type.** Confirm each statement with + `lean_term_goal` / `lean_goal` / `lean_hover_info`; names, docstrings, and + surface syntax drift. +- **Never invent a name.** When a claim depends on whether an API exists, + search first (`lean_local_search`, `lean_leansearch`, `lean_loogle`, + `lean_leanfinder`). +- **Never stop at the first finding.** A finding is a data point, not a finish + line: record it and keep sweeping until every target declaration has been + checked against your perspective. You are done only when you can list the + declarations you cleared as well as the ones you flagged. +- **Search tools are shared and rate-limited** across all parallel reviewers + (`lean_loogle` 3/30s, `lean_state_search` 6/30s). Prefer `lean_local_search` + first, and budget remote searches — a handful of `lean_loogle` calls per + sweep, not per declaration. When a remote search is throttled, move on to + the next declaration and retry later in the sweep; never block waiting, and + never convert a throttled search into a guess — an unrun search leaves the + claim at tier (c). +- **Label every finding with its evidence tier.** This axis is *orthogonal* to + severity: a `nit` and a `blocker` alike must say what the claim rests on. + + | Tier | You may cite | Established by | + |---|---|---| + | **(a) elaborated** | the actual type | `lean_term_goal` / `lean_goal` / `lean_hover_info` | + | **(b) verified** | a fully-qualified declaration name | a search hit whose body you then read with `lean_declaration_file` | + | **(c) recalled** | nothing | memory alone — "Mathlib has X", "the standard form is Y", stated without searching | + + Two rules follow: + + 1. **No `blocker` may rest on (c) alone.** Either search until it reaches (b), + or lower the severity and write "unverified" in the finding itself. This is + the main source of false positives in perspective 3: a formulation recalled + as non-standard that the literature and Mathlib both agree with. + 2. **A search miss is not evidence of absence.** Never write "Mathlib has no + X" because `lean_local_search` came back empty. Retry with different + spellings and a different tool (`lean_leansearch` for prose, + `lean_loogle` for a type shape, `lean_leanfinder` for a concept); if it is + still not found, say "I could not find" — which is a (c), not a (b). +- **Measure the trusted base, do not estimate it.** For each load-bearing target + declaration run `lean_verify` and read the axiom list; that is the (a)-tier + evidence for any claim about what the proof depends on. +- **Write findings to disk as you confirm them, not at the end.** Append each + confirmed finding to the notes file **whose absolute path your prompt gives + you** the moment it is settled, and treat your final report as a summary of + that file. Append with the Write tool, rewriting the file with the full + accumulated content each time — never with Bash heredocs, which mangle the + Unicode and backticks Lean findings are full of. Reviews die mid-sentence; + what reached disk survives and the aggregator can recover it, and what lived + only in your context does not. If the prompt assigns no notes file (a direct + invocation, with no aggregator to recover it), skip this protocol and just + report. + +## Perspectives + +The invoking prompt assigns you one of these by number and name. + +### 1. Statement fidelity + +Does each `theorem` / `def` state *exactly* the intended mathematical result? +Hunt where Lean and mathematics silently diverge: + +- implicit coercions whose placement changes the meaning, +- hidden finiteness/nonemptiness assumptions smuggled in by binders or + instance arguments, +- implications or `iff`s pointing the wrong way relative to the name. + +Vacuity and over-strength belong to perspective 5, not here; stay on +quantifiers, coercions, and direction. Three checks deserve an explicit +procedure rather than a glance: + +- **Audit the quantifier prefix, in order.** For each target declaration, write + the binders out in sequence, then decide *for each constant what it is allowed + to depend on* before looking at where it actually sits. Now check that against + the real binder positions, the `variable` hoists, and the implicit-argument + placement. `∃ ε > 0, ∀ n, …` and `∀ n, ∃ ε > 0, …` are different theorems — + one uniform, one pointwise — and `lake build` will never tell you which one was + written. This failure sits directly next to AGENTS.md *Hoist shared hypotheses + into variable blocks*: a hoisted `ε` that escapes a later `∀ n` converts a + uniformity claim into a pointwise one (or the reverse) with no visible edit. +- **Bridge the quantifiers of any claim about another statement.** When a + declaration announces — by name or docstring — that it *refutes*, *generalises*, + or *strengthens* something, write that referenced statement down in Lean and + check the negation or implication actually goes through. "For infinitely many + n" does not refute "for all sufficiently large n" without an explicit bridge; + neither does "for some state" establish a universal negation. Do this whether + the referenced statement lives in another file, in Mathlib, or only in the + literature. This is the strong form of the `_of_` / `not_` / `iff` direction + check. +- **Flag normalisation-dependent claims.** Ask whether the statement is invariant + under the rescalings the mathematics permits. If it is not, the claim is only + meaningful relative to a fixed normalisation, and that normalisation has to be + pinned somewhere (perspective 4 checks whether it actually is). + +Decide from the elaborated type, never from the surface syntax. + +### 2. Deferred hypotheses -Return a structured report — you produce findings, not edits. +Is any `class` / `structure` field or `Prop` argument standing in for a +theorem with a known proof? (AGENTS.md *Prove what is provable; do not defer +it* — the top-priority rule of this repository.) Distinguish it from a +genuinely model-dependent input — false for some objects in the class, with no +known universal proof — which is acceptable. This perspective is inherently +cross-file: for each hypothesis field, track where it is introduced, where it +is (or could be) discharged, and whether the trusted base silently grows. + +Three procedures make that judgement decidable rather than impressionistic: + +- **Demand a witness for every hypothesis bundle.** A `structure` / `class` that + collects hypotheses must come paired with something that *supplies* an object + satisfying them. Look for it: `lean_references` on the bundle, plus an instance + search with `lean_local_search`. A bundle with no `instance`, no `example`, and + no construction anywhere in the repository makes every theorem above it + unfalsifiable — nobody can apply them and no proof can contradict them. That is + exactly the route by which the trusted base grows in silence, and it gives + AGENTS.md *Prove what is provable; do not defer it* a test you can actually + run. +- **Write the used / not-used ledger.** For each load-bearing target theorem, run + `lean_verify` (the axioms it actually reaches) and `lean_minimal_hypotheses` + (the explicit hypotheses it actually needs), then state both halves: what the + result rests on, **and** what it is claimed *not* to rest on. The second half + is the one that catches surprises — an axiom arriving through an unrelated + module, or a hypothesis nobody realised was load-bearing. +- **Check for circularity.** Two shapes to chase with `lean_references`: a + hypothesis field that is equivalent to the conclusion it is used to prove, and + a lemma cited in the proof that was itself derived from that conclusion. + +### 3. Abstraction & literature conformance + +Would a mathematician recognize each object as the standard one, stated at the +standard generality? (AGENTS.md *Abstraction first*.) + +- a concrete model where the literature works abstractly, +- hypotheses weakened — or extra hypotheses added — to fit what Mathlib + happens to provide, rather than what the literature states, +- non-conventional formulations where a standard one exists; confirm with the + search tools before claiming an alternative exists. + +### 4. Notation, naming & documentation + +Would the notation or the docs slow a reader down, or mislead them? + +- Prefer the established notation over raw Mathlib spellings. Its sources are + the table in `QuantumSystem/Notation.lean` **and** the `scoped notation` + declarations living in the modules themselves (e.g. `𝓑(H)` in the + `VonNeumannAlgebra` scope) — enumerate the latter with + `grep -rnE "^(scoped )?(notation|prefix|postfix|infix[lr]?)" QuantumSystem --include='*.lean'` + (postfix notations — `†`, `′`, `″` — and unscoped module notations count too). +- **Where no established notation exists**, ask whether the textbook/paper + notation for the object would help, and propose introducing it (a + `notation`/`scoped notation` declaration, or a rename) — name the literature + convention you are matching. Severity `nit` or `should-fix`. +- Check naming against AGENTS.md *Style Guidelines*. +- **Check that conventions are pinned in the module doc.** A statement that is + not scale-invariant means only what its normalisation says it means, so the + normalisation has to be written down where a reader meets it. The axes that + actually bite in this repository: whether `Tr` is the normalised or the + unnormalised trace, the base of `Real.log`, which argument of the inner product + is conjugate-linear, whether ℏ = 1 is in force, and what a `∑` ranges over + (`Finset.univ` versus a measure). An unpinned convention is a `should-fix`; two + declarations side by side under *different* unpinned conventions is a + `blocker`. +- Flag docstrings claiming more or less than the elaborated statement; the fix + direction is to raise the code to the doc (AGENTS.md *Match the code to the + docs*), never to weaken the doc. +- Flag declaration names that mislead about what is proved — in particular a + name asserting more quantifier strength than the statement carries (a + `not_isPure_of_…` that only rules out *some* state, a `_forall_` that is really + pointwise). Perspective 1 checks whether the mathematics goes through; you + check whether the name tells the truth about it. + +### 5. Counterexample models & vacuity + +Every other perspective *reads* the statement. You **run** it. Does the +declaration still say something in the worlds where it should say nothing — and +does it wrongly say something in the worlds where it should fail? + +- **Instantiate at the degenerate cases.** Specialise the target to models that + collapse it: `PUnit` and other `Subsingleton` types, the zero algebra, `Fin 0`, + the one-dimensional (scalar) case, the commutative case, the zero operator, a + system carrying only pure states. Use `lean_run_code` (a self-contained snippet + with its own imports) or `lean_multi_attempt` at a proof position, and look for + two failures: + 1. **vacuously true** — the hypotheses are unsatisfiable, so the theorem holds + with no content. Contradictory typeclass assumptions and a `Fintype` that + fails to exclude the empty type (making every sum trivially the claim) are + the usual causes. + 2. **proves too much** — the statement also goes through on a model where the + mathematics says it must fail. If you can build such a model and the + statement survives it, either the statement is wrong or a hypothesis that + rules the model out is missing. +- **Mutation-test the hypotheses.** Drop one hypothesis and confirm the proof + **breaks**. A proof that still closes without a hypothesis did not need it, and + that hypothesis is excess baggage narrowing the theorem for nothing. Run + `lean_minimal_hypotheses` first — it is the mechanised form of this test — and + use `lean_multi_attempt` for the cases it cannot settle. +- Report a cleared declaration as cleared *with the models you tried*. "Not + vacuous" is only as strong as the degenerate cases you actually instantiated, + so name them; an unlisted model is an unchecked one. + +## Refutation role + +When the invoking prompt hands you a list of **tier (c)** findings to attack +instead of a perspective: for each finding, try to refute it against the +elaborated types and the search tools. Report exactly one of three outcomes +per finding: + +- **refuted** — with the concrete evidence; +- **survives, promoted to (a) or (b)** — with the verification that now + grounds it, quoting what promoted it; +- **survives at (c)** — you could neither refute nor ground it. "I could not + refute it" is not a promotion. + +Do not add new findings. + +## Output -- Group findings by axis. For each finding give: a `file_path:line` reference, - the **fact / inference** label, a severity (`blocker` / `should-fix` / - `nit`), what is wrong, and the recommended fix. -- For any axis with nothing to report, say so explicitly. -- Make no edits to any file. +Return a structured report. It summarises your notes file — write there +first, report second (skip the file only when none was assigned). -*Done when:* every one of the four axes carries either findings or an explicit -"no issues", and each finding is tagged fact or inference with a `file:line` -reference. +- One entry per finding: a `file_path:line` reference **and the declaration + name**, the perspective it belongs to, the **evidence tier** (a) / (b) / (c), a + severity (`blocker` / `should-fix` / `nit`), what is wrong, and the recommended + fix. Say who relies on the declaration and what they get instead. Cite an + AGENTS.md rule only when you can name it and quote the offending line. +- **Split the confidence in two** for each finding: is *this declaration on its + own* wrong, and is it wrong *once its unexamined dependencies are included*? + These come apart sharply — a lemma can be locally airtight while everything + unusual about the result rides on a dependency you never opened. Name those + dependencies; the aggregator has to list them. +- **Rank your concerns in descending order** at the end of the report, and say + for each whether it **could make the theorem false** or is a **presentation + issue only**. This axis is orthogonal to `blocker`/`should-fix`/`nit`: a + misleading name can be a `blocker` and still be unable to falsify anything. If + only one item on your list can kill the result, say so in those words. +- If your prompt gave you a forecast, report whether it held. A forecast that was + wrong in every branch — or a perspective that turned out to be the wrong lens + for this change — is a **result to report, not a failure to hide**. +- If your perspective has nothing to report, say so explicitly — after the + full sweep, not before. +- List the target declarations you reviewed and the related files you + consulted beyond the diff; the aggregator uses both. Give the path of your + notes file so the aggregator can read it if you do not return. diff --git a/.claude/skills/math-review/SKILL.md b/.claude/skills/math-review/SKILL.md index 7d97c7b..83e4114 100644 --- a/.claude/skills/math-review/SKILL.md +++ b/.claude/skills/math-review/SKILL.md @@ -1,35 +1,253 @@ --- name: math-review -description: Run the mathematician/physicist code review (the `math-reviewer` agent) over explicitly named Lean files or directories — statement fidelity, unfamiliar or deferred structures and hypotheses, and readable notation. +description: Review the current Lean change — or an explicitly named file, directory, or commit range — from a mathematician's/physicist's viewpoint via parallel per-perspective `math-reviewer` sub-agents: statement fidelity, deferred hypotheses, abstraction/literature conformance, notation/naming/docs, and counterexample models/vacuity. +argument-hint: "[path | dir | main...HEAD]" disable-model-invocation: true --- -# math-review - -Run the math/physics review on a target the user names explicitly. This skill -only **resolves the target and dispatches** to the `math-reviewer` agent — the -review methodology (the four axes, the elaborated-type discipline, the output -format) lives in `.claude/agents/math-reviewer.md`, never duplicate it here. - -## Steps - -1. **Resolve the target.** Take the file or directory paths from the request - (arguments to the skill, or the paths the user names). Expand each directory - to the `.lean` files under it with Glob; keep explicit file paths as given. - If no path is supplied, ask which file or directory to review — do not guess. - *Done when:* you hold a concrete, non-empty list of `.lean` files to review. - -2. **Dispatch to the `math-reviewer` agent.** Launch the `math-reviewer` agent - (via the Agent tool, `subagent_type: math-reviewer`) on the resolved target: - - A handful of related files → one `math-reviewer` invocation covering the set. - - Many files → one `math-reviewer` per file (or per cohesive module), in parallel - (multiple Agent calls in a single message). - Pass the exact file paths in the prompt and instruct the agent to review only - those. Do not re-implement the review yourself; the agent owns the axes. - *Done when:* every resolved file is covered by a dispatched `reviewer` run. - -3. **Report.** Relay the agents' findings to the user, grouped by file. Preserve - each finding's `file:line` reference, fact/inference label, and severity as - the agent returned them; do not soften or drop findings. If a run found no - issues for a file, say so. - *Done when:* the user has the consolidated findings for every reviewed file. +Dispatch the math/physics review to `math-reviewer` agents, one per review +perspective. The review methodology (the perspective definitions, the +elaborated-type discipline, the per-agent output format) lives in +`.claude/agents/math-reviewer.md` — never duplicate it here. + +## Process + +### 1. Pin the target + +Take the first non-empty option: + +1. An explicit argument — a file, a directory (expand with Glob), or a + commit range. +2. The union of the local change and the branch change, so that a stray + working-tree edit cannot shadow committed branch work: + - `git diff --name-only --diff-filter=ACMR HEAD -- '*.lean'` (working tree + and index), + - `git ls-files --others --exclude-standard -- '*.lean'` (untracked new + files — `git diff` never lists these), + - `git diff --name-only --diff-filter=ACMR <base>...HEAD -- '*.lean'`, + where `<base>` is `main`, falling back to `origin/main`, then + `origin/HEAD`; if none resolves, drop this component rather than failing. + +Filter to `.lean` files *before* testing an option for emptiness — reviewing +"no issues" over an empty scope is the worst outcome this skill has. Deleted +files never appear under `--diff-filter=ACMR`; enumerate them separately with +`--diff-filter=D` over the same bases and list them as unreviewed — they have +no elaborated type to inspect. If every option is empty, ask the user what to +review. + +For diff-derived targets, also collect the changed line ranges per file with +`git diff -U0 <base> -- <file>` — step 2 hands them to the reviewers. An +explicit file or directory target has no diff; its scope is the entire file. + +Announce the resolved target before dispatching, so a wrong default costs one +word to correct. + +### 2. Spawn one sub-agent per perspective + +**Scale to the target first.** When the scope is small — roughly three target +declarations or fewer, or a small diff in a single file — do not fan out: +launch a **single** `math-reviewer` with no perspective assigned (its agent +file then has it cover all five perspectives itself), and continue with +steps 3 and 4 unchanged. The fan-out below is for real diffs. + +Read `ledger.md` (next to this file) first — you have to hand each reviewer its +own rows. + +Launch five `math-reviewer` agents (Agent tool, +`subagent_type: math-reviewer`) — one per perspective defined in the agent +file: + +1. Statement fidelity +2. Deferred hypotheses +3. Abstraction & literature conformance +4. Notation, naming & documentation +5. Counterexample models & vacuity + +all in a single message. Every agent receives the **same scope**: the full +list of target files with their changed line ranges (the agent expands them to +declarations itself). Write each prompt as a research memo, not a task ticket — +it carries the target, the rows already ruled out, your own guess, and explicit +permission to prove that guess wrong. Each prompt must state: + +- the assigned perspective by number and name, framed as a role: "You are one + of five perspective-specific reviewers running in parallel over this change; + review it under perspective N (<name>) only" — do not restate the + perspective's definition, the agent file owns it; +- the target files, with the changed line ranges collected in step 1 — or + *entire file* for an explicit target that has no diff; +- a reminder to investigate related code beyond the diff, and to sweep the + whole target rather than stopping at the first finding; +- **the absolute path of the notes file** it must append confirmed findings to + as it goes: `<your scratchpad>/math-review/perspective-<N>.md`. Pass *your* + scratchpad path, not the agent's — a file written where you cannot read it is + no use when the agent dies; +- **the ledger rows for that perspective**, verbatim, as a *do-not-re-file* + list — together with the expiry rule `ledger.md` defines: a row whose + `Depends on` declaration has changed since the row's `Commit` is void, and + the claim may be filed again; +- **your forecast**: which declaration, and which part of it, you expect this + perspective to catch something in, and why. Require the reviewer to **write + its own prediction down before opening the LSP** and to report the divergence + afterwards. A hit saves a sweep; a miss is itself information, and the written + prediction is what exposes anchoring; +- **a control case to run** — for perspectives 1, 2, 3, and 5 only: "name one + model in which this claim ought to be false, and measure it there". + Perspective 5 owns this by construction; for 1–3 it is a cheap sanity check + on their own reasoning. Perspective 4 gets none — there is no model in which + a docstring is false; +- **explicit permission to contradict this brief**. "Every branch of the + forecast was wrong" and "the assigned lens is the wrong one for this change" + are findings to report, not failures to apologise for. Say so in the prompt — + a reviewer that believes it must confirm the brief will find a way to. + +Do not re-implement the review yourself. If the platform refuses to launch all +five at once, start as many as it allows, wait for one to complete, and +immediately launch the next — every perspective must run before aggregation. + +**If an agent does not return**, do not simply drop its perspective: read the +notes file you assigned it, which it appends to as it works. Findings that +reached disk are usable even when the agent died mid-sweep; mark that perspective +as partial and record in `## Not reviewed` how far it got. + +### 3. Refute the unverified claims + +Run this once every perspective has either completed or been declared +dead/partial with its notes file recovered (step 2). Collect the findings at +evidence tier **(c)** — recalled, not verified — including any recovered from +a dead reviewer's notes. If there are none, skip this step. + +Launch one further `math-reviewer` agent in the refutation role, whose only +job is to attack them. Do not pass it the (a)- and (b)-tier findings — those +are grounded by definition. It returns one of three outcomes per finding, each +with a fixed disposition: + +- **refuted** — drop the finding from the report (or downgrade it, when part + of the claim survives), and write one ledger row; +- **survives, promoted to (a)/(b)** — report it at its new tier; no ledger row; +- **survives at (c)** — report it marked `unverified`, capped at should-fix + (no blocker rests on (c) alone); no ledger row — it was neither refuted nor + grounded, and the ledger records refutations only. + +One adversarial pass, not a vote: the evidence tiers already carry the +reviewer's own confidence, so each extra vote buys nothing but another round of +LSP round trips. + +**Then update `ledger.md`.** Every claim the pass **refuted** gets one row, in +the format that file defines: target by declaration name (never a line +number), perspective, the claim, the refuting evidence, the declarations the +refutation depends on, the commit (`git rev-parse --short HEAD`), and the +date. One row per claim, not per finding. While you are in the file, delete +rows that are void under its expiry rule and rows whose claim was re-filed and +re-adjudicated this run — the new adjudication replaces the old row. This is +the only step that writes to the ledger, and skipping it is what makes the +next run repeat this one's dead ends. + +### 4. Aggregate + +Wait for every perspective (and the refutation pass, if any) to complete, then +emit one markdown report to the chat, grouped by severity. Do not soften, +merge, or drop findings; findings from different perspectives on the same line +stay separate entries. The one exception: the reviewers' `## Out of +perspective` sections (defects fitting no perspective — layout violations, +Mathlib duplicates) may name the same defect several times; de-duplicate those +and file each once, under the severity it deserves. + +**Verify every blocker yourself before printing it.** Open the declaration and +confirm the claim with `lean_goal` / `lean_term_goal` from your own seat — so +that you are not merely relaying. A blocker you could not confirm drops to +should-fix and is marked `aggregator-unverified`; it is not deleted, because +failing to confirm is not refuting. This is the one place the skill spends your +own LSP calls rather than an agent's, and it is worth it: a false blocker costs +the reader more than a missed nit. + +**Attribute claims to whoever made them.** Write "the perspective 2 reviewer +reports X; I confirmed the elaborated type at Y" — not "X is a bug". You are +reporting what the review produced and how far you checked it, and those are two +different statements. Keep them separate in the prose. + +Template: + +```markdown +# Math Review — <target> + +**Scope**: <N> files / <M> declarations <!-- from the agents' reviewed-declaration lists --> +**Verdict**: <worst severity present, or ✅ no findings> + +## 🛑 Blocker +### 1. <one-line title> +- `file:line` `declName` — [<perspective>/<a|b|c>] <!-- note "promoted by refutation" where step 3 upgraded it --> +- **Problem**: … +- **Fix**: … +- **Verified**: <what you confirmed yourself, or `aggregator-unverified`> + +## ⚠️ Should-fix +…same shape… + +## 💡 Nit +…same shape… + +## Ranked risks +<descending by concern, independent of severity; for each, whether it + **could make a theorem false** or is **presentation only**. State plainly which + findings, if any, can actually kill a result — and say so when none can.> + +## What this change does not claim +<what a reader might wrongly take away: the generality the statements stop + short of, the cases left uncovered, the corollaries that do not follow> + +## Per-perspective summary +| Perspective | blocker | should-fix | nit | forecast | verdict | +|---|---|---|---|---|---| +<all five perspectives, every row present; ✅ for a clean perspective; + forecast is hit / miss / n.a. — the divergence the reviewer reported> + +## Refuted findings <!-- only if step 3 dropped or downgraded any --> +<one line each: the finding and why it was refuted> + +## Not reviewed +<deleted files; files no agent could reach; perspectives that returned partial; + and — always — the **unexamined dependencies the verdict rests on**: the + declarations the reviewers relied upon without opening, taken from each + reviewer's per-finding confidence split. The risk lives here, not in what was + checked, so this section is never omitted.> +``` + +Omit an empty severity section, never an empty summary row, and never +`## Not reviewed`. + +## Why perspectives, not files + +A diff hunk is not a reviewable unit in Lean: a statement's elaborated type is +fixed by binders, `variable` blocks, and `open scoped` lines that sit outside +the hunk, and one hunk routinely spans several declarations. That expansion +belongs to the `math-reviewer` agent; this skill only resolves *which files* +enter the review. + +Nor is a file the unit of judgement: deferred hypotheses are discharged — or +silently left standing — across files, and abstraction drift shows up only +when the definition and its uses are read together. One reviewer per +perspective sees the whole change at once, and caps the fan-out at five agents. +Four of them lean on the shared search tools, so the `lean_loogle` rate limit +(3 requests / 30s) is a genuinely scarce shared budget — each reviewer's agent +file has it prefer `lean_local_search` and spend remote searches per sweep, +not per declaration. Perspective 5 works almost entirely through +`lean_run_code` and `lean_multi_attempt` against the local toolchain, so adding +it costs concurrency but not remote quota. + +## Ledger + +`ledger.md`, next to this file, is the skill's memory across runs. Without it +every run re-derives the same dead ends: a reviewer files a plausible claim, the +refutation pass kills it, the report ships, and the next run files it again. + +Step 3 writes it — one row per claim the refutation pass refuted — and is also +the step that deletes rows voided by expiry or replaced by a re-adjudication. +Step 2 reads it and hands each reviewer its own rows as a do-not-re-file list. +Nothing else touches it. + +The rows are keyed by **declaration name**, because line numbers move. Each +carries the declarations its refutation depends on, because a ledger that +silences a true finding is worse than no ledger: when a `Depends on` declaration +changes relative to the row's `Commit`, the row expires and the claim is open +again. Reviewers are told this rule explicitly, and a reviewer that doubts a row +should re-file rather than stay quiet. diff --git a/.claude/skills/math-review/ledger.md b/.claude/skills/math-review/ledger.md new file mode 100644 index 0000000..1c25dc1 --- /dev/null +++ b/.claude/skills/math-review/ledger.md @@ -0,0 +1,57 @@ +# Refuted-findings ledger + +A do-not-repeat list for `math-review`. Step 3 (the refutation pass) appends to +it; step 2 hands each perspective reviewer its own rows so the same claim is not +re-filed run after run. + +## What goes in + +**One row per *claim*, not per finding.** The same defect reported twice under +different wording is one claim. Reference the target by **declaration name** — +never by line number, which moves with the next edit. + +Only claims the refutation pass **refuted** are recorded. A finding that +survived refutation — whether promoted to (a)/(b) or still at tier (c) — +belongs in the report, not here. + +## Expiry — read this before trusting a row + +Every refutation rests on something: an elaborated type, an instance, a +docstring. The `Depends on` column names it; the `Commit` column records when +it was measured. **When a declaration listed under `Depends on` has changed +since `Commit`, the row is void and the claim may be filed again.** The check +is mechanical, not a judgement call: + +1. `git diff <Commit>..HEAD -- <file>` for each file housing a `Depends on` + declaration; untouched files mean the row stands. +2. If a file changed, re-fetch the declaration's current elaborated type and + compare it against the evidence quoted in `Refutation`. +3. A `Depends on` declaration that no longer resolves — renamed or deleted — + voids the row unconditionally. + +A stale ledger suppressing a true finding is the one real danger of this file. +When in doubt about whether a row still holds, re-file rather than stay +silent. Rows are never deleted for being old — only by step 3 of the skill, +when they are void under this rule or when the claim is re-filed and +re-adjudicated (the new adjudication replaces the old row). + +## Format + +| Target | P | Claim | Refutation | Depends on | Commit | Date | +|---|---|---|---|---|---|---| + +- **Target** — `path/to/File.lean:declarationName` (no line numbers) +- **P** — perspective 1–5 that filed the claim +- **Claim** — what was asserted to be wrong, in one line +- **Refutation** — the concrete evidence, quotable: an elaborated type or a + fully-qualified declaration name +- **Depends on** — the declaration(s) the refutation rests on; the expiry trigger +- **Commit** — `git rev-parse --short HEAD` when the row was appended; the + baseline the expiry check diffs against +- **Date** — `YYYY-MM-DD` the row was appended + +## Entries + +| Target | P | Claim | Refutation | Depends on | Commit | Date | +|---|---|---|---|---|---|---| +<!-- Append below. Newest last. --> From ca91d56fe1669c0d40c1630a846d20c4014ba43b Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 15:12:20 +0000 Subject: [PATCH 077/113] docs: gloss the tensor-bar shorthand in TensorFactor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs across the von Neumann tensor cluster write `A ⊗̄ B` for the spatial tensor product of algebras, but the symbol has no Lean declaration and was never explained. Pin it at the definition site of the two factors it names, and point at the notations that are declared (`⊗̂`, `⊗ₕ`). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index fff8da5..3c53adb 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -18,6 +18,11 @@ von Neumann factors on the completed Hilbert tensor product: * `HilbertTensor.vnTensorRight = 1 ⊗̄ B(H₂)` — the von Neumann algebra generated by the image of `amplifyRight`. +Here and in the files downstream, `⊗̄` is documentation shorthand for the von Neumann (spatial) +tensor product of algebras: it has no Lean declaration, and the algebras it names are the two +definitions above. The tensor notations that *are* declared live in `TensorProductCompletion`: +`⊗̂` for the completed Hilbert tensor product and `⊗ₕ` for elementary tensors. + These are the objects in the split-property tensor decomposition `A₁ ⊆ B(H₁)⊗̄1`, `A₂ ⊆ 1⊗̄B(H₂)` (paper eq. (39)). The file culminates in the **tensor commutation theorem** `vnTensorLeft.commutant = vnTensorRight` (von Neumann's commutation theorem for a full factor on From 8f1472efddfe16999a783134dba236e1d876bd4f Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 15:12:28 +0000 Subject: [PATCH 078/113] refactor: name the proper-containment hypothesis in the split lemma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `isSplitInclusion_of_le_of_le` recorded only its two `≤` hypotheses and left the load-bearing `O₁ ⋐ O₂` out of the name. Rename it to `isSplitInclusion_of_le_of_properlyContained_of_le`, matching the `properlyContained` wording the class already uses. No call sites existed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- QuantumSystem/Algebra/LocalNet/SplitProperty.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean index f058d9a..917088c 100644 --- a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean +++ b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean @@ -186,7 +186,7 @@ variable {R : CStarRep N.quasiLocalCStarAlgebra} /-- The split property extends to enlarged pairs: if `O₀ ≤ O₁ ⋐ O₂ ≤ O₃` then the inclusion `𝓡(O₀) ≤ 𝓡(O₃)` is split as well. -/ -lemma SplitProperty.isSplitInclusion_of_le_of_le (hs : N.SplitProperty R) +lemma SplitProperty.isSplitInclusion_of_le_of_properlyContained_of_le (hs : N.SplitProperty R) {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) (h₃ : O₂ ≤ O₃) : VonNeumannAlgebra.IsSplitInclusion (N.localVonNeumannAlgebra R O₀) (N.localVonNeumannAlgebra R O₃) := From 5445e7fce83b90970bf7f5e177d880475176414a Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 16:03:34 +0000 Subject: [PATCH 079/113] feat: add lint-fix skill and move the lint rules into it AGENTS.md carried both the thinking principles and the mechanical rules (editing hygiene, prohibited tokens, commit style, style guidelines). The mechanical half is now in the lint-fix skill, which detects violations and applies the fixes that are genuinely mechanical. The rules sit in references/rules.md rather than in SKILL.md so that consulting them does not pull in the fixer: SKILL.md carries disable-model-invocation because it writes to the working tree, and a rule lookup must not turn into an unrequested rename. AGENTS.md therefore points at the two separately. Tier A/B/C in SKILL.md records which fixes are safe. Deleting a sorry does not prove a theorem and dropping a set_option does not make a proof fast, so those are reported rather than fixed; a set_option whose removal breaks the build is restored and reported, naming the proof that depends on it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/lint-fix/SKILL.md | 225 ++++++++++++++++++++ .claude/skills/lint-fix/references/rules.md | 69 ++++++ AGENTS.md | 65 +----- 3 files changed, 303 insertions(+), 56 deletions(-) create mode 100644 .claude/skills/lint-fix/SKILL.md create mode 100644 .claude/skills/lint-fix/references/rules.md diff --git a/.claude/skills/lint-fix/SKILL.md b/.claude/skills/lint-fix/SKILL.md new file mode 100644 index 0000000..d07c680 --- /dev/null +++ b/.claude/skills/lint-fix/SKILL.md @@ -0,0 +1,225 @@ +--- +name: lint-fix +description: Fix a change — or an explicitly named file, directory, or commit range — into conformance with the project lint rules: whitespace, 120-column layout, naming, docstrings, English comments, prohibited tokens, pinned files, and Conventional Commits. Applies the safe fixes, verifies with `lake build`, and reports what it deliberately left alone. +argument-hint: "[path | dir | main...HEAD]" +disable-model-invocation: true +--- + +Bring the target files into conformance with the project lint rules: detect the +violations, apply the fixes that are genuinely mechanical, and report the rest +rather than forcing them. The rules are the ones `lake exe runLinter`, +`cz check`, and Mathlib review would eventually catch — this skill closes them +now, at the cost of touching the working tree, so the discipline about *which* +fixes are safe matters more than the detection. + +The failure mode to avoid is a fix that makes the lint report clean while making +the code worse: deleting a `sorry` does not prove a theorem, dropping a +`set_option` does not make a proof fast, and inventing a docstring for a lemma +you have not read is a false claim in the repository. Those are reported, not +fixed. + +## Rules + +The rules live in `references/rules.md`, next to this file — never duplicate them +here. That file is their authoritative home: `AGENTS.md` points readers at it for +the rules alone, without dragging in this skill's fixing machinery, and keeping +one copy is what stops a rule from being tightened in one place and left stale in +the other. + +Read it in step 3; detection does not work without it. + +## What may be fixed, and what may not + +Sort every violation into one of three tiers before touching a file. The tier +decides the action; when a violation could belong to two tiers, take the more +cautious one. + +**Tier A — apply directly.** Purely textual, no effect on the elaborated term. + +- Tabs → spaces at the surrounding indentation width (2-space steps). +- Trailing whitespace on a line you are already editing. +- Layout nits: `by` placement, `calc` alignment on the relation, `case _ =>` → + `·`, indentation that is not a multiple of two. +- Non-English comments → English, preserving the technical content. + +**Tier B — apply, then prove it survived.** The fix is known but can change +elaboration or break callers, so each one is verified in step 5. + +- Lines over 120 columns: re-wrap. Never shorten by deleting content, weakening + a statement, or renaming to something shorter — wrap at a binder, an + argument, or a `calc` step instead. +- Missing docstrings: read the declaration's *elaborated* statement first + (`lean_hover_info`, or `lean_goal` for a theorem) and describe what it + actually establishes. A docstring that overstates the code is worse than none, + because the repo's own principle is to raise the code to the docs — writing an + aspirational summary silently manufactures that debt. +- Naming violations: rename, then update every reference. Find them with + `lean_references` (not grep — grep misses qualified and re-exported uses) and + fix all of them in the same pass; a half-renamed declaration does not build. +- `set_option`: remove it and rebuild. If the build then fails, the option was + load-bearing — restore it and report the finding, noting *which* proof depends + on it. That dependency is a real defect worth naming rather than a lint nit, + and discovering it is more useful than silently keeping the line. +- `namespace`/`section QuantumSystem`: removing it re-qualifies every + declaration inside, so treat it as a rename of all of them — sweep references + the same way, and expect to touch importers. + +**Tier C — never fix here; report it.** Either no mechanical fix exists, or the +fix destroys work. + +- `sorry`, `admit`, `axiom`: the only real fix is a proof, which is mathematical + work, not linting. Deleting the token leaves an unproved goal or removes a + declaration others depend on. Report as a blocker and stop there. +- `unsafe`: removing it means rewriting the definition to be safe — a design + change, not a lint fix. +- Edits to `lakefile.toml`, `lean-toolchain`, `lake-manifest.json`: the fix is + `git checkout -- <file>`, which discards whatever the user did. Print the + command and let them decide. +- Commit messages: correcting one means `git commit --amend` or a rebase, which + rewrites history. Print the corrected message and the command; do not run it + without the user saying so in this conversation. +- `System` / `Lean.Elab` / `Lean.Meta` / `Lean.Compiler` uses: dropping the + import or the reference requires replacing the functionality. Report it. + +## Process + +### 1. Pin the target + +Take the first non-empty option: + +1. An explicit argument — a file, a directory (expand with Glob), or a commit range. +2. The union of the local change and the branch change, so that a stray + working-tree edit cannot shadow committed branch work: + - `git diff --name-only --diff-filter=ACMR HEAD` (working tree and index), + - `git ls-files --others --exclude-standard` (untracked new files — `git diff` never lists these), + - `git diff --name-only --diff-filter=ACMR <base>...HEAD`, where `<base>` is + `main`, falling back to `origin/main`, then `origin/HEAD`; if none + resolves, drop this component rather than failing. + +Do **not** filter to `.lean` here — the tab and pinned-file rules apply to every +file in the change. If every option is empty, ask the user what to fix rather +than reporting a clean pass over nothing. + +Announce the resolved target before editing anything. This skill writes to the +working tree, so a wrong default is expensive — one word of correction now beats +a revert later. + +### 2. Record the baseline + +Before the first edit, capture what "no *new* errors" will be measured against: + +- `git status --short` — note pre-existing modifications, so your fixes stay + distinguishable from the user's own work in the final diff. +- `lake build` on the target modules. If the build is already broken, say so and + fix only Tier A violations: with a red baseline you cannot tell whether a + Tier B fix broke something. Detection still runs in full — every Tier B + violation you find gets reported as deferred, with the pre-existing error that + blocked it. Omitting them would read as "nothing else to fix", which is the + opposite of what a red baseline means. + +### 3. Detect (Bash, restricted to the target files) + +Read `references/rules.md` first. The commands below encode the rules that happen +to be greppable; the rules themselves — and the reasons behind them, which are +what let you judge a case the grep does not literally cover — are in that file. + +A grep hit is a *lead*, not a verdict: open the line and confirm it before +fixing. A token inside a string literal, a docstring quoting the rule, or this +skill file itself is not a violation — and a fix applied to a false positive is +a real defect introduced by the fixer. + +- **Tabs** (all files): `grep -nP '\t' <files>` +- **Line length** (`.lean` files only — the 120-column rule is Lean layout style; + the repo's own markdown exceeds it): + `awk 'length > 120 {print FILENAME ":" FNR ": " length($0) " cols"}' <files>` +- **Pinned files**: check whether the target list contains `lakefile.toml`, + `lean-toolchain`, or `lake-manifest.json`. +- **Prohibited tokens** (`.lean` files only): + - `grep -nwE 'sorry|admit|axiom|set_option|unsafe' <files>` + - `grep -nE 'open System|Lean\.(Elab|Meta|Compiler)' <files>` + - `grep -nw 'System' <files>` — then judge each hit in context; `System` is a + common English word in comments, and only the Lean namespace is prohibited. +- **Forbidden namespace** (`.lean` files only): + `grep -nE '^\s*(namespace|section)\s+QuantumSystem\b' <files>` +- **Commit messages** (only when the target is a commit range): for each commit + in the range run `uv run cz check -m "$(git log -1 --format=%s <sha>)"`, then + additionally check the type against the narrower project vocabulary + (`feat|fix|chore|docs|refactor|test|perf`) — `cz check` alone accepts more + types than the project convention does. + +Then read the changed declarations for what cannot be grepped, judging each +against the corresponding section of `references/rules.md`: naming (its +*Naming* bullets), docstring presence and whether the first sentence is a +self-contained summary, module docs on new files (*Docstrings*), comment +language (*Editing Hygiene*), and layout (*Layout*). + +Confine this to the changed declarations (use the diff's line ranges); do not +re-litigate untouched code in a diff-derived run. An explicit file or directory +target has no diff — cover the whole file. + +### 4. Apply the fixes + +Work one rule at a time across all files, not one file at a time across all +rules: a diff whose hunks each address a single rule is reviewable, and a +mixed-up one is not. Fix Tier A first — it cannot break the build, so it gets +the later verification for free — then Tier B, unless step 2 found a red +baseline, in which case Tier B is deferred rather than attempted. + +Keep the fixes separable from any semantic change. If a fix tempts you into +altering a statement, a hypothesis, or a proof, stop: that is the repository's +"prove what is provable" territory, and it belongs in its own change with its +own review, not smuggled in under a lint pass. + +### 5. Verify + +A fix is not done because the file was written; it is done when the build agrees. + +- `lake build` on the edited modules **and their downstream importers** — Tier B + renames and namespace removals fail precisely there. +- Compare against the step 2 baseline: no new errors and no new warnings. +- Re-run the step 3 detection over the same targets to confirm the violations + are actually gone and that no fix introduced a new one (a re-wrap that lands + on a tab, a rename that collides). +- If a Tier B fix cannot be made to build, revert that fix and report it as + unfixed with the error. Never reach for `try`, `<;>`, or `set_option` to make + a broken fix compile — that trades a lint violation for a worse one. + +## Report + +Lead with what changed in the working tree, since that is what the user has to +review. Then what was left, and why — the deliberate omissions are the part +only this pass knows about. + +```markdown +# Lint Fix — <target> + +**Scope**: <N> files (<M> .lean) / <commit range if any> +**Result**: <K> fixed, <L> left unfixed, <D> deferred (see below) +**Build**: <lake build outcome vs. baseline, naming the modules built> + +## ✅ Fixed +- `file:line` — <rule>: <what it was> → <what it is now>. [Tier A|B] + +## 🛑 Left unfixed — blockers +<Tier C, and any Tier B fix reverted in step 5. For each: `file:line`, the rule, + why it was not fixed, and the concrete next action — the command to run, or the + proof obligation to discharge.> + +## ⚠️ Left unfixed — needs a decision +<violations whose fix would discard the user's work or rewrite history: pinned + files, commit messages. Give the exact command, do not run it.> + +## ⏸️ Deferred — baseline build was red <!-- only when step 2 found a broken build --> +<Tier B violations that were detected but not attempted, because verification was + impossible. `file:line` and the rule for each, plus the pre-existing build error + that blocked the pass, so that re-running once the build is green picks them up. + These are not judgements that the code is fine — they are unexamined.> + +## Not checked +<files skipped (binary, generated), checks not applicable (no commit range → no + commit-message check), and any grep hit dismissed as a false positive — name it + and say why, so the dismissal is auditable> +``` + +If nothing needed fixing, say so explicitly (✅) together with the scope +covered — a clean report over the wrong scope is worse than no report. diff --git a/.claude/skills/lint-fix/references/rules.md b/.claude/skills/lint-fix/references/rules.md new file mode 100644 index 0000000..6aff996 --- /dev/null +++ b/.claude/skills/lint-fix/references/rules.md @@ -0,0 +1,69 @@ +# Project Lint Rules + +The authoritative statement of this repository's editing hygiene, prohibited +tokens, commit style, and style guidelines. `AGENTS.md` points here rather than +restating them, and the `lint-fix` skill detects and fixes violations of them — +so this file is the one place to edit when a rule changes. + +Each rule carries the reason it exists where the reason is not self-evident. The +reasons are load-bearing: they are what lets you judge an edge case the bullet +does not literally cover, instead of guessing. + +## Editing Hygiene + +- Spaces only, never tabs. + **Why:** Mathlib style; mixed whitespace breaks `lake exe runLinter`. +- Never modify `lakefile.toml`, `lean-toolchain`, or `lake-manifest.json`. + **Why:** the toolchain and manifest are pinned intentionally; accidental edits cascade into reproducibility failures. +- Write comments in English. +- Never create namespaces or sections named `QuantumSystem`. + **Why:** the module path already prefixes every declaration; an extra namespace would produce `QuantumSystem.QuantumSystem.Foo`. + +## Prohibited Tokens + +The following tokens are strictly prohibited in Lean sources, grouped by reason. + +- *Unsound or deferred proofs:* `sorry`, `admit`, `axiom`. + **Why:** the project targets a fully axiom-free formalization; assumptions smuggled into structure fields count as axioms too. +- *Global configuration and unsafe code:* `set_option`, `unsafe`. + **Why:** these mutate kernel or elaborator behavior project-wide, or bypass soundness. +- *Compiler and metaprogramming internals:* `System`, `open System`, `Lean.Elab`, `Lean.Meta`, `Lean.Compiler`. + **Why:** this is a mathematics repository, not a tactic-library repository; depending on internals creates brittle code. + +## Commit Style + +`lefthook` + `commitizen` (`cz check`, configured in `pyproject.toml`) enforce this; the accepted +vocabulary is: + +- Conventional Commits: `feat` / `fix` / `chore` / `docs` / `refactor` / `test` / `perf`. +- Lowercase type, colon, imperative subject. Example: `feat: add GNS faithfulness lemma`. +- One logical change per commit. + +The hook runs the stock `cz_conventional_commits` schema, which also accepts `build` / `ci` / +`style` / `revert` / `bump`; the list above is the deliberately narrower project convention. + +## Style Guidelines + +The Mathlib contribute templates are authoritative; the bullets below distill what actually comes up during edits. + +**Naming.** +- `lowerCamelCase` for terms and definitions (`gnsRepresentation`, `isPureState`). +- `UpperCamelCase` for types, structures, and propositions (`CStarAlgebra`, `IsState`). +- Theorem names use `_` as word separator (`norm_add_le`, `inner_self_nonneg`). +- Prefer the `_of_` pattern for implications (`continuous_of_lipschitz`); `iff` joins equivalences; `not_` prefixes negations. + +**Layout.** +- 120-column line limit. +- 2-space indentation; `by` stays on the same line as the goal it opens unless the resulting line would exceed the limit. +- Hoist shared hypotheses into `variable` blocks; keep explicit/implicit arity consistent with sibling lemmas. +- Align `calc` steps on the relation; use `·` (centered dot) for focused goals, not `case _ =>`. + +**Docstrings.** +- Every public declaration gets a `/-- ... -/` docstring whose first sentence is a self-contained summary. +- Module docs (`/-! # Title ... -/`) at the top of each file describe the content and any non-obvious conventions. + +**References** (fetch when a rule above is ambiguous): + +- https://github.com/leanprover-community/leanprover-community.github.io/blob/lean4/templates/contribute/doc.md +- https://github.com/leanprover-community/leanprover-community.github.io/blob/lean4/templates/contribute/naming.md +- https://github.com/leanprover-community/leanprover-community.github.io/blob/lean4/templates/contribute/style.md diff --git a/AGENTS.md b/AGENTS.md index c3f3188..7f5b232 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,64 +67,17 @@ the error — re-inspect the goal with `lean_goal` and address the actual mismatch. -## Editing Hygiene +## Lint Rules -- Spaces only, never tabs. - **Why:** Mathlib style; mixed whitespace breaks `lake exe runLinter`. -- Never modify `lakefile.toml`, `lean-toolchain`, or `lake-manifest.json`. - **Why:** the toolchain and manifest are pinned intentionally; accidental edits cascade into reproducibility failures. -- Write comments in English. -- Never create namespaces or sections named `QuantumSystem`. - **Why:** the module path already prefixes every declaration; an extra namespace would produce `QuantumSystem.QuantumSystem.Foo`. +Editing hygiene, prohibited tokens, commit style, and style guidelines live in +`.claude/skills/lint-fix/references/rules.md`. Read that file when a hygiene or +style question arises while editing — it is the authoritative statement of the +rules and stands on its own. -## Prohibited Tokens - -The following tokens are strictly prohibited, grouped by reason. - -- *Unsound or deferred proofs:* `sorry`, `admit`, `axiom`. - **Why:** the project targets a fully axiom-free formalization; assumptions smuggled into structure fields count as axioms too. -- *Global configuration and unsafe code:* `set_option`, `unsafe`. - **Why:** these mutate kernel or elaborator behavior project-wide, or bypass soundness. -- *Compiler and metaprogramming internals:* `System`, `open System`, `Lean.Elab`, `Lean.Meta`, `Lean.Compiler`. - **Why:** this is a mathematics repository, not a tactic-library repository; depending on internals creates brittle code. - -## Commit Style - -`lefthook` + `commitizen` (`cz check`, configured in `pyproject.toml`) enforce this; the accepted -vocabulary is: - -- Conventional Commits: `feat` / `fix` / `chore` / `docs` / `refactor` / `test` / `perf`. -- Lowercase type, colon, imperative subject. Example: `feat: add GNS faithfulness lemma`. -- One logical change per commit. - -The hook runs the stock `cz_conventional_commits` schema, which also accepts `build` / `ci` / -`style` / `revert` / `bump`; the list above is the deliberately narrower project convention. - -## Style Guidelines - -The Mathlib contribute templates are authoritative; the bullets below distill what actually comes up during edits. - -**Naming.** -- `lowerCamelCase` for terms and definitions (`gnsRepresentation`, `isPureState`). -- `UpperCamelCase` for types, structures, and propositions (`CStarAlgebra`, `IsState`). -- Theorem names use `_` as word separator (`norm_add_le`, `inner_self_nonneg`). -- Prefer the `_of_` pattern for implications (`continuous_of_lipschitz`); `iff` joins equivalences; `not_` prefixes negations. - -**Layout.** -- 120-column line limit. -- 2-space indentation; `by` stays on the same line as the goal it opens unless the resulting line would exceed the limit. -- Hoist shared hypotheses into `variable` blocks; keep explicit/implicit arity consistent with sibling lemmas. -- Align `calc` steps on the relation; use `·` (centered dot) for focused goals, not `case _ =>`. - -**Docstrings.** -- Every public declaration gets a `/-- ... -/` docstring whose first sentence is a self-contained summary. -- Module docs (`/-! # Title ... -/`) at the top of each file describe the content and any non-obvious conventions. - -**References** (fetch when a rule above is ambiguous): - -- https://github.com/leanprover-community/leanprover-community.github.io/blob/lean4/templates/contribute/doc.md -- https://github.com/leanprover-community/leanprover-community.github.io/blob/lean4/templates/contribute/naming.md -- https://github.com/leanprover-community/leanprover-community.github.io/blob/lean4/templates/contribute/style.md +To fix a change rather than consult the rules, run `/lint-fix`: it applies the +safe fixes, verifies with `lake build`, and reports what it deliberately left +alone. It writes to the working tree, so it runs only when you ask for it by +name. ## Source of Truth From 9fed2096a049d8724820978617207f79a97e5e08 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 16:17:45 +0000 Subject: [PATCH 080/113] docs: add plan-mode response guidance to AGENTS.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --- AGENTS.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 7f5b232..a992235 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,6 +67,25 @@ the error — re-inspect the goal with `lean_goal` and address the actual mismatch. +## Plan Mode & Responses + +**In plan mode, a question deserves an answer — not a plan.** +- When the user asks a question under plan mode, reply with the + AskUserQuestion tool and answer *only* what was asked. Do not invent a + problem statement or start drafting a plan the user never requested. + +**Numbered steps first, prose second.** +- Do not narrate a whole plan in prose. Lead with the concrete steps as a + numbered list, then add brief supplementary notes after it. + **Why:** the reader has ADHD; a response that demands sustained attention + to parse is a response that does not get read. Keep it scannable. + +**Do not force a plan that does not fit.** +- If the request is judged infeasible or inappropriate to turn into an + implementation plan, do not force one. State the grounds for that + judgement, then offer alternative approaches that are viable for the + current codebase, or point to references worth investigating further. + ## Lint Rules Editing hygiene, prohibited tokens, commit style, and style guidelines live in From d33e61bfcbdca6456af2bf64911417570382312a Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 17:58:55 +0000 Subject: [PATCH 081/113] feat: add math-extract skill for pre-Lean literature extraction Extract the mathematics of an object from the literature before any Lean is written, via parallel per-lane math-extractor sub-agents: definitional variants and the conventions behind them, results and what they rest on, hypotheses sorted into provable / model-dependent / open, degenerate cases, and rejected formulations each carrying the object that rules it out. The skill stops at the mathematics. Notes under docs/math/ contain no Lean types, declaration names, or docstring drafts, and the agent is given no tool that elaborates Lean. Reporting what Mathlib already has is a fact and is allowed; proposing how this project should define anything is not. Three disciplines make the evidence tiers mean something rather than be self-reported: - a four-tier scale (quoted / read / attested / recalled) whose locator rule forbids a theorem number for a source nobody opened, and demands a one-line statement of what the cited result says in its place; - a quote check: every verbatim quotation must survive grep -F against the cached source. Measured on math-ph/0411058, a real sentence matches in source.flat.txt, fails in source.txt because LaTeX wraps it across lines, and a fabricated variant fails in both; - a rejection discipline where each rejected formulation carries a typed discriminator naming the object that separates it, and "harder to formalize" is explicitly not one. Ingestion prefers arXiv LaTeX source, which is the original text and so needs no quote check at all. PDF conversion through MinerU is a later serial rung, documented in references/ingestion.md but exiting 5 for now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/agents/math-extractor.md | 385 ++++++++++++++++++ .claude/settings.local.json | 8 +- .claude/skills/math-extract/SKILL.md | 321 +++++++++++++++ .../math-extract/references/ingestion.md | 130 ++++++ .../math-extract/references/note-format.md | 322 +++++++++++++++ .claude/skills/math-extract/scripts/ingest.py | 311 ++++++++++++++ .claude/skills/math-extract/sources.md | 68 ++++ AGENTS.md | 2 + docs/math/README.md | 28 ++ 9 files changed, 1574 insertions(+), 1 deletion(-) create mode 100644 .claude/agents/math-extractor.md create mode 100644 .claude/skills/math-extract/SKILL.md create mode 100644 .claude/skills/math-extract/references/ingestion.md create mode 100644 .claude/skills/math-extract/references/note-format.md create mode 100644 .claude/skills/math-extract/scripts/ingest.py create mode 100644 .claude/skills/math-extract/sources.md create mode 100644 docs/math/README.md diff --git a/.claude/agents/math-extractor.md b/.claude/agents/math-extractor.md new file mode 100644 index 0000000..9144758 --- /dev/null +++ b/.claude/agents/math-extractor.md @@ -0,0 +1,385 @@ +--- +name: math-extractor +description: >- + Extracts the mathematics of an object from the literature, before any Lean is + written — what each source's definition literally says, which conventions make + those statements meaningful, what the results are and what they rest on, which + hypotheses are provable versus genuinely model-dependent, where the definition + degenerates, and what prior formalizations chose. Reports mathematics only: + never a Lean type, definition, declaration name, or docstring. Use via the + `math-extract` skill when a new object is about to be designed. For reviewing + Lean that already exists, use `math-reviewer` instead. +tools: Read, Grep, Glob, Bash, Write, WebSearch, WebFetch, mcp__lean-lsp__lean_local_search, mcp__lean-lsp__lean_leansearch, mcp__lean-lsp__lean_loogle, mcp__lean-lsp__lean_leanfinder, mcp__lean-lsp__lean_declaration_file, mcp__lean-lsp__lean_hover_info, mcp__lean-lsp__lean_file_outline, mcp__lean-lsp__lean_references +model: inherit +--- + +# math-extractor + +Extract the mathematics of an object as a working mathematician would prepare it +for someone else to formalize — reading sources, not writing code. Your evidence +is the text of a source you actually fetched and opened. You inspect and report; +the one file you may write is the notes file your prompt assigns. + +**You do not formalize.** No Lean types, no `def`/`structure`/`class` sketches, +no candidate declaration names, no docstring drafts, no ` ```lean ` fences. This +is not a stylistic preference: a premature Lean sketch becomes noise at the +moment the Lean is actually written, and the skill that owns this decision has +excluded it from scope. You are given no tool that elaborates Lean, which is the +structural half of the same rule. You may *report* that Mathlib or another +system already contains something — that is a fact about the world. You may not +propose how this project should define, name, or arrange anything. + +## Your role in the extraction + +You are normally launched as **one of several lane-specific extractors** working +over the *same* object and the *same* corpus in parallel. The invoking prompt +assigns you exactly one of the lanes below — or the refutation role. Own your +lane completely and file **only** rows that belong to it: the other lanes have +their own extractor, and a row filed under two lanes is double-counted at merge. +When a row sits on a boundary, the tie-breaks below decide the owner. + +- **1 vs 2** — sources differing only by *convention* is lane 1, as one `(C#)` + row; sources differing in mathematical content is lane 2, as separate `(R#)`. +- **1 vs 3** — **follow the source's typography, not the logic.** A condition + written *inside the definition* is lane 1; the same condition written *in a + theorem's hypothesis list* is lane 3. Sources disagreeing about which is + which is itself a lane 1 finding — a definitional variant — while lane 3 + records only the hypothesis form and points at the `(D#)`. The two are + logically interchangeable, so placement is the only decidable criterion + available, and a decidable criterion is what stops both lanes filing it. +- **1 vs 4** — **variants exist in the literature; rejections are this note's + own constructions.** A formulation some source actually adopts is a lane 1 + variant, carrying that source. A formulation nobody adopts, invented here to + be tested, is lane 4. It follows that **lane 4 may never "reject" a + formulation a source adopts**: the most it can do is produce a discriminator + showing the two inequivalent and hand it to lane 1. +- **1 vs 5** — whether the *literature* has several definitions is lane 1; + whether a *proof assistant* has one is lane 5, and that row points back at the + `(D#)` it matches instead of restating it. +- **2 vs 3** — **an edge has something to point at; a hypothesis does not.** If + the dependency is another numbered statement, in the corpus or external, it is + an edge and belongs to lane 2. If it is a condition on the objects with no + statement behind it — separability, nuclearity — it is a hypothesis and + belongs to lane 3. Standing hypotheses are lane 3 and receive no edge. +- **2 vs 4** — a lemma a result **rests on** is lane 2; a case where a result + **breaks** is lane 4. +- **2 vs 5** — an external result a source cites without proof is a lane 2 + `[ext: …]` edge; whether it is already formalized is lane 5. +- **3 vs 4** — **classification is lane 3; constructing the model is lane 4.** A + lane 3 row needing a falsifying model it cannot exhibit is filed `open`, naming + what it needs; lane 4 builds it and the orchestrator routes it back at merge. +- **3 vs 5** — that a proof assistant has *proved* a hypothesis is a fact lane 5 + supplies; classifying the hypothesis `provable` on that basis is lane 3's + judgement. +- **4 vs 5** — the degenerate case itself is lane 4; that some system's + typeclass hierarchy excludes it is lane 5. + +A real finding that fits **no** lane — a typo in the corpus, a theorem number +that differs between the preprint and the published version, a source that +contradicts itself — goes in a final `## Out of lane` section of your report, +separate from your lane's rows. The orchestrator de-duplicates those. Never +discard a finding for fitting badly. If you are invoked with no lane assigned, +cover all five yourself. + +## Ground rules + +- **Evidence tiers.** Every row you file carries one. + + | Tier | What you have | What you may write | + |---|---|---| + | **(a) quoted** | the source in the corpus cache, opened at the passage | a verbatim quote, **a full locator**, and the cache path | + | **(b) read** | the same, passage read | a paraphrase and **a full locator** | + | **(c) attested** | *another* fetched source attributes the claim to this one | the claim and **the attesting source's** locator; the original's locator only if the attester quotes it verbatim | + | **(d) recalled** | nothing | the claim, plus author and title. **No locator of any kind.** | + +- **The locator substitution rule.** A full locator — theorem number, section, + page, equation number — may appear only at tier (a) or (b). **A row forbidden + a locator must instead state, in one line, what the cited result says.** A + number is cheap to fabricate and expensive to check; a statement is expensive + to fabricate and cheap to check. So write + + > `[ext: Takesaki, *Theory of Operator Algebras I* — every type I factor is + > spatially isomorphic to a tensor product of a full operator algebra with a + > commutant acting trivially. tier (d), no locator, not retrieved]` + + and never `[ext: Takesaki V.1.4]` for a book you did not open. This + repository already contains locators written from memory; do not add more. + +- **Tier inheritance.** A row's tier is the **minimum** over what it rests on. A + result read at (b) whose defining terms come from a (d) recollection is a (d) + row. Report the inherited tier, not the flattering one. + +- **A quote is bytes, not a memory.** Every verbatim quote you file must be + copied from the corpus cache and must survive `grep -F` against it — the + orchestrator checks this mechanically and deletes or downgrades what fails. + Quote in the source's own language and notation; never silently normalise a + formula, fix a typo, or translate inside the quotation marks. A translation + goes outside the quote, marked `[tr.]`, and is tier (b) at best because it is + a paraphrase with an extra step. + +- **Converted PDFs are not verbatim.** MinerU's formula recognition is model + inference, so a quote taken from converted Markdown is (b) with + `mineru-unchecked` attached — it reaches (a) only if you compare it against + the page image. **An arXiv LaTeX source is the original and needs no such + check.** Prefer LaTeX over converted PDF whenever the corpus offers both. + +- **Inspect the instrument before believing the reading.** A tool's output is + evidence about the tool as much as about the world. A converted PDF with + garbled formulas indicts the converter; an empty search indicts the query + first. When a reading is surprising, suspect the measurement. + +- **A search miss is not evidence of absence.** Never write "Mathlib has no X" + because one search came back empty. Retry with different spellings and a + different tool (`lean_leansearch` for prose, `lean_loogle` for a type shape, + `lean_leanfinder` for a concept); if it is still not found, write "I could not + find X, having searched …", which is a claim about your search. + +- **Do not fetch what the orchestrator already fetched.** The corpus is built + serially before you are launched, because the PDF converter fails when run + concurrently. Read the cache paths your prompt gives you. Fetching a source + yourself is warranted only for lane 5's search targets and for a source your + prompt lists as *not retrieved* — and then one at a time. + +- **Search tools are shared and rate-limited** across all parallel extractors + (`lean_loogle` 3/30s). Prefer `Grep` over `.lake/packages/mathlib` and + `lean_local_search`; budget remote searches per sweep, not per question. When + throttled, move on and retry later; never convert a throttled search into a + guess. + +- **Start wide, then narrow.** Open with the concept name and its standard + synonyms to map the ground, then drill in. A first query specific enough to + confirm what you already believe will confirm it. + +- **Never stop at the first row.** You are done when your lane's whole question + is answered and you can list what you cleared as well as what you filed. + +- **Write rows to disk as you confirm them, not at the end.** Append each row to + the notes file **whose absolute path your prompt gives you** the moment it is + settled, and treat your final report as a summary of that file. Append with + the Write tool, rewriting the file with the full accumulated content each time + — never with Bash heredocs, which mangle the Unicode and backticks these rows + are full of. Extractions die mid-sweep; what reached disk survives. + +## Lanes + +### 1. Definitions and conventions + +Establish what the object *is*, across every source in the corpus, and pin the +conventions that make those statements mean anything. Your unit of work is the +definition as each source literally writes it — not as the field remembers it. +Every defining source gets its own variant row `(D#)` with its tier, its locator +where the tier allows one, and a verbatim quote where the tier allows that. Two +sources that agree word for word still get a row each when they come from +different traditions; two that differ by one quantifier get two rows and a +`differs by:` line naming the difference in a sentence. + +You do not choose the adopted general form — the orchestrator writes that at +merge time from your variants and lane 4's discriminators. What you supply is +the material for that choice: for each pair of variants, whether the *sources +themselves* claim equivalence, and under which standing assumptions. Equivalence +asserted by a source is a citation; equivalence asserted by you is an argument +and has to be written out. + +The conventions half is not decoration. The axes that actually change truth +values in this domain: whether the trace is normalised, the base of the +logarithm, which argument of the inner product is conjugate-linear, whether +ℏ = 1 is in force, what a summation ranges over, whether algebras are unital, +whether representations are assumed nondegenerate, and whether an order symbol +means the Löwner order or containment of algebras. For every axis the corpus +touches, file `(C#)`: what each source adopts and the translation between them. +A convention a source leaves implicit is recorded as implicit, together with the +passage you inferred it from — and that inference is tier (b) at best. + +Notation is recorded, never invented. Where sources disagree on a symbol, record +both. Do not propose notation and do not name anything. + +### 2. Results and dependency skeleton + +Extract the statements the object exists to support, and the edges between them. +Each result gets `(R#)`: the statement written out, its source and locator at the +tier the locator rule allows, its **proof status** in that source — proved / +sketched / cited elsewhere / asserted — and a `Depends on:` line. Edges point at +other `(R#)`, at hypotheses `(A#)`, or at external results marked `[ext: …]`. + +An external edge is any result a source uses without proving in the corpus. Mark +every one: they are the whole handle anyone later has on the unexamined base +this note rests on. At tier (c) or (d) an external edge carries no locator and +instead carries the one-line statement the substitution rule requires. Getting +that sentence right is the most valuable thing you produce, because it converts +an uncheckable pointer into a checkable claim. + +State each result exactly once. Two sources stating the same result under +different conventions is one row with a `Conventions:` flag, not two. Two +sources stating genuinely different results under the same name is two rows, +plus a note for lane 1. Keep each source's own numbering as the locator; never +renumber and never merge two numbered statements because they look alike. + +Do not classify hypotheses and do not judge degenerate cases. If you notice +either, put it in `## Handoffs` and let the orchestrator route it. + +### 3. Hypotheses + +Take every hypothesis the corpus attaches to the object and to the results, and +classify each as **provable**, **model-dependent**, or **open**. This is +AGENTS.md *Prove what is provable; do not defer it* applied one stage before +`math-review` can apply it — before there is any Lean for a hypothesis to hide +in. + +The bars are deliberately asymmetric: + +- **provable** — say where the proof is: a source and locator at the permitted + tier, or an argument you write out. Mathlib or any other library lacking the + supporting lemmas is irrelevant to this classification. +- **model-dependent** — **name a witness**: a specific object in the intended + class for which the hypothesis fails. Not "it can fail for non-hyperfinite + algebras" but a named object. Also name something satisfying it, so the + hypothesis is not vacuous. +- **open** — neither a proof nor a falsifying object is known. Name the open + question. + +**A hypothesis you believe is model-dependent but cannot supply a witness for is +filed `open`, never `model-dependent`.** Plausibility is not a classification. +This single rule is what keeps the model-dependent class from becoming the place +where unproved things go to rest, and it is what lets a later hypothesis class +be defended rather than merely asserted. + +Distinguish standing from local hypotheses. "Throughout this paper H is +separable" is a standing hypothesis of that source: file it with +`scope: standing`, and lane 2 draws no edge to it. For each `(A#)` record which +results actually use it — a standing hypothesis no result needs is itself a +finding worth reporting. + +### 4. Degeneracies, boundaries and rejected formulations + +You are the only lane that probes rather than reads, and the two activities here +stay in one lane on purpose: the degenerate model that collapses the adopted +definition is usually the same object that separates it from a rejected variant, +and splitting the lane would have two agents build it twice. + +Run the degeneracy checklist against the adopted general form and record a +disposition for **every** item, including the ones where nothing happens — "no +effect" is a result: the zero object (zero algebra, the scalars, an empty +region); the finite-dimensional case; the commutative case; the non-separable or +non-σ-finite case; the type III case; the non-unital or degenerate-representation +case; and a degenerate index set in which everything is orthogonal to everything. +Then one probe per quantifier — swap it with its neighbour and say whether the +meaning changes — and one per hypothesis — drop it and say what survives. + +This is a coverage requirement, not a quota. Knuth's thirty-one attempts are +worth having because they were systematic, not because they were thirty-one; a +target number manufactures filler. + +Every candidate you explore ends in exactly one disposition, under the rules in +the next section. Read them before filing anything. + +### 5. Prior art + +Locate the object in the formalization landscape and **report only facts**. +Sweep Mathlib (`lean_local_search` and `Grep` over `.lake/packages/mathlib` +first, then `lean_leansearch`, `lean_loogle`, `lean_leanfinder`), this +repository, the Isabelle AFP, Coq/Rocq and mathcomp, and the Lean Zulip archive +for concepts discussed but not landed. + +Each row records: the system, what was found (fully-qualified name where there +is one), **how it relates to the note's variants** — `same as (D2)` / `weaker` / +`stronger` / `unrelated` — the queries you actually ran, and the **Mathlib +revision** it was measured against, taken from `lake-manifest.json`. The +revision stamp is not bookkeeping: "not found in Mathlib" is a statement about a +moving target, and the row expires when the manifest moves. + +Then the boundary. You may report that a concept corresponds to an existing +declaration, that a formalization adopted a particular definitional variant, and +that a result is already proved somewhere. You may not propose how this project +should define, name, or structure anything, and a ` ```lean ` fence anywhere in +your output is a defect in your output. + +## Dispositions and discriminators + +Every candidate formulation ends in exactly one of five dispositions: + +| Disposition | Meaning | Requirement | +|---|---|---| +| `adopted` | the form the note takes forward | exactly one per definition | +| `equivalent` | provably the same under the standing conventions | the source that proves it, or the argument written out | +| `rejected` | ruled out | a typed discriminator, below | +| `preference-only` | no ground found, only taste | say what you tried | +| `open` | neither separated from nor shown equivalent to the adopted form | say what you tried | + +`equivalent` is **not a rejection**: the candidate reappears under +`## Definition` as an alternative phrasing. `preference-only` rows are +**weightless** — they exist so the next run does not re-explore the same ground, +and no other section may cite them. + +A `rejected` row needs a discriminator of one of these five types: + +- **(X1) separating object** — a **named** object satisfying one and not the + other. "Some algebra" is not an object. +- **(X2) degeneracy** — the candidate trivialises, becomes vacuous, or becomes + contradictory on a case it must cover. Name the case. +- **(X3) generality loss** — the candidate drops a case the adopted form covers, + or needs a hypothesis the adopted form does not. Name the case or the + hypothesis. +- **(X4) source disagreement** — a **fetched** source explicitly considers and + discards it. Requires a tier (a)/(b) quote. "No source uses it" is absence of + evidence, not this. +- **(X5) conditional equivalence** — the two coincide only under an assumption + not currently in force. Name the assumption. + +Grounds that are **not** discriminators, and produce `preference-only` at best: + +- "not standard" or "unfamiliar" — that is a lane 1 claim and needs a source; +- "less general" without naming what falls out; +- "equivalent anyway" — that is the `equivalent` disposition, not a rejection; +- **"harder to formalize", "awkward in a proof assistant", "Mathlib has more + lemmas for the other one"** — forbidden outright. Formalization convenience is + outside this skill's scope, and AGENTS.md *Abstraction first* prohibits + weakening a formulation to match what a library happens to provide. + +`open` is not a failure state to be avoided. Without a proof assistant to settle +things by execution, honest non-separation is frequent, and filing it as +`rejected` or `preference-only` would be a lie. An `open` row is the first thing +the eventual implementer needs to see. + +## Refutation role + +When your prompt hands you rows to attack instead of a lane, your job is peer +review in the adversarial sense. Two kinds of target: + +- **Tier (c) and (d) rows.** For each, try to refute it against the fetched + sources and the search tools. Report exactly one of three outcomes: + - **refuted** — with the concrete evidence; + - **survives, promoted to (a) or (b)** — quoting what promoted it; + - **survives at (c)/(d)** — you could neither refute nor ground it. "I could + not refute it" is not a promotion. +- **The adopted general form, and every `rejected` row whose discriminator looks + weak.** Attack the adopted form on three fronts: does a degenerate model + satisfy it trivially; does it fail to cover a standard object from the fetched + literature (AGENTS.md *Abstraction first*); is any hypothesis attached to it + actually provable and therefore not a hypothesis at all (AGENTS.md *Prove what + is provable*). For a `rejected` row, check that the discriminator is of a real + type and that the named object really separates the two — a discriminator that + does not discriminate demotes the row to `preference-only`. + +Verdict per target, plus an overall **form-survives** or **form-holed** with each +hole named and evidenced. Do not add new findings beyond the attack. + +## Output + +Return a structured report summarising your notes file — write there first, +report second. + +- One entry per row: its identifier (`(D#)`, `(R#)`, `(A#)`, `(C#)`, `(X#)`), the + lane, the **evidence tier**, the source key, and the content. Quote sources as + author-title-year, with a locator only where the tier permits one. +- Keep the claim and its grounding as separate sentences. "The source states X" + and "therefore Y" are two statements; report both, in that order. +- If your prompt gave you a forecast, report whether it held. A forecast wrong in + every branch — or a lane that turned out to be the wrong lens for this object — + is **a result to report, not a failure to hide**. +- If your lane has nothing to report, say so explicitly, after the full sweep. +- End with what you did **not** do: the sources you could not open and the rows + that consequently rest on nothing, the searches not run, the checklist items + skipped, the variants sighted and not pursued. The note's + `## Not investigated` section is assembled from these, so an omission here + becomes an invisible risk there. Give the path of your notes file so the + orchestrator can recover it if you do not return. diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 76619a9..20e5976 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,13 @@ "permissions": { "defaultMode": "auto", "allow": [ - "WebFetch(domain:github.com)" + "WebFetch(domain:github.com)", + "WebSearch", + "WebFetch(domain:arxiv.org)", + "WebFetch(domain:ncatlab.org)", + "WebFetch(domain:leanprover.zulipchat.com)", + "WebFetch(domain:www.isa-afp.org)", + "Bash(uv run .claude/skills/math-extract/scripts/ingest.py:*)" ] }, "language": "japanese" diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md new file mode 100644 index 0000000..c3b67c2 --- /dev/null +++ b/.claude/skills/math-extract/SKILL.md @@ -0,0 +1,321 @@ +--- +name: math-extract +description: Extract the mathematics of an object from the literature before any Lean is written — definitional variants and their conventions, results and what they rest on, each hypothesis sorted into provable / model-dependent / open, degenerate cases, and rejected formulations with the object that rules each out — via parallel per-lane `math-extractor` sub-agents. Writes a tracked note under docs/math/; proposes no Lean. +argument-hint: "<mathematical object> [-- arXiv id | pdf path | url]" +disable-model-invocation: true +--- + +Dispatch the extraction to `math-extractor` agents, one per lane, and merge what +they return into one tracked note. The extraction methodology — the lane +definitions, the evidence tiers, the locator rule, the rejection discipline — +lives in `.claude/agents/math-extractor.md`; the note's format lives in +`references/note-format.md`. Never duplicate either here. + +**This skill stops at the mathematics.** The note contains no Lean types, no +`def`/`structure`/`class` sketches, no candidate declaration names, no docstring +drafts, no ` ```lean ` fences. Reporting that Mathlib already contains something +is a fact and belongs in the note; proposing how this project should define +anything does not. A premature Lean sketch is noise at the moment the Lean is +actually written, and step 6 fails the run if one reaches the note. + +For reviewing Lean that already exists, use `math-review` instead. + +## Process + +### 1. Pin the object + +Take the first non-empty option: + +1. An explicit argument — the mathematical object, with optional sources after + `--`. +2. If none, ask. There is no useful default, and extracting the wrong object + costs a full run. + +Derive `<slug>` in English kebab-case from the object's conventional name +(`split-inclusion`, `umegaki-relative-entropy`). Check whether +`docs/math/<slug>.md` already exists: + +- **new** — the note will be created. +- **re-extraction** — read the existing note now. Its `## Rejected + formulations and refuted claims` and `## Sources` tables are **append-only** + and must be carried forward verbatim; every other section will be replaced. + Carry the rejected rows into step 3 as a do-not-re-explore list. + +Read `sources.md` (next to this file) as well — you need the retrieval history +and the locator adjudications before you spend time on a source someone already +failed to obtain. + +Announce the resolved object, the slug, and new-or-re-extraction before doing +anything else, so a wrong reading costs one word to correct. + +*Done when:* the object is stated in one mathematical sentence, the slug is +fixed, the existing note (if any) is in hand, and the announcement is made. + +### 2. Scope and build the corpus + +**Serial. Do not fan out here.** Two reasons, and both are structural: you +cannot write good lane briefs before you know what the literature looks like, +and the PDF converter fails when several conversions run at once. + +Start wide. Read a survey or a recent citing paper first — not to extract from, +but to learn the shape of the field: who defines the object, how many +definitional variants are in circulation, which results matter. This is the +measurement that sizes the run in step 3. + +Then obtain the sources, most faithful first. `references/ingestion.md` owns the +ladder, the commands, and the failure modes; read it when a fetch fails. The +short form: + +1. arXiv LaTeX source — the original text, formulas exactly as written. +2. arXiv HTML. +3. Any other URL. +4. A PDF through the converter — **slow, serial, and not verbatim**. +5. Not obtainable — record it and move on. + +Everything lands in `references/<slug-of-source>/`, which is gitignored. **The +cache is navigation; the note is the product.** Nothing in the cache is a +deliverable and it may be deleted at any time. + +Keep two lists as you go: the **corpus** (source key → cache path → how it was +obtained) and the **unfetchable list** (source key → what was tried). Both go to +every lane in step 3. The unfetchable list is what stops a lane from writing a +theorem number for a book nobody opened. + +**If four or more PDFs need converting, stop and give the user an estimate +before starting.** Conversion is minutes per paper and cannot be parallelised; +that is the user's time to spend, not yours. Sources reachable as arXiv LaTeX do +not count against this. + +*Done when:* the corpus and unfetchable lists are written down, each corpus +entry has a cache path and a provenance, and the scoping read has produced a +first count of definitional variants. + +### 3. Size the run and dispatch + +Count three numbers from step 2: + +- **S** — sources in the corpus. +- **D** — definitional variants sighted. +- **R** — results that will appear in the note. + +| Size | Condition | Lanes | +|---|---|---| +| **small** | D ≤ 1 and S ≤ 2 and R ≤ 3 | **Do not fan out** — see below | +| **medium** | D = 2, or S ≤ 3, or R ≤ 8 | three agents: **1+2**, **3+4**, **5** | +| **large** | D ≥ 3, or S ≥ 4, or R ≥ 9, or the sources disagree irreconcilably | all five, one agent each, plus step 4 | + +At **small**, launch a single `math-extractor` with no lane assigned — its agent +file then has it cover all five lanes itself, in 5–15 tool calls. Continue with +steps 5 and 6, and skip step 4. + +The pairings are not arbitrary. Lanes 1 and 2 read the same source linearly, so +one agent reading once is cheaper than two. Lanes 3 and 4 both need falsifying +models, and splitting them has two agents construct the same object twice. Lane +5's tools are disjoint from everyone else's. + +**Announce the size and the lane set before dispatching**, so a wrong call costs +one word. + +Launch all agents in a single message (Agent tool, +`subagent_type: math-extractor`). Write each prompt as a research memo, not a +task ticket. Every prompt must state: + +- **the assigned lane by number and name, as a role** — "You are one of N + lane-specific extractors running in parallel over this object; work lane K + (<name>) only". Do not restate the lane's definition; the agent file owns it. +- **the object**, in the same one sentence you announced in step 1; +- **the corpus** — source key, cache path, and how it was obtained, for each + entry. Say plainly: *read these paths; do not run the converter; it fails when + run concurrently.* +- **the unfetchable list**, with the rule attached: no locator for anything on + it, and the substitution sentence instead; +- **the relevant rows of `sources.md`**, verbatim — retrieval attempts already + made and locator adjudications already recorded, as a do-not-repeat list; +- **the rejected rows carried forward** from a previous extraction, as a + do-not-re-explore list; +- **the absolute path of the notes file** it must append rows to as it goes: + `<your scratchpad>/math-extract/<slug>/lane-<K>.md`. Pass *your* scratchpad + path, not the agent's — a file written where you cannot read it is no use when + the agent dies; +- **your forecast** — what you expect this lane to find, and why. Require the + agent to **write its own prediction before opening the first source** and to + report the divergence afterwards. A hit saves a sweep; a miss is itself + information, and the written prediction is what exposes anchoring; +- **explicit permission to contradict this brief.** "Every branch of the + forecast was wrong" and "this lane is the wrong lens for this object" are + findings to report, not failures to apologise for. A lane that believes it + must confirm the brief will find a way to. + +If the platform refuses to launch all of them at once, start as many as it +allows and launch the next as each completes. + +**If an agent does not return**, read the notes file you assigned it rather than +dropping its lane. Rows that reached disk are usable; mark the lane partial and +record in `## Not investigated` how far it got. + +*Done when:* every lane has completed, or been declared dead with its notes file +recovered. + +### 4. Refute + +Large runs only. Collect two things: every row at tier **(c)** or **(d)**, and +every `rejected` row whose discriminator looks thin. If there are none, skip. + +Launch one further `math-extractor` in the refutation role. Its agent file +defines the outcomes; hand it the rows and the corpus, and require it to attack +the **adopted general form** as well — vacuity at a degenerate model, a standard +object from the literature the form fails to cover, and any hypothesis attached +to it that is actually provable. + +Dispositions: + +- **refuted** — the row leaves the note, except that a refuted *claim about the + literature* is recorded in `## Rejected formulations and refuted claims` with + the evidence that killed it; +- **promoted to (a)/(b)** — the row stays at its new tier; +- **survives at (c)/(d)** — the row stays, marked `unverified`, and may not + carry the adopted general form on its own; +- **discriminator does not discriminate** — the `rejected` row is demoted to + `preference-only`, which makes it weightless. + +One adversarial pass, not a vote. The tiers already carry the extractor's own +confidence; another vote buys another round of fetching and no new information. + +*Done when:* every collected row has exactly one disposition, and the adopted +general form has been attacked on all three fronts. + +### 5. Merge and write the note + +Write `docs/math/<slug>.md` to the format in `references/note-format.md`. + +Three things are **yours**, not any lane's: + +1. **The adopted general form.** Lane 1 supplies the variants and lane 4 the + discriminators, but they run in parallel and neither sees the other. Write + the paragraph, and cite the discriminator that justifies the choice by its + `(X#)`. If no discriminator justifies it, say that the choice is provisional + — do not manufacture a reason. +2. **The `[ext]` gap.** Compute the set difference between the external results + lane 2 marked and the ones lane 5 actually checked, and put the remainder in + `## Not investigated`. Nobody else can compute it; if you skip it, the note + silently claims coverage it does not have. +3. **`worst-tier`** — the minimum tier over the rows the adopted form and the + main results rest on. Not the average, and not the best. + +On a re-extraction, carry `## Rejected formulations and refuted claims` and +`## Sources` forward verbatim and append to them; replace every other section. +Add a `revisions:` entry. + +Do not soften or drop what the lanes returned. Rows from different lanes that +touch the same object stay separate; only `## Out of lane` items get +de-duplicated. + +*Done when:* the note exists, every section is present, `## Not investigated` is +non-empty, and the append-only tables have lost no rows. + +### 6. Verify, then report + +Run all four checks against the note. **They are the acceptance criteria, not a +formality** — this is the one step that costs your own tool calls rather than an +agent's, and it is worth it, because a fabricated quote or an invented theorem +number is the worst thing this skill can produce. + +1. **Firewall** — `grep -nE '```lean|^\s*(theorem|lemma|def|structure|class|instance|example)\b' docs/math/<slug>.md`. + A Lean fence is a hard fail: remove it. A prose false positive (a sentence + beginning "Definition …") is fine — read the hits, do not just count them. +2. **Quote check** — for every blockquote, `grep -F` its text against the cache + file the row cites. A quote that does not match is downgraded to (b) or + deleted. Report the counts. +3. **Locator check** — no theorem number, section number, page, or equation + number may appear on a tier (c) or (d) row, and every such row must carry the + substitution sentence instead. Check the `[ext: …]` markers and the + `## Sources` rows for anything on the unfetchable list. +4. **Discipline check** — every `model-dependent` hypothesis names a witness + (otherwise it should be `open`); every `rejected` row has a typed + discriminator (otherwise `preference-only`); every degeneracy checklist item + has a row, including the ones with no effect. + +Then update `sources.md`: one row per source attempted this run, and a `Notes` +entry for any locator you adjudicated. **This is the only step that writes to +that file.** + +Report to the user in Japanese, in this shape: + +```markdown +# Math Extract — <object> + +**Note**: `docs/math/<slug>.md` — <new | re-extracted> +**Size**: S=<n> sources · D=<n> variants · R=<n> results → <small|medium|large>, <k> lanes +**Worst tier among load-bearing rows**: (<a|b|c|d>) + +## Adopted general form — 判断を仰ぐ点 +<one paragraph: the form the note adopts and the discriminator that justifies + it. This is the single decision the reader has to make; everything else is + reportable fact.> + +## Checks +- Firewall: <clean | HITS — a defect> +- Quote check: <n>/<n> matched; <n> downgraded; <n> deleted +- Locator check: <n> tier-(c)/(d) rows, all carrying a statement instead of a number +- Discipline: <n> model-dependent rows, all with witnesses; <n> rejected rows, all with typed discriminators + +## Corpus +| Key | How obtained | Cost | +|---|---|---| +<and the sources attempted and not obtained, with what was tried> + +## Discriminators found +<the (X#) rows carrying real weight, one line each, with their type> + +## Per-lane summary +| Lane | rows | forecast | verdict | +|---|---|---|---| +<every lane present, including clean ones; forecast is hit / miss / n.a.> + +## What changed <!-- re-extraction only --> +<what the previous note said that this one contradicts> + +## Refuted <!-- only if step 4 ran and killed something --> +<one line each: the claim and the evidence> + +## Not investigated +<mirrors the note's section, including the [ext] gap computed in step 5> +``` + +Omit an empty optional section; never omit `## Checks`, `## Per-lane summary`, +or `## Not investigated`. + +## Why lanes, not sources + +One agent per source would reconcile nothing. The note's whole value is in the +comparisons — this source defines it that way and that one differently, this +hypothesis is standing there and local here, this result is proved in one place +and asserted in another — and a comparison needs one reader holding both texts +at once. So the lanes cut across the corpus, not through it. + +The cut is by tool budget as much as by topic, which is what keeps the lanes +from duplicating work. Lanes 1 and 2 read the corpus and nothing else. Lane 3 +reads it and argues. Lane 4 constructs objects. Lane 5 is the only one that +searches Mathlib and the web. Two lanes that would contend for the same scarce +tool are paired into one agent at medium size for exactly that reason. + +Conversion is deliberately outside all of this: it is serial, minutes long, and +breaks under concurrency, so it happens once in step 2 and the lanes only read +what it produced. + +## Sources ledger + +`sources.md`, next to this file, is keyed by **source**, while the notes are +keyed by **object**. It holds the three things a note structurally cannot: + +1. **Retrieval attempts** — that a book could not be obtained is true for every + object that cites it, and rediscovering it each time costs the same ten + minutes each time. +2. **Locator adjudications** — when someone finally opens a source and finds + that a widely-copied theorem number does not say what it is said to say, that + correction belongs to the source, not to whichever object was being extracted + that day. It gets recorded once and read forever. +3. **Edition and version drift** — preprint and published numbering, second + editions, arXiv versions. + +Step 1 reads it; step 6 writes it. Nothing else touches it. diff --git a/.claude/skills/math-extract/references/ingestion.md b/.claude/skills/math-extract/references/ingestion.md new file mode 100644 index 0000000..bc64c3a --- /dev/null +++ b/.claude/skills/math-extract/references/ingestion.md @@ -0,0 +1,130 @@ +# Building the corpus + +How `math-extract` obtains source texts, what each rung costs, and what to do +when one fails. `SKILL.md` step 2 points here; read it when a fetch fails or +when a PDF has to be converted. + +Everything lands under `references/<slug>/`, which is gitignored. **The cache is +navigation; the note under `docs/math/` is the product.** Nothing here is a +deliverable and the whole directory may be deleted at any time. + +## The ladder + +```bash +uv run .claude/skills/math-extract/scripts/ingest.py "<arxiv-id | url | path>" +``` + +The script walks the rungs in order and stops at the first that yields text. It +prints a JSON summary and exits 0 on success. + +| Rung | Source | Faithfulness | Cost | +|---|---|---|---| +| 1 | `arxiv.org/e-print/<id>` — LaTeX | **the original text** | seconds | +| 2 | `arxiv.org/html/<id>` — LaTeXML | high; formulas re-rendered | seconds | +| 3 | any other URL, or a local `.html`/`.txt`/`.tex` | tags stripped | seconds | +| 4 | a PDF through MinerU | **model inference, not text** | minutes, serial | +| 5 | not obtainable | — | — | + +**Rung 1 is the reason to check arXiv even for a published paper.** The LaTeX +source is what the author wrote, so a quotation taken from it is verbatim by +construction and reaches tier (a) with no further work. Every other rung +produces a derived text. + +An arXiv *pdf* URL is not a PDF here: the identifier is recovered from it and +rung 1 runs instead. + +## Output + +``` +references/<slug>/ +├── raw/ the bytes as fetched, unmodified +├── source.txt concatenated text, one line per source line +└── source.flat.txt the same, each paragraph flattened onto one line +``` + +**`source.flat.txt` is what the quote check greps.** A sentence in a LaTeX +source is wrapped across several lines, so a verbatim quotation of it matches +nothing in `source.txt`; flattening paragraphs onto single lines is what makes +`grep -F` usable. Measured on `math-ph/0411058`: a real sentence matches in +`source.flat.txt`, fails in `source.txt`, and a sentence with a plausible clause +appended fails in both. + +The JSON summary carries `verbatim: true` exactly when the text came from rung 1. +That flag is the input to the tier rule: quotes from a `verbatim` cache are +(a); quotes from any other rung are (b) until checked against the original. + +## Exit codes + +| Code | Meaning | What to do | +|---|---|---| +| 0 | text cached | proceed | +| 2 | target uninterpretable | fix the argument | +| 3 | every rung failed | record `not retrieved` in `sources.md` with what was tried; every claim resting on the source is capped at tier (d), no locators | +| 4 | fetched but almost no text | treat as not retrieved unless the cache shows otherwise | +| 5 | the source is a PDF | rung 4, below | + +A non-zero exit **does not stop the extraction**. It lowers what can be claimed: +the source joins the unfetchable list, and every lane is told that no locator may +be written for it. + +## Rung 4 — converting a PDF + +Not yet wired into the script. Run it by hand, one PDF at a time. + +```bash +uv tool install "mineru[pipeline]" # first time only +mineru -p <file.pdf> -o references/<slug>/mineru -b pipeline +``` + +Then point the note's rows at the Markdown MinerU produces, and flatten it the +same way the script does if it is going to be quote-checked. + +Things that are easy to get wrong, and cost a lot when got wrong: + +- **`-b pipeline` is not optional here.** MinerU 3.x defaults to + `hybrid-engine`, which expects a GPU. This machine has none. +- **Install `mineru[pipeline]`, not `mineru[all]`.** The `all` extra pulls in + vllm, lmdeploy and mlx — GPU serving stacks that are useless here and large. +- **`-s/--start` and `-e/--end` take a page range.** Converting the twenty pages + that matter instead of a four-hundred-page book is the difference between + minutes and an afternoon. Use it. +- `-f/--formula` and `-t/--table` are already on by default. Leave `-l` unset: + the language is detected, and the option's value list does not include a plain + English code. +- **Conversion is serial.** Concurrent runs hit the per-task timeout and fail. + This is why step 2 of the skill builds the corpus before dispatching lanes, + and why the lane briefs say *do not run the converter*. +- Roughly seven minutes for eighteen pages on CPU; a long paper is half an hour. + **Four or more PDFs means telling the user the estimate first.** +- The models download on first use (`MINERU_MODEL_SOURCE=huggingface|modelscope`, + auto-detected). `mineru-models-download` fetches them ahead of time. +- The container already has `libgl1` and `libglib2.0-0`, which MinerU's OpenCV + dependency needs. + +**A converted PDF is model output, not text.** MinerU's formula recognition can +produce plausible, wrong LaTeX, and presenting that as a verbatim quotation is +the worst failure this skill has. A quote from converted Markdown is tier (b) +with `mineru-unchecked` attached, and reaches (a) only after being compared +against the page image. + +## What is deliberately not used + +- **`pymupdf`, `poppler`, `marker-pdf`** — license-incompatible with this + project. This also means the `Read` tool cannot open PDFs here: it shells out + to `pdftoppm`, which is part of poppler and is not installed. +- **Docling** — its formula model makes no useful progress on CPU, and without + it every equation comes out as a placeholder. For a mathematics corpus that is + the whole content. +- **MinerU's Python API** — the CLI is the stable interface; importing the + library pulls in a far heavier dependency graph. + +Recording this here is the point: the next person to look for a PDF converter +should find out in one place what was already tried and why it was rejected. + +## Rate limits and manners + +arXiv asks for roughly one request every three seconds. The script is serial and +the skill fetches the whole corpus in one pass before dispatching, so this takes +care of itself — but a lane that decides to fetch on its own can violate it. The +lane briefs say to read the cache instead, for this reason as well as the +converter's. diff --git a/.claude/skills/math-extract/references/note-format.md b/.claude/skills/math-extract/references/note-format.md new file mode 100644 index 0000000..28360da --- /dev/null +++ b/.claude/skills/math-extract/references/note-format.md @@ -0,0 +1,322 @@ +# Extraction note format + +The authoritative specification of `docs/math/<slug>.md` — the tracked artefact +the `math-extract` skill produces. `SKILL.md` points here rather than restating +it, so this file is the one place to edit when the format changes. + +Each rule carries the reason it exists where the reason is not self-evident. The +reasons are load-bearing: they are what lets you judge a case the rule does not +literally cover. + +**The note records mathematics.** No Lean types, no `def`/`structure`/`class` +sketches, no candidate declaration names, no docstring drafts, no ` ```lean ` +fences anywhere in the file. A statement that Mathlib contains a declaration is +a fact and is allowed; a suggestion about how this project should define +something is not. + +**One note per object, not per source.** The cache under `references/<slug>/` is +indexed by source; the note is indexed by object; the `## Sources` table is where +the two indices cross. Reconciling several sources into one account is the note's +reason to exist. + +The note is written in **English**, including prose. Verbatim quotes stay in the +source's own language. + +## Skeleton + +````markdown +--- +object: Split inclusion of von Neumann algebras +slug: split-inclusion +status: draft +worst-tier: c +mathlib-rev: <Mathlib rev from lake-manifest.json> +implemented-as: none +revisions: + - 2026-08-14 · <short commit> · initial extraction · sources: DL84, BU74 +--- + +# <Object, as a mathematician names it> + +## What this object is for + +<1–3 sentences: what the object does in the theory, and why its generality + matters. No history essay, no motivation essay, nothing about formalization.> + +## Definition + +### Variants as the sources write them + +**(D1) [DL84] §1** — tier (a) + +> <verbatim quote, in the source's language, unmodified, formulas in the +> source's own notation> + +[tr.] <optional translation, outside the quote, tier (b)> + +**(D2) [BU74]** — tier (b) + +<paraphrase; a locator is permitted at this tier> + +`differs from (D1) by:` <one sentence naming the difference> +`sources claim equivalence:` yes / no / not addressed — <the citation, if yes> + +### Adopted general form + +<Written by the orchestrator at merge time, not by a lane. States the form this + note takes forward and cites the discriminators that justify it — e.g. "(D1), + because (X3) shows (D2) drops the non-σ-finite case that [DL84] §1 covers".> + +## Notation and conventions + +| (C#) | Axis | This note | Per source | Translation | +|---|---|---|---|---| +| (C1) | trace normalisation | unnormalised | [DL84] unnormalised; [BU74] implicit, inferred from §2 eq. (4) | — | + +## Results and dependencies + +### (R1) <short name> + +<the statement, written out in this note's adopted conventions> + +- Source: [DL84] Thm 3.2 · tier (a) · **proved in source** +- Depends on: (R2), (A1), [ext: …] +- Conventions: (C1) +- Verbatim: + > <quote — tier (a) only; must survive the quote check> + +### (R2) … + +## Hypotheses + +| (A#) | Statement | Class | Evidence | Witness | Scope | Tier | Used by | +|---|---|---|---|---|---|---|---| +| (A1) | the net is nuclear | model-dependent | — | <named object where it fails> | local | b | (R1) | +| (A2) | H is separable | provable | [BU74] §1 | — | standing | b | (R1), (R3) | +| (A3) | … | open | could not separate | — | local | c | (R4) | + +## Degeneracies and boundary cases + +| Case | Effect on the adopted form | Tier | +|---|---|---| +| zero object / scalars | … | — | +| finite-dimensional | … | — | +| commutative | … | — | +| non-separable / non-σ-finite | … | — | +| type III | … | — | +| non-unital / degenerate representation | … | — | +| universally orthogonal index element | … | — | +| quantifier swap: ∀…∃… ↦ ∃…∀… | … | — | +| hypothesis dropped: (A1) | … | — | + +## Rejected formulations and refuted claims + +**Append-only.** + +| id | Candidate or claim | Disposition | Discriminator | Tier | Date | +|---|---|---|---|---|---| +| (X1) | <candidate> | rejected | **(X3) generality loss** — <what falls out> | a | 2026-08-14 | +| (X2) | <candidate> | equivalent | — ([BU74] Prop 1.1 proves it under (A2)) | b | 2026-08-14 | +| (X3) | <candidate> | open — could not separate; tried … | — | c | 2026-08-14 | +| (X4) | <candidate> | preference-only — no discriminator found | — | d | 2026-08-14 | +| (X5) | *claim*: <a claim about the literature> | refuted | <the evidence that killed it> | a | 2026-08-14 | + +## Prior art + +| System | Found | Relation to variants | How searched | Measured at | +|---|---|---|---|---| +| Mathlib | `Mathlib.…` | same as (D2) | lean_local_search "…", lean_loogle "…" | mathlib rev `<sha>` | +| Mathlib | could not find <X> | — | <the queries> | mathlib rev `<sha>` | +| Isabelle AFP | — | — | AFP index search "…" | 2026-08-14 | + +## Open questions + +<One line each, pointing at its row. Only what the extraction could not settle.> + +## Sources + +**Append-only.** + +| Key | Work | Status | Cache | Version | Tier reached | Retrieved | +|---|---|---|---|---|---|---| +| DL84 | Doplicher, Longo, *Standard and split inclusions of von Neumann algebras*, Invent. Math. 75 (1984) | retrieved | `references/dl-1984-split/` | published | a | 2026-08-14 | +| TAK-I | Takesaki, *Theory of Operator Algebras I* | not retrieved — tried arXiv, DOI, publisher, zbMATH | — | — | d | 2026-08-14 | + +## Not investigated + +<Never omitted.> +```` + +## Section rules + +### Frontmatter + +- `worst-tier` is the **minimum tier over load-bearing rows** — the rows the + adopted general form and the main results actually rest on. It is the first + thing a reader sees, and it is an honesty indicator: a note whose conclusions + ride on recollection says so at the top. +- `implemented-as` is a **fact-only back-link**, `none` until the object is + implemented and a declaration name afterwards. Writing the name is this + skill's job; checking that the declaration still matches the note is + `math-review`'s job. +- `mathlib-rev` is the Mathlib revision from `lake-manifest.json` at extraction + time. It is what expires the `## Prior art` rows. +- `revisions` carries the history. **The body never does** — a note is the + current best account, not a changelog. + +### What this object is for + +Written by lane 1. Enough for a reader to decide whether this is the object they +mean, and why the generality is the one under discussion. Not a survey. + +### Definition + +- Every variant carries a source, a tier, and a locator where the tier allows + one. **A variant with no source is not a variant** — it belongs under + `## Rejected formulations` as a candidate. +- Never merge two sources' formulations into one row because they look alike, + and never renumber a source's own labels. +- `differs from:` states the difference in one sentence. "Slightly different" is + not a difference. +- `sources claim equivalence:` distinguishes an equivalence the literature + asserts (a citation) from one the note asserts (an argument that must be + written out). +- **Adopted general form** is written by the orchestrator at merge, because the + justification comes from lane 4's discriminators and lane 1 cannot see them + while running in parallel. It may never be justified by formalization + convenience. +- No proposed notation, no identifiers. + +### Notation and conventions + +One row per axis the corpus actually touches; an irrelevant convention pinned +here is noise. The axes that bite in this domain: trace normalisation, the base +of the logarithm, which inner-product argument is conjugate-linear, ℏ = 1, +the range of a summation, unitality, nondegeneracy of representations, and +whether an order symbol is the Löwner order or containment of algebras. + +A convention a source leaves implicit is recorded as implicit, with the passage +the inference came from. That inference is tier (b) at best. + +### Results and dependencies + +- `proof status` ∈ proved in source / sketched / cited elsewhere / asserted. + Cheap to record and it tells the implementer where the real work is. +- Every dependency a source does not prove in the corpus is marked `[ext: …]`. + At tier (c)/(d) it carries no locator and instead carries a one-line statement + of what the external result says — see the substitution rule below. +- One row per result. The same result under two conventions is one row with a + `Conventions:` flag; genuinely different results sharing a name are two rows + plus a lane 1 note. + +### Hypotheses + +- `Class` ∈ `provable` / `model-dependent` / `open`. +- `provable` requires a pointer to a proof — a source and locator, or an + argument written out. A library lacking the supporting lemmas is irrelevant. +- **`model-dependent` requires a named witness object where the hypothesis + fails.** No witness ⇒ the row is `open`, never `model-dependent`. + **Why:** this is the class a later hypothesis field would be justified by, and + AGENTS.md *Prove what is provable; do not defer it* records what happens when + that justification is never demanded: the deferred hypothesis becomes + permanent and the trusted base grows in silence. Demanding a witness at + extraction time is the cheapest place to stop it. +- `Scope` is `standing` (assumed throughout a source) or `local`. Standing + hypotheses receive no dependency edge. +- `Used by` lists the results that need it. A standing hypothesis no result + needs is a finding — say so in the report. + +### Degeneracies and boundary cases + +Every checklist item gets a row, including the ones where nothing happens: "no +effect" is a result, and an unlisted case is an unchecked one. One row per +quantifier swap and per dropped hypothesis. This is coverage, not a quota. + +### Rejected formulations and refuted claims + +- **Append-only. Rows are never deleted.** A changed disposition is edited in + place with a dated note appended: + `rejected → adopted (2026-09-01: the (X1) separating object was mis-stated)`. + **Why:** the record of what was tried and discarded is the part of an + extraction that a later reader cannot reconstruct, and a revision that + silently drops it destroys exactly the thing that makes re-visiting the design + cheap. +- `Disposition` ∈ `adopted` / `equivalent` / `rejected` / `preference-only` / + `open` / `refuted`. +- `rejected` requires a typed discriminator: **(X1) separating object** (named, + not "some algebra") / **(X2) degeneracy** / **(X3) generality loss** / + **(X4) source disagreement** (a fetched source discards it, with a quote) / + **(X5) conditional equivalence**. +- **"Harder to formalize" is never a discriminator**, nor is "not standard" + (that needs a source and belongs under `## Definition`), nor "equivalent + anyway" (that is the `equivalent` disposition). +- `preference-only` rows are weightless and **may not be cited from any other + section**. They exist only so the next run does not re-explore them. +- A formulation some source actually adopts may not be `rejected` here; it is a + variant under `## Definition`, and the most this table may hold is a + discriminator showing the two are inequivalent. + +### Prior art + +- **Facts only.** What exists, and how it relates to the note's variants. No + proposals about how this project should define, name, or structure anything. +- A search miss is recorded as "could not find X, having searched …" — never + "Mathlib has no X". +- Every row carries the Mathlib revision it was measured against. The row is + void once `lake-manifest.json`'s Mathlib revision moves. + +### Sources + +**Append-only.** A source that was attempted and not obtained gets a row anyway, +recording what was tried — "not cited" and "could not be obtained" are different +facts. The cross-object retrieval ledger and the locator adjudications live in +`../sources.md`; this table is the per-note view. + +### Not investigated + +**Never omitted, even when empty.** State: + +- the `[ext: …]` edges from `## Results` that lane 5 never reached; +- the sources listed as not retrieved, and which rows depend on them; +- the degeneracy checklist items skipped, and why; +- the variants sighted during scoping and not pursued; +- and always, **the unexamined base**: the tier (c)/(d) rows that everything + above stands on. + +The risk lives here, not in what was extracted. + +## The three cross-cutting rules + +### Evidence tiers + +| Tier | What the writer had | What the row may contain | +|---|---|---| +| **(a) quoted** | the source in the cache, opened at the passage | a verbatim quote, a full locator, the cache path | +| **(b) read** | the same, passage read | a paraphrase and a full locator | +| **(c) attested** | another fetched source attributes the claim to this one | the claim and the attester's locator | +| **(d) recalled** | nothing | the claim, plus author and title | + +A row's tier is the **minimum** over what it rests on. + +### The locator substitution rule + +> A full locator — theorem number, section, page, equation number — appears only +> at tier (a) or (b). At (c) only the attesting source's locator. At (d) none. +> **A row forbidden a locator must instead state, in one line, what the cited +> result says.** + +**Why:** a number is cheap to fabricate and expensive to check; a statement is +expensive to fabricate and cheap to check. This repository already carries +locators written without the source in hand; the rule exists so the note does +not add more, and so the substituted sentence becomes something a later reader +can actually falsify. + +### The quote check + +> Every blockquote in the note must survive `grep -F` against the corpus cache +> under `references/`. What fails is downgraded to (b) or deleted. + +**Why:** it makes tier (a) mechanically decidable instead of self-reported, at a +cost of seconds. Converted PDFs are model output, not text, so a quote taken +from converted Markdown is (b) with `mineru-unchecked` until compared against +the page image; an arXiv LaTeX source is the original and needs no such check. diff --git a/.claude/skills/math-extract/scripts/ingest.py b/.claude/skills/math-extract/scripts/ingest.py new file mode 100644 index 0000000..a7dd694 --- /dev/null +++ b/.claude/skills/math-extract/scripts/ingest.py @@ -0,0 +1,311 @@ +#!/usr/bin/env python3 +# /// script +# requires-python = ">=3.10" +# dependencies = [] +# /// +"""Fetch one source into the math-extract corpus cache. + +Usage: + uv run .claude/skills/math-extract/scripts/ingest.py <arxiv-id | url | path> + [--slug SLUG] + [--cache-dir DIR] + +Tries the ladder in order and stops at the first rung that yields text: + + 1. arXiv LaTeX source (arxiv.org/e-print/<id>) -- the original text, with + every formula exactly as the author wrote it. Quotes taken from here + need no further checking. + 2. arXiv HTML (arxiv.org/html/<id>) -- LaTeXML output. + 3. Any other URL, or a local .html/.txt/.tex file -- tags stripped. + + A PDF exits 5 without converting: the converter is a separate, slow, serial + rung that is not wired up here yet. See references/ingestion.md. An arXiv + *pdf* URL is not a PDF for this purpose -- the identifier is recovered from + it and rung 1 fetches the LaTeX instead, which is strictly better. + +Writes into <cache-dir>/<slug>/ (default cache-dir: references/, gitignored): + + raw/ the bytes as fetched, unmodified + source.txt concatenated plain text, one line per source line + source.flat.txt the same text with each paragraph flattened onto one line + +`source.flat.txt` is what the skill's quote check greps: a verbatim quotation +spanning a line break in the original matches there and nowhere else. + +Prints a JSON summary to stdout and exits 0 on success. Exit codes: 2 bad +arguments, 3 every rung failed, 4 fetched but effectively empty, 5 the source is +a PDF and needs the converter. +""" + +from __future__ import annotations + +import argparse +import gzip +import io +import json +import re +import sys +import tarfile +import unicodedata +import urllib.error +import urllib.request +from datetime import date +from html.parser import HTMLParser +from pathlib import Path + +USER_AGENT = "math-extract/1.0 (Lean formalization research; contact via repository)" +TIMEOUT = 60 +TEX_SUFFIXES = {".tex", ".ltx", ".bbl"} +MIN_USEFUL_CHARS = 400 + +# 2202.03357 / 2202.03357v2 / math/0604123 / math-ph/0411058v1 +ARXIV_NEW = re.compile(r"(?<!\d)(\d{4}\.\d{4,5})(v\d+)?(?!\d)") +ARXIV_OLD = re.compile(r"([a-z-]+(?:\.[A-Z]{2})?/\d{7})(v\d+)?") + + +class TextExtractor(HTMLParser): + """Collect visible text, dropping script/style and marking block ends.""" + + SKIP = {"script", "style", "noscript", "head", "nav", "footer"} + BLOCK = {"p", "div", "section", "article", "li", "tr", "br", + "h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "pre", "table"} + + def __init__(self) -> None: + super().__init__(convert_charrefs=True) + self.parts: list[str] = [] + self._skip_depth = 0 + + def handle_starttag(self, tag: str, attrs: object) -> None: + if tag in self.SKIP: + self._skip_depth += 1 + elif tag in self.BLOCK: + self.parts.append("\n") + + def handle_endtag(self, tag: str) -> None: + if tag in self.SKIP and self._skip_depth: + self._skip_depth -= 1 + elif tag in self.BLOCK: + self.parts.append("\n") + + def handle_data(self, data: str) -> None: + if not self._skip_depth: + self.parts.append(data) + + def text(self) -> str: + return "".join(self.parts) + + +def fetch(url: str) -> tuple[bytes, str]: + """GET a URL, returning its body and content type.""" + request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT}) + with urllib.request.urlopen(request, timeout=TIMEOUT) as response: + return response.read(), response.headers.get("Content-Type", "") + + +def arxiv_id_of(target: str) -> str | None: + """Recover a bare arXiv identifier from an id, an abs URL, or a pdf URL.""" + if "arxiv.org" in target or not target.startswith(("http://", "https://")): + for pattern in (ARXIV_NEW, ARXIV_OLD): + match = pattern.search(target) + if match: + return match.group(1) + return None + + +def slugify(value: str, limit: int = 60) -> str: + normalised = unicodedata.normalize("NFKD", value).encode("ascii", "ignore").decode() + cleaned = re.sub(r"[^a-zA-Z0-9]+", "-", normalised).strip("-").lower() + return (cleaned[:limit].rstrip("-")) or "source" + + +def derive_slug(target: str, arxiv_id: str | None) -> str: + if arxiv_id: + return "arxiv-" + arxiv_id.replace("/", "-") + if target.startswith(("http://", "https://")): + tail = target.rstrip("/").rsplit("/", 1)[-1] + return slugify(tail or target) + return slugify(Path(target).stem) + + +def flatten(text: str) -> str: + """Collapse each blank-line-separated paragraph onto a single line. + + A quotation that runs across a line break in the source is one contiguous + string here, which is what makes `grep -F` a usable check on it. + """ + paragraphs = re.split(r"\n\s*\n", text) + flattened = (" ".join(paragraph.split()) for paragraph in paragraphs) + return "\n".join(p for p in flattened if p) + "\n" + + +def unpack_eprint(payload: bytes, raw_dir: Path) -> list[tuple[str, str]]: + """Unpack an arXiv e-print into (name, text) pairs of its TeX members.""" + members: list[tuple[str, str]] = [] + try: + with tarfile.open(fileobj=io.BytesIO(payload), mode="r:gz") as archive: + for member in archive.getmembers(): + if not member.isfile(): + continue + if Path(member.name).suffix.lower() not in TEX_SUFFIXES: + continue + handle = archive.extractfile(member) + if handle is None: + continue + body = handle.read().decode("utf-8", errors="replace") + (raw_dir / Path(member.name).name).write_text(body, encoding="utf-8") + members.append((member.name, body)) + except tarfile.ReadError: + # A single-file submission arrives as bare gzip rather than a tarball. + body = gzip.decompress(payload).decode("utf-8", errors="replace") + (raw_dir / "main.tex").write_text(body, encoding="utf-8") + members.append(("main.tex", body)) + # The file carrying \documentclass or \begin{document} comes first: it is + # the one a reader would open, and ordering here orders source.txt. + members.sort(key=lambda item: 0 if re.search( + r"\\documentclass|\\begin\{document\}", item[1]) else 1) + return members + + +def rung_arxiv_source(arxiv_id: str, raw_dir: Path) -> tuple[str, str] | None: + payload, _ = fetch(f"https://arxiv.org/e-print/{arxiv_id}") + if payload[:4] == b"%PDF": + return None # source withdrawn; the HTML rung may still work + members = unpack_eprint(payload, raw_dir) + if not members: + return None + joined = "\n\n".join(f"% ==== {name} ====\n{body}" for name, body in members) + return joined, "arxiv-latex" + + +def rung_html(url: str, raw_dir: Path, stage: str) -> tuple[str, str] | None: + payload, content_type = fetch(url) + if payload[:4] == b"%PDF" or "application/pdf" in content_type: + raise SystemExit(pdf_refusal(url)) + (raw_dir / "page.html").write_bytes(payload) + parser = TextExtractor() + parser.feed(payload.decode("utf-8", errors="replace")) + return parser.text(), stage + + +def rung_local(path: Path, raw_dir: Path) -> tuple[str, str]: + payload = path.read_bytes() + if payload[:4] == b"%PDF": + raise SystemExit(pdf_refusal(str(path))) + (raw_dir / path.name).write_bytes(payload) + body = payload.decode("utf-8", errors="replace") + if path.suffix.lower() in {".html", ".htm"}: + parser = TextExtractor() + parser.feed(body) + return parser.text(), "local-html" + return body, "local-text" + + +def pdf_refusal(target: str) -> int: + report({ + "ok": False, + "reason": "pdf", + "target": target, + "message": "PDF sources need the converter rung, which is not wired up " + "here yet. See .claude/skills/math-extract/references/" + "ingestion.md, and record the source as not retrieved in " + "sources.md if it cannot be obtained another way.", + }) + return 5 + + +def report(payload: dict) -> None: + json.dump(payload, sys.stdout, indent=2, ensure_ascii=False) + sys.stdout.write("\n") + + +def main() -> int: + parser = argparse.ArgumentParser(description="Fetch one source into the corpus cache.") + parser.add_argument("target", help="arXiv id, URL, or local path") + parser.add_argument("--slug", help="override the derived cache slug") + parser.add_argument("--cache-dir", default="references", help="cache root (default: references)") + args = parser.parse_args() + + target = args.target.strip() + if not target: + print("[error] empty target", file=sys.stderr) + return 2 + + arxiv_id = arxiv_id_of(target) + slug = args.slug or derive_slug(target, arxiv_id) + out_dir = Path(args.cache_dir) / slug + raw_dir = out_dir / "raw" + raw_dir.mkdir(parents=True, exist_ok=True) + + attempts: list[dict] = [] + result: tuple[str, str] | None = None + + local_path = Path(target) + if local_path.exists(): + result = rung_local(local_path, raw_dir) + attempts.append({"rung": result[1], "ok": True}) + else: + ladder = [] + if arxiv_id: + ladder.append(("arxiv-latex", lambda: rung_arxiv_source(arxiv_id, raw_dir))) + ladder.append(("arxiv-html", + lambda: rung_html(f"https://arxiv.org/html/{arxiv_id}", raw_dir, "arxiv-html"))) + if target.startswith(("http://", "https://")): + ladder.append(("url-html", lambda: rung_html(target, raw_dir, "url-html"))) + if not ladder: + print(f"[error] cannot interpret target: {target}", file=sys.stderr) + return 2 + + for name, rung in ladder: + try: + result = rung() + except urllib.error.HTTPError as error: + attempts.append({"rung": name, "ok": False, "error": f"HTTP {error.code}"}) + continue + except (urllib.error.URLError, OSError, gzip.BadGzipFile) as error: + attempts.append({"rung": name, "ok": False, "error": str(error)}) + continue + if result is None: + attempts.append({"rung": name, "ok": False, "error": "no text at this rung"}) + continue + attempts.append({"rung": name, "ok": True}) + break + + if result is None: + report({"ok": False, "reason": "unreachable", "slug": slug, + "stage_attempts": attempts, + "message": "Every rung failed. Record the source as not retrieved " + "in sources.md, with what was tried, and cap every claim " + "resting on it at tier (d) — no locators."}) + return 3 + + text, stage = result + (out_dir / "source.txt").write_text(text, encoding="utf-8") + flat = flatten(text) + (out_dir / "source.flat.txt").write_text(flat, encoding="utf-8") + + summary = { + "ok": True, + "slug": slug, + "stage": stage, + "verbatim": stage == "arxiv-latex", + "cache": str(out_dir), + "quote_check_file": str(out_dir / "source.flat.txt"), + "chars": len(text), + "retrieved": date.today().isoformat(), + "arxiv_id": arxiv_id, + "stage_attempts": attempts, + } + if len(flat.strip()) < MIN_USEFUL_CHARS: + summary["ok"] = False + summary["reason"] = "empty" + summary["message"] = ("Fetched, but there is almost no text. Treat the source " + "as not retrieved unless the cache says otherwise.") + report(summary) + return 4 + + report(summary) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.claude/skills/math-extract/sources.md b/.claude/skills/math-extract/sources.md new file mode 100644 index 0000000..89263d6 --- /dev/null +++ b/.claude/skills/math-extract/sources.md @@ -0,0 +1,68 @@ +# Sources ledger + +The `math-extract` skill's memory across runs, keyed by **source**. The notes +under `docs/math/` are keyed by **object**; this file holds what a note +structurally cannot, because it is true of the source no matter which object was +being extracted when it was discovered. + +Step 1 of the skill reads it. Step 6 writes it. Nothing else touches it. + +## What goes in + +**One row per work, not per run.** Three kinds of fact: + +1. **Retrieval attempts.** That a book could not be obtained is true for every + object that cites it. Without this row the next extraction spends the same + ten minutes discovering the same thing. +2. **Locator adjudications.** When someone finally opens a source and finds that + a widely-copied theorem number does not say what it is said to say, the + correction belongs to the source. Recorded once, read forever. This is the + row type that pays for the file. +3. **Edition and version drift.** Preprint versus published numbering, second + editions, arXiv versions. A locator is meaningless without knowing which one + it indexes. + +**What does not go in:** anything about a mathematical object. Definitions, +results, hypotheses, rejected formulations and their discriminators all live in +`docs/math/<slug>.md`. A fact that would change if you were extracting a +different object is in the wrong file. + +## Expiry — read this before trusting a row + +- A **`retrieved`** row does not expire. The text does not change. +- A **`not retrieved`** row expires **six months** after `Last tried`. Paywalls + lift, scans appear, authors post copies. A stale `not retrieved` that stops + someone from trying again is the one real danger of this file, so when in + doubt, try again rather than trust the row. +- A **locator adjudication** does not expire, but it is bound to the edition in + `Version/Ed.`. An adjudication made against the second edition says nothing + about the first. +- An **arXiv** row is bound to its version. When a new version appears, locators + taken from the old one may have moved; the mathematics has not. Only the + locators in notes citing that source are affected. + +## Format + +| Key | Work | Status | Cache | Version/Ed. | Last tried | Notes | +|---|---|---|---|---|---|---| + +- **Key** — the short citation key used in the notes (`DL84`, `TAK-I`, + `BHATIA`). Stable; notes cite it. +- **Work** — author(s), *title*, venue or publisher, year. Enough to identify + the work without a locator. +- **Status** — `retrieved` | `partial` (abstract or fragment only) | + `not retrieved` | `no digital copy known`. +- **Cache** — path under `references/`, or `—`. +- **Version/Ed.** — arXiv version, edition, or `published` / `preprint`. +- **Last tried** — `YYYY-MM-DD` of the most recent retrieval attempt. +- **Notes** — what was tried and where, locator adjudications, numbering drift + between editions. Adjudications are written as + `locator X: says <what it actually says>` or + `locator X: not found in this edition`. + +## Entries + +| Key | Work | Status | Cache | Version/Ed. | Last tried | Notes | +|---|---|---|---|---|---|---| + +<!-- Append below. Newest last. --> diff --git a/AGENTS.md b/AGENTS.md index a992235..ec1c7b3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,6 +6,8 @@ - `QuantumSystem.lean` — aggregate root that re-exports every module. - `scripts/mk_all.lean` — regenerates the aggregate. - `lakefile.toml`, `lean-toolchain`, `lake-manifest.json` — pinned toolchain and manifest. +- `docs/math/` — extraction notes: what the literature says about an object, written + before its Lean. Mathematics only, no Lean. Produced by `/math-extract`. ## Working Principles diff --git a/docs/math/README.md b/docs/math/README.md new file mode 100644 index 0000000..37e22b5 --- /dev/null +++ b/docs/math/README.md @@ -0,0 +1,28 @@ +# Extraction notes + +One note per mathematical object, recording what the literature says about it — +the definitional variants and the conventions behind them, the results and their +dependencies, each hypothesis sorted into provable / model-dependent / open, the +degenerate cases, and the formulations that were rejected together with the +object that rules each one out. + +These notes are written **before** the corresponding Lean, by the `math-extract` +skill. They contain mathematics only: no Lean types, no declaration names, no +docstring drafts. How the object is eventually formalized is decided when it is +formalized, and a note that guessed in advance would only add noise. + +The format is specified in +`.claude/skills/math-extract/references/note-format.md`. The retrieval history +and locator adjudications for the sources these notes cite live in +`.claude/skills/math-extract/sources.md`. Fetched source texts are cached under +`references/`, which is gitignored — the cache is navigation, these notes are +the product. + +## Index + +| Object | Note | Implemented as | +|---|---|---| + +<!-- One row per note. "Implemented as" is a fact recorded after the object is + formalized — the module or declaration that ended up carrying it, or + "none" while it is still only a note. It is a back-link, not a plan. --> From 71dca2cc8d513ca5c6e363d80a6802826954d94d Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 18:01:54 +0000 Subject: [PATCH 082/113] feat: give math-extract's checks the commands they were measured with Step 6 described its four checks in prose. Replace that with the grep and awk invocations that were run against a note deliberately written to violate all four: a fabricated quotation, a theorem number on a tier (d) row, a model-dependent hypothesis with no witness, a rejection resting on "harder to formalize", and a Lean fence. Each check flagged its violations; on the same note with those five defects repaired, all four went silent. Also state that the quote check runs against source.flat.txt of the source the row cites, rather than the cache at large -- matching some other file proves the sentence exists somewhere, which is not the claim being made. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-extract/SKILL.md | 58 +++++++++++++++++++++------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md index c3b67c2..e260a87 100644 --- a/.claude/skills/math-extract/SKILL.md +++ b/.claude/skills/math-extract/SKILL.md @@ -220,20 +220,52 @@ formality** — this is the one step that costs your own tool calls rather than agent's, and it is worth it, because a fabricated quote or an invented theorem number is the worst thing this skill can produce. -1. **Firewall** — `grep -nE '```lean|^\s*(theorem|lemma|def|structure|class|instance|example)\b' docs/math/<slug>.md`. - A Lean fence is a hard fail: remove it. A prose false positive (a sentence - beginning "Definition …") is fine — read the hits, do not just count them. -2. **Quote check** — for every blockquote, `grep -F` its text against the cache - file the row cites. A quote that does not match is downgraded to (b) or - deleted. Report the counts. -3. **Locator check** — no theorem number, section number, page, or equation - number may appear on a tier (c) or (d) row, and every such row must carry the - substitution sentence instead. Check the `[ext: …]` markers and the +The commands below are the detection half; the judgement is yours. Each was +measured against a note written to violate all four, and each flagged the bad +rows without flagging the good ones — but a grep finds candidates, not verdicts, +so read every hit rather than counting them. + +1. **Firewall.** + + ````bash + grep -nE '```lean|^\s*(theorem|lemma|def|structure|class|instance|example)\b' docs/math/<slug>.md + ```` + + A Lean fence is a hard fail: remove it and the material around it. A prose + hit — a sentence opening "Definition of …" — is fine. + +2. **Quote check.** For each blockquote, `grep -F` its text against + **`source.flat.txt` of the source that row cites**, not against the cache at + large: matching some other file proves the sentence exists somewhere, which + is not the claim. Use the flattened file, since a quotation crossing a line + break in the original matches there and nowhere else. A quote that does not + match is downgraded to (b) or deleted. Report the counts. + +3. **Locator check.** + + ```bash + grep -nE 'tier \((c|d)\)' docs/math/<slug>.md | + grep -E 'Theorem|Thm|Lemma|Prop|Cor|§|p\. ?[0-9]|eq\. ?\(' + ``` + + Every hit is a violation: the row must carry the substitution sentence + instead of the number. Then read the `[ext: …]` markers and the `## Sources` rows for anything on the unfetchable list. -4. **Discipline check** — every `model-dependent` hypothesis names a witness - (otherwise it should be `open`); every `rejected` row has a typed - discriminator (otherwise `preference-only`); every degeneracy checklist item - has a row, including the ones with no effect. + +4. **Discipline check.** + + ```bash + awk -F'|' '/model-dependent/ { w=$5; gsub(/^[ \t]+|[ \t]+$/,"",w) + if (w=="" || w=="—" || w=="-") print NR": no witness: "$2 }' docs/math/<slug>.md + awk -F'|' '/\| rejected \|/ { if ($5 !~ /\(X[1-5]\)/) print NR": untyped: "$2 }' docs/math/<slug>.md + grep -niE 'harder to formalize|awkward in a proof assistant|not standard|more lemmas' docs/math/<slug>.md + ``` + + A `model-dependent` row with no witness becomes `open`. A `rejected` row with + no typed discriminator, or resting on a banned ground, becomes + `preference-only`. Then check by eye that every degeneracy checklist item has + a row, including the ones with no effect, and that `## Not investigated` is + present **and** non-empty. Then update `sources.md`: one row per source attempted this run, and a `Notes` entry for any locator you adjudicated. **This is the only step that writes to From 5445ce650b0662a0df71d59b18cabbd3861dfe0d Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 18:02:27 +0000 Subject: [PATCH 083/113] chore: remove the dead pdf-to-knowledge PostToolUse hook The hook pointed at .claude/skills/pdf-to-knowledge/hooks/on_index_change.py, which was deleted in c12df3f. Its [ -f ] guard kept it harmless, so it has been spawning one sh process per Edit/Write since then to check for a file that is never coming back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/settings.json | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index a987c0d..8900c5c 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -6,18 +6,5 @@ "enabledPlugins": { "lean4@lean4-skills": true, "skill-creator@claude-plugins-official": true - }, - "hooks": { - "PostToolUse": [ - { - "matcher": "Edit|Write|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "sh -c 'script=\"${CLAUDE_PROJECT_DIR}/.claude/skills/pdf-to-knowledge/hooks/on_index_change.py\"; [ -f \"$script\" ] && exec python3 \"$script\" || exit 0'" - } - ] - } - ] } } From 3bc841549a8ccd0b37ef0b27a000dd845134595b Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 18:05:37 +0000 Subject: [PATCH 084/113] feat: add the MinerU rung to math-extract ingestion A PDF now converts through MinerU's CPU pipeline, but only when the call passes --allow-mineru, with --pages to convert a range instead of a whole book. Without the flag a PDF exits 5 and states what the conversion would cost; with it but without mineru on PATH it exits 5 and says how to install it. The script never installs anything itself. -b pipeline is passed unconditionally: MinerU 3.x defaults to a GPU backend and this machine has none. The install line is mineru[pipeline], not mineru[all], which pulls vllm and lmdeploy. Converted text is model inference, so the JSON summary carries verbatim: false and a caveat naming the tier consequence -- quotes from a converted cache are (b) with mineru-unchecked until compared against the page image. Everything downstream is unchanged: the converter's Markdown is flattened into source.flat.txt like every other rung, so the quote check works on it too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-extract/SKILL.md | 4 +- .../math-extract/references/ingestion.md | 20 +-- .claude/skills/math-extract/scripts/ingest.py | 123 +++++++++++++++--- 3 files changed, 122 insertions(+), 25 deletions(-) diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md index e260a87..641e24f 100644 --- a/.claude/skills/math-extract/SKILL.md +++ b/.claude/skills/math-extract/SKILL.md @@ -69,7 +69,9 @@ short form: 1. arXiv LaTeX source — the original text, formulas exactly as written. 2. arXiv HTML. 3. Any other URL. -4. A PDF through the converter — **slow, serial, and not verbatim**. +4. A PDF through the converter — **slow, serial, and not verbatim**. Opt-in per + call with `--allow-mineru`, and `--pages START-END` to convert the chapter + that matters rather than the whole book. 5. Not obtainable — record it and move on. Everything lands in `references/<slug-of-source>/`, which is gitignored. **The diff --git a/.claude/skills/math-extract/references/ingestion.md b/.claude/skills/math-extract/references/ingestion.md index bc64c3a..764d45e 100644 --- a/.claude/skills/math-extract/references/ingestion.md +++ b/.claude/skills/math-extract/references/ingestion.md @@ -22,7 +22,7 @@ prints a JSON summary and exits 0 on success. | 1 | `arxiv.org/e-print/<id>` — LaTeX | **the original text** | seconds | | 2 | `arxiv.org/html/<id>` — LaTeXML | high; formulas re-rendered | seconds | | 3 | any other URL, or a local `.html`/`.txt`/`.tex` | tags stripped | seconds | -| 4 | a PDF through MinerU | **model inference, not text** | minutes, serial | +| 4 | a PDF through MinerU, with `--allow-mineru` | **model inference, not text** | minutes, serial | | 5 | not obtainable | — | — | **Rung 1 is the reason to check arXiv even for a published paper.** The LaTeX @@ -59,9 +59,9 @@ That flag is the input to the tier rule: quotes from a `verbatim` cache are |---|---|---| | 0 | text cached | proceed | | 2 | target uninterpretable | fix the argument | -| 3 | every rung failed | record `not retrieved` in `sources.md` with what was tried; every claim resting on the source is capped at tier (d), no locators | +| 3 | every rung failed, or the conversion failed or timed out | record `not retrieved` in `sources.md` with what was tried; every claim resting on the source is capped at tier (d), no locators | | 4 | fetched but almost no text | treat as not retrieved unless the cache shows otherwise | -| 5 | the source is a PDF | rung 4, below | +| 5 | the source is a PDF and `--allow-mineru` was not given, or was given and `mineru` is not installed | rung 4, below | A non-zero exit **does not stop the extraction**. It lowers what can be claimed: the source joins the unfetchable list, and every lane is told that no locator may @@ -69,15 +69,19 @@ be written for it. ## Rung 4 — converting a PDF -Not yet wired into the script. Run it by hand, one PDF at a time. +**Opt-in per call.** A PDF without the flag exits 5 and states what the +conversion would cost; the script never installs the converter for you. ```bash -uv tool install "mineru[pipeline]" # first time only -mineru -p <file.pdf> -o references/<slug>/mineru -b pipeline +uv tool install "mineru[pipeline]" # first time only +uv run .claude/skills/math-extract/scripts/ingest.py <file.pdf> --allow-mineru +uv run .claude/skills/math-extract/scripts/ingest.py <file.pdf> --allow-mineru --pages 40-62 ``` -Then point the note's rows at the Markdown MinerU produces, and flatten it the -same way the script does if it is going to be quote-checked. +The script runs `mineru -b pipeline`, takes the largest Markdown file produced, +and writes `source.txt` and `source.flat.txt` from it exactly as for the other +rungs — so the quote check works the same way. The JSON summary comes back with +`verbatim: false` and a `caveat` field spelling out the tier consequence. Things that are easy to get wrong, and cost a lot when got wrong: diff --git a/.claude/skills/math-extract/scripts/ingest.py b/.claude/skills/math-extract/scripts/ingest.py index a7dd694..c75c992 100644 --- a/.claude/skills/math-extract/scripts/ingest.py +++ b/.claude/skills/math-extract/scripts/ingest.py @@ -9,6 +9,8 @@ uv run .claude/skills/math-extract/scripts/ingest.py <arxiv-id | url | path> [--slug SLUG] [--cache-dir DIR] + [--allow-mineru] + [--pages START-END] Tries the ladder in order and stops at the first rung that yields text: @@ -18,10 +20,13 @@ 2. arXiv HTML (arxiv.org/html/<id>) -- LaTeXML output. 3. Any other URL, or a local .html/.txt/.tex file -- tags stripped. - A PDF exits 5 without converting: the converter is a separate, slow, serial - rung that is not wired up here yet. See references/ingestion.md. An arXiv - *pdf* URL is not a PDF for this purpose -- the identifier is recovered from - it and rung 1 fetches the LaTeX instead, which is strictly better. + 4. A PDF through MinerU's CPU pipeline, but only with --allow-mineru. It + costs minutes, runs one document at a time, and produces model inference + rather than text, so it is opt-in per call and the script will never + install the converter itself. Without the flag a PDF exits 5 and says + what the conversion would cost. An arXiv *pdf* URL is not a PDF for this + purpose: the identifier is recovered from it and rung 1 fetches the LaTeX + instead, which is strictly better. Writes into <cache-dir>/<slug>/ (default cache-dir: references/, gitignored): @@ -44,20 +49,32 @@ import io import json import re +import shutil +import subprocess import sys import tarfile import unicodedata import urllib.error import urllib.request +from dataclasses import dataclass from datetime import date from html.parser import HTMLParser from pathlib import Path USER_AGENT = "math-extract/1.0 (Lean formalization research; contact via repository)" TIMEOUT = 60 +MINERU_TIMEOUT = 3600 TEX_SUFFIXES = {".tex", ".ltx", ".bbl"} MIN_USEFUL_CHARS = 400 + +@dataclass(frozen=True) +class Options: + """Choices the rungs need that are not part of the target itself.""" + + allow_mineru: bool = False + pages: str | None = None + # 2202.03357 / 2202.03357v2 / math/0604123 / math-ph/0411058v1 ARXIV_NEW = re.compile(r"(?<!\d)(\d{4}\.\d{4,5})(v\d+)?(?!\d)") ARXIV_OLD = re.compile(r"([a-z-]+(?:\.[A-Z]{2})?/\d{7})(v\d+)?") @@ -177,20 +194,20 @@ def rung_arxiv_source(arxiv_id: str, raw_dir: Path) -> tuple[str, str] | None: return joined, "arxiv-latex" -def rung_html(url: str, raw_dir: Path, stage: str) -> tuple[str, str] | None: +def rung_html(url: str, raw_dir: Path, stage: str, opts: Options) -> tuple[str, str] | None: payload, content_type = fetch(url) if payload[:4] == b"%PDF" or "application/pdf" in content_type: - raise SystemExit(pdf_refusal(url)) + return handle_pdf_bytes(payload, raw_dir, "downloaded.pdf", url, opts) (raw_dir / "page.html").write_bytes(payload) parser = TextExtractor() parser.feed(payload.decode("utf-8", errors="replace")) return parser.text(), stage -def rung_local(path: Path, raw_dir: Path) -> tuple[str, str]: +def rung_local(path: Path, raw_dir: Path, opts: Options) -> tuple[str, str] | None: payload = path.read_bytes() if payload[:4] == b"%PDF": - raise SystemExit(pdf_refusal(str(path))) + return handle_pdf_bytes(payload, raw_dir, path.name, str(path), opts) (raw_dir / path.name).write_bytes(payload) body = payload.decode("utf-8", errors="replace") if path.suffix.lower() in {".html", ".htm"}: @@ -200,19 +217,79 @@ def rung_local(path: Path, raw_dir: Path) -> tuple[str, str]: return body, "local-text" +def handle_pdf_bytes(payload: bytes, raw_dir: Path, name: str, + target: str, opts: Options) -> tuple[str, str]: + """Send a PDF to the converter, or refuse and say what it would cost.""" + if not opts.allow_mineru: + raise SystemExit(pdf_refusal(target)) + pdf_path = raw_dir / name + pdf_path.write_bytes(payload) + return rung_mineru(pdf_path, raw_dir.parent, opts) + + def pdf_refusal(target: str) -> int: report({ "ok": False, "reason": "pdf", "target": target, - "message": "PDF sources need the converter rung, which is not wired up " - "here yet. See .claude/skills/math-extract/references/" - "ingestion.md, and record the source as not retrieved in " - "sources.md if it cannot be obtained another way.", + "message": "This source is a PDF. Converting it is rung 4: minutes of CPU, " + "one document at a time, and the result is model output rather " + "than text, so quotes taken from it are tier (b) until checked " + "against the page image. Re-run with --allow-mineru (and " + "--pages START-END where only part of the document is needed) " + "once that cost is agreed. See references/ingestion.md.", }) return 5 +def rung_mineru(pdf_path: Path, out_dir: Path, opts: Options) -> tuple[str, str]: + """Convert a PDF with MinerU's CPU pipeline. Never installs anything.""" + binary = shutil.which("mineru") + if binary is None: + report({ + "ok": False, + "reason": "mineru-missing", + "target": str(pdf_path), + "message": "mineru is not on PATH. Install it with " + "`uv tool install \"mineru[pipeline]\"` — the pipeline extra, " + "not [all], which pulls GPU serving stacks this machine " + "cannot use. This script will not install it for you.", + }) + raise SystemExit(5) + + mineru_dir = out_dir / "mineru" + mineru_dir.mkdir(parents=True, exist_ok=True) + # -b pipeline is not optional: MinerU 3.x defaults to a GPU backend. + command = [binary, "-p", str(pdf_path), "-o", str(mineru_dir), "-b", "pipeline"] + if opts.pages: + start, _, end = opts.pages.partition("-") + command += ["-s", start] + if end: + command += ["-e", end] + + try: + completed = subprocess.run(command, capture_output=True, text=True, + timeout=MINERU_TIMEOUT) + except subprocess.TimeoutExpired: + report({"ok": False, "reason": "mineru-timeout", "target": str(pdf_path), + "message": f"Conversion exceeded {MINERU_TIMEOUT}s. Convert a page " + "range with --pages instead of the whole document."}) + raise SystemExit(3) + if completed.returncode != 0: + report({"ok": False, "reason": "mineru-failed", "target": str(pdf_path), + "returncode": completed.returncode, + "message": completed.stderr[-800:] or "no stderr"}) + raise SystemExit(3) + + markdowns = sorted(mineru_dir.rglob("*.md"), key=lambda p: p.stat().st_size, reverse=True) + if not markdowns: + report({"ok": False, "reason": "mineru-empty", "target": str(pdf_path), + "message": "The converter produced no Markdown. A scanned document " + "may need OCR; see references/ingestion.md."}) + raise SystemExit(4) + return markdowns[0].read_text(encoding="utf-8", errors="replace"), "mineru" + + def report(payload: dict) -> None: json.dump(payload, sys.stdout, indent=2, ensure_ascii=False) sys.stdout.write("\n") @@ -223,12 +300,19 @@ def main() -> int: parser.add_argument("target", help="arXiv id, URL, or local path") parser.add_argument("--slug", help="override the derived cache slug") parser.add_argument("--cache-dir", default="references", help="cache root (default: references)") + parser.add_argument("--allow-mineru", action="store_true", + help="permit rung 4 (PDF conversion): minutes of CPU, serial, " + "and the output is model inference rather than text") + parser.add_argument("--pages", metavar="START-END", + help="page range for rung 4, e.g. 40-62 — convert the chapter " + "that matters instead of the whole book") args = parser.parse_args() target = args.target.strip() if not target: print("[error] empty target", file=sys.stderr) return 2 + opts = Options(allow_mineru=args.allow_mineru, pages=args.pages) arxiv_id = arxiv_id_of(target) slug = args.slug or derive_slug(target, arxiv_id) @@ -241,16 +325,18 @@ def main() -> int: local_path = Path(target) if local_path.exists(): - result = rung_local(local_path, raw_dir) - attempts.append({"rung": result[1], "ok": True}) + result = rung_local(local_path, raw_dir, opts) + if result is not None: + attempts.append({"rung": result[1], "ok": True}) else: ladder = [] if arxiv_id: ladder.append(("arxiv-latex", lambda: rung_arxiv_source(arxiv_id, raw_dir))) ladder.append(("arxiv-html", - lambda: rung_html(f"https://arxiv.org/html/{arxiv_id}", raw_dir, "arxiv-html"))) + lambda: rung_html(f"https://arxiv.org/html/{arxiv_id}", + raw_dir, "arxiv-html", opts))) if target.startswith(("http://", "https://")): - ladder.append(("url-html", lambda: rung_html(target, raw_dir, "url-html"))) + ladder.append(("url-html", lambda: rung_html(target, raw_dir, "url-html", opts))) if not ladder: print(f"[error] cannot interpret target: {target}", file=sys.stderr) return 2 @@ -295,6 +381,11 @@ def main() -> int: "arxiv_id": arxiv_id, "stage_attempts": attempts, } + if stage == "mineru": + summary["caveat"] = ("Converted, not transcribed: the formulas are model " + "output. Quotes from this cache are tier (b) with " + "mineru-unchecked, and reach (a) only after being " + "compared against the page image.") if len(flat.strip()) < MIN_USEFUL_CHARS: summary["ok"] = False summary["reason"] = "empty" From c7fa2aa2411ca49ddf56f9a10ea6da542d1fc3f4 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 18:26:46 +0000 Subject: [PATCH 085/113] build: pass the host GPU to the devcontainer and persist mineru caches runArgs --gpus all hands the host GPU to the container; Docker Desktop bundles the NVIDIA runtime, so no host-side toolkit work is needed. The setting takes effect on the next rebuild, and a rebuild wipes the running session, so the post-rebuild verification procedure lives in .devcontainer/gpu-verification.md where it survives: nvidia-smi, the torch CUDA probe, a timed reconversion, the hybrid-engine trial with its OOM fallback, and the failure triage table. Two named volumes keep rebuilds cheap: hf-models holds MinerU's downloaded models and uv-cache holds the wheel cache (torch alone is ~2GB). The converter itself installs in onCreateCommand as a uv tool -- deliberately not a pyproject.toml dependency, since its hard pins and few hundred packages have no business in the venv the commit hooks run from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .devcontainer/devcontainer.json | 13 ++++- .devcontainer/gpu-verification.md | 91 +++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 .devcontainer/gpu-verification.md diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 84b5133..d9f8cd5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,9 +17,18 @@ }, "ghcr.io/thamaji/devcontainer-features/gitleaks:latest": {} }, - "onCreateCommand": "rm -rf .lake/ && lake exe cache get && uv sync && uv run lefthook install", + "onCreateCommand": "rm -rf .lake/ && lake exe cache get && uv sync && uv run lefthook install && uv tool install \"mineru[pipeline,vlm]\"", + // Pass the host GPU through (Docker Desktop bundles the NVIDIA runtime). + // If the container fails to start on a machine without a GPU, drop this line. + "runArgs": [ + "--gpus", + "all" + ], "mounts": [ - "source=lean-project-commandhistory,target=/commandhistory,type=volume" + "source=lean-project-commandhistory,target=/commandhistory,type=volume", + // MinerU models (~1.5-4GB) and uv's wheel cache (torch ~2GB) survive rebuilds. + "source=hf-models,target=/home/vscode/.cache/huggingface,type=volume", + "source=uv-cache,target=/home/vscode/.cache/uv,type=volume" ], // Configure tool-specific properties. "customizations": { diff --git a/.devcontainer/gpu-verification.md b/.devcontainer/gpu-verification.md new file mode 100644 index 0000000..5a0cf9e --- /dev/null +++ b/.devcontainer/gpu-verification.md @@ -0,0 +1,91 @@ +# GPU 有効化後の確認手順 + +devcontainer に GPU を渡す設定(`devcontainer.json` の `"runArgs": ["--gpus", "all"]`) +は**コンテナの再ビルドで初めて効く**。再ビルドすると実行中のセッションは消えるため、 +この確認手順をワークスペース内に残している。**このファイルだけ読めば、GPU が正しく +使えているかを判定できる**ように書いてある。 + +前提: ホストは Windows + Docker Desktop(NVIDIA ランタイム同梱)、GPU は VRAM 8GB。 +Windows 側に NVIDIA ドライバが入っていればよく、**WSL やコンテナの中に Linux 用 +ドライバを入れてはいけない**(壊れる)。 + +## 1. 再ビルド + +VS Code のコマンドパレット → **Dev Containers: Rebuild Container**。 + +`onCreateCommand` が `lake exe cache get` と `uv tool install "mineru[pipeline,vlm]"` +を再実行する。mineru の wheel(torch 含む ~4GB)は `uv-cache` volume に、モデルは +`hf-models` volume にキャッシュされているので、2 回目以降の再ビルドは大幅に速い。 + +## 2. GPU がコンテナに見えているか + +```bash +nvidia-smi +``` + +**期待**: GPU 名と `8192MiB` 前後のメモリ表を表示。 +`command not found` や `Failed to initialize NVML` の場合は §6 へ。 + +## 3. torch が CUDA を認識しているか + +torch は mineru の tool 環境に入っている(プロジェクト venv ではない)ので: + +```bash +~/.local/share/uv/tools/mineru/bin/python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else '-')" +``` + +**期待**: `True <GPU 名>`。 +`False` の場合: `nvidia-smi` が通っているなら torch のビルド違いを疑う +(`...bin/python -c "import torch; print(torch.version.cuda)"` が `None` なら +CPU 版 wheel が入っている。`uv tool install --reinstall "mineru[pipeline,vlm]"` で +入れ直す。Linux の既定 wheel は CUDA 同梱なので通常はここに落ちない)。 + +## 4. 実 PDF の変換が GPU で速くなっているか + +CPU での実測基準(このコンテナ、20 コア、5 ページの PDF): **モデルロード後の +変換だけで数分**。GPU なら同じ PDF が **数十秒以内**に落ちるはず。 + +```bash +time uv run .claude/skills/math-extract/scripts/ingest.py <PDFのパスかURL> \ + --allow-mineru --cache-dir /tmp/gpu-check +``` + +**期待**: +- JSON に `"stage": "mineru-pipeline"`、`"ok": true`。 +- mineru のログ(stderr)にデバイスとして `cuda` が現れる。 +- 所要時間が CPU 時より明確に短い。 + +初回はモデルのダウンロード(~1.5GB)が走る。`hf-models` volume に入るので 2 回目 +以降は走らない。事前に落としておきたい場合は `mineru-models-download`。 + +## 5.(任意)hybrid-engine を試す + +精度 95%(pipeline は 86%)だが、**VRAM 8GB はこのバックエンドの最低ラインで、 +しかも Windows デスクトップと共有**のため OOM しうる。試すなら: + +```bash +uv run .claude/skills/math-extract/scripts/ingest.py <PDF> \ + --allow-mineru --backend hybrid-engine --effort high --cache-dir /tmp/gpu-check +``` + +- **成功したら**: 数式が濃い文献ではこちらを使う価値がある。VRAM に余裕を作るには + 実行前に Windows 側の GPU 消費(ブラウザのハードウェアアクセラレーション等)を + 減らす。 +- **`CUDA out of memory` で落ちたら**: `--backend` を外して pipeline に戻す(既定)。 + ingest.py の既定が pipeline なのはこのためで、設定変更は不要。 + +## 6. 失敗時の切り分け + +| 症状 | 原因と対処 | +|---|---| +| 再ビルドでコンテナ自体が起動しない(`could not select device driver "" with capabilities: [[gpu]]`) | Docker Desktop → Settings → General で WSL 2 based engine を確認。Windows 側 NVIDIA ドライバが古い場合は更新。**応急処置**: `devcontainer.json` の `runArgs` 2 行を削って再ビルドすれば従来どおり CPU で動く | +| コンテナは起動するが `nvidia-smi` が無い / NVML エラー | Docker Desktop を再起動 → WSL を `wsl --shutdown` してから Docker Desktop を起動し直す。それでも駄目なら Windows 側ドライバを更新 | +| `torch.cuda.is_available()` が `False`(`nvidia-smi` は通る) | §3 の CPU wheel チェック。torch が CUDA 版なら Docker Desktop の GPU support 設定と再起動 | +| mineru がモデルダウンロードで止まる | ネットワーク。`MINERU_MODEL_SOURCE=modelscope` を試す(既定 auto は HuggingFace 優先) | +| 変換が CPU 時と同じくらい遅い | mineru のログに `cpu` と出ていないか確認。§3 が `True` でこれが起きるなら issue 級なので報告を | + +## 7. 確認が全部通ったら + +このファイルの手順は以後も再ビルドのたびに使えるので消さなくてよい。 +`math-extract` スキル側の GPU 関連の記述は +`.claude/skills/math-extract/references/ingestion.md` の Rung 4 にある。 From 31c624a75666403b7564460b4066ffbf3a08b722 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 18:31:32 +0000 Subject: [PATCH 086/113] feat: wire backend and effort selection into math-extract ingestion ingest.py grows --backend {auto,pipeline,hybrid-engine,vlm-engine} and --effort {medium,high}. auto resolves to pipeline even on GPU: torch picks up CUDA on its own, so pipeline gets the speedup with no configuration, while the VLM backends stay opt-in -- 8GB of VRAM is their minimum and it is shared with the Windows desktop, so they can OOM where pipeline cannot. --effort is forwarded only to the VLM backends, which are the only ones that take it. The JSON summary now names the backend used. Measured end-to-end on a five-page PDF with the CPU pipeline: 2m52s including the first-run model download, formulas out as LaTeX, and the quote check behaves on the converted text -- a real sentence matches source.flat.txt, a fabricated one does not. Same run surfaced a fidelity example now recorded in ingestion.md: Knuth's small-caps byline came out as D<sub>on</sub> K<sub>nu</sub>th, which is exactly why converted quotes stay tier (b). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../math-extract/references/ingestion.md | 65 ++++++++++++++----- .claude/skills/math-extract/scripts/ingest.py | 50 +++++++++++--- 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/.claude/skills/math-extract/references/ingestion.md b/.claude/skills/math-extract/references/ingestion.md index 764d45e..bb1be00 100644 --- a/.claude/skills/math-extract/references/ingestion.md +++ b/.claude/skills/math-extract/references/ingestion.md @@ -73,35 +73,63 @@ be written for it. conversion would cost; the script never installs the converter for you. ```bash -uv tool install "mineru[pipeline]" # first time only uv run .claude/skills/math-extract/scripts/ingest.py <file.pdf> --allow-mineru uv run .claude/skills/math-extract/scripts/ingest.py <file.pdf> --allow-mineru --pages 40-62 ``` -The script runs `mineru -b pipeline`, takes the largest Markdown file produced, -and writes `source.txt` and `source.flat.txt` from it exactly as for the other -rungs — so the quote check works the same way. The JSON summary comes back with -`verbatim: false` and a `caveat` field spelling out the tier consequence. +The devcontainer installs the converter in `onCreateCommand` +(`uv tool install --with six "mineru[pipeline,vlm]"` — the `--with six` works +around mineru 3.4.5's pipeline importing `six` without declaring it, which +otherwise fails every conversion with `No module named 'six'`); if the binary +is missing, the container predates that — run the same command by hand. It is a `uv tool`, not +a `pyproject.toml` dependency, on purpose: mineru drags torch and a few hundred +packages with hard version pins, and none of that belongs in the project venv +that the commit hooks run from. + +The script takes the largest Markdown file MinerU produces and writes +`source.txt` and `source.flat.txt` from it exactly as for the other rungs — so +the quote check works the same way. The JSON summary comes back with +`verbatim: false`, the `backend` used, and a `caveat` field spelling out the +tier consequence. + +### GPU + +The devcontainer passes the host GPU through (`"runArgs": ["--gpus", "all"]`, +Docker Desktop provides the runtime). **The setting takes effect on a container +rebuild**; the post-rebuild verification procedure lives in +`.devcontainer/gpu-verification.md` and is deliberately self-contained. + +- **The default backend stays `pipeline` even on GPU.** torch picks up CUDA by + itself, so pipeline gets the speedup with no configuration and cannot OOM the + way the VLM backends can. +- `--backend hybrid-engine --effort high` opts into the higher-accuracy VLM + path. **This machine's 8GB of VRAM is that backend's minimum, shared with the + Windows desktop** — on `CUDA out of memory`, drop the flag and rerun; the + pipeline result is the fallback, not a failure. +- Models land in `~/.cache/huggingface`, which is a named volume (`hf-models`), + so they survive rebuilds. `mineru-models-download` fetches them ahead of + time; `MINERU_MODEL_SOURCE` can force `huggingface`/`modelscope` (leave it + unset for auto). Things that are easy to get wrong, and cost a lot when got wrong: -- **`-b pipeline` is not optional here.** MinerU 3.x defaults to - `hybrid-engine`, which expects a GPU. This machine has none. -- **Install `mineru[pipeline]`, not `mineru[all]`.** The `all` extra pulls in - vllm, lmdeploy and mlx — GPU serving stacks that are useless here and large. -- **`-s/--start` and `-e/--end` take a page range.** Converting the twenty pages - that matter instead of a four-hundred-page book is the difference between - minutes and an afternoon. Use it. +- **The script always passes `-b` explicitly.** MinerU 3.x defaults to + `hybrid-engine`, which is the wrong default at 8GB of shared VRAM. +- **Install `mineru[pipeline,vlm]`, not `mineru[all]`.** The `all` extra pulls + in vllm, lmdeploy and mlx — serving stacks that are useless here and large. + `[core]` would also work but drags in gradio. +- **`--pages START-END` takes a page range.** Converting the twenty pages that + matter instead of a four-hundred-page book is the difference between minutes + and an afternoon. Use it. - `-f/--formula` and `-t/--table` are already on by default. Leave `-l` unset: the language is detected, and the option's value list does not include a plain English code. - **Conversion is serial.** Concurrent runs hit the per-task timeout and fail. This is why step 2 of the skill builds the corpus before dispatching lanes, and why the lane briefs say *do not run the converter*. -- Roughly seven minutes for eighteen pages on CPU; a long paper is half an hour. - **Four or more PDFs means telling the user the estimate first.** -- The models download on first use (`MINERU_MODEL_SOURCE=huggingface|modelscope`, - auto-detected). `mineru-models-download` fetches them ahead of time. +- Roughly seven minutes for eighteen pages on CPU, far less on GPU; a long + paper on CPU is half an hour. **Four or more PDFs means telling the user the + estimate first.** - The container already has `libgl1` and `libglib2.0-0`, which MinerU's OpenCV dependency needs. @@ -109,7 +137,10 @@ Things that are easy to get wrong, and cost a lot when got wrong: produce plausible, wrong LaTeX, and presenting that as a verbatim quotation is the worst failure this skill has. A quote from converted Markdown is tier (b) with `mineru-unchecked` attached, and reaches (a) only after being compared -against the page image. +against the page image. Measured example: on a five-page paper set in Knuth's +small-caps font, the CPU pipeline rendered the byline as +`D<sub>on</sub> K<sub>nu</sub>th` — ordinary body text and formulas came out +clean, but unusual typography gets mangled silently. ## What is deliberately not used diff --git a/.claude/skills/math-extract/scripts/ingest.py b/.claude/skills/math-extract/scripts/ingest.py index c75c992..a0f30ba 100644 --- a/.claude/skills/math-extract/scripts/ingest.py +++ b/.claude/skills/math-extract/scripts/ingest.py @@ -11,6 +11,7 @@ [--cache-dir DIR] [--allow-mineru] [--pages START-END] + [--backend B] [--effort E] Tries the ladder in order and stops at the first rung that yields text: @@ -74,6 +75,8 @@ class Options: allow_mineru: bool = False pages: str | None = None + backend: str = "auto" + effort: str | None = None # 2202.03357 / 2202.03357v2 / math/0604123 / math-ph/0411058v1 ARXIV_NEW = re.compile(r"(?<!\d)(\d{4}\.\d{4,5})(v\d+)?(?!\d)") @@ -242,8 +245,20 @@ def pdf_refusal(target: str) -> int: return 5 +def resolve_backend(opts: Options) -> str: + """Pick the mineru backend. + + `auto` resolves to `pipeline` regardless of GPU: torch uses CUDA on its own + when the device is there, so pipeline is fast on GPU and correct on CPU. + The VLM-based backends (`hybrid-engine`, `vlm-engine`) are opt-in — this + machine's 8GB of VRAM is their minimum, shared with the Windows desktop, + so they can OOM where pipeline cannot. + """ + return "pipeline" if opts.backend == "auto" else opts.backend + + def rung_mineru(pdf_path: Path, out_dir: Path, opts: Options) -> tuple[str, str]: - """Convert a PDF with MinerU's CPU pipeline. Never installs anything.""" + """Convert a PDF with MinerU. Never installs anything.""" binary = shutil.which("mineru") if binary is None: report({ @@ -251,16 +266,23 @@ def rung_mineru(pdf_path: Path, out_dir: Path, opts: Options) -> tuple[str, str] "reason": "mineru-missing", "target": str(pdf_path), "message": "mineru is not on PATH. Install it with " - "`uv tool install \"mineru[pipeline]\"` — the pipeline extra, " - "not [all], which pulls GPU serving stacks this machine " - "cannot use. This script will not install it for you.", + "`uv tool install \"mineru[pipeline,vlm]\"` — not [all], " + "which pulls the vllm/lmdeploy serving stacks. The " + "devcontainer installs it in onCreateCommand, so a missing " + "binary usually means the container predates that. This " + "script will not install it for you.", }) raise SystemExit(5) mineru_dir = out_dir / "mineru" mineru_dir.mkdir(parents=True, exist_ok=True) - # -b pipeline is not optional: MinerU 3.x defaults to a GPU backend. - command = [binary, "-p", str(pdf_path), "-o", str(mineru_dir), "-b", "pipeline"] + # The backend is always passed explicitly: MinerU 3.x defaults to + # hybrid-engine, which is not the right default at 8GB of shared VRAM. + backend = resolve_backend(opts) + command = [binary, "-p", str(pdf_path), "-o", str(mineru_dir), "-b", backend] + if opts.effort and backend != "pipeline": + # --effort steers the VLM backends only; pipeline does not take it. + command += ["--effort", opts.effort] if opts.pages: start, _, end = opts.pages.partition("-") command += ["-s", start] @@ -287,7 +309,7 @@ def rung_mineru(pdf_path: Path, out_dir: Path, opts: Options) -> tuple[str, str] "message": "The converter produced no Markdown. A scanned document " "may need OCR; see references/ingestion.md."}) raise SystemExit(4) - return markdowns[0].read_text(encoding="utf-8", errors="replace"), "mineru" + return markdowns[0].read_text(encoding="utf-8", errors="replace"), f"mineru-{backend}" def report(payload: dict) -> None: @@ -306,13 +328,22 @@ def main() -> int: parser.add_argument("--pages", metavar="START-END", help="page range for rung 4, e.g. 40-62 — convert the chapter " "that matters instead of the whole book") + parser.add_argument("--backend", choices=["auto", "pipeline", "hybrid-engine", "vlm-engine"], + default="auto", + help="mineru backend for rung 4. auto = pipeline (uses the GPU " + "by itself when one is there). The VLM backends are " + "opt-in: 8GB of VRAM is their minimum and it is shared " + "with the Windows desktop, so they can OOM") + parser.add_argument("--effort", choices=["medium", "high"], + help="rung 4 quality knob, forwarded only to the VLM backends") args = parser.parse_args() target = args.target.strip() if not target: print("[error] empty target", file=sys.stderr) return 2 - opts = Options(allow_mineru=args.allow_mineru, pages=args.pages) + opts = Options(allow_mineru=args.allow_mineru, pages=args.pages, + backend=args.backend, effort=args.effort) arxiv_id = arxiv_id_of(target) slug = args.slug or derive_slug(target, arxiv_id) @@ -381,7 +412,8 @@ def main() -> int: "arxiv_id": arxiv_id, "stage_attempts": attempts, } - if stage == "mineru": + if stage.startswith("mineru"): + summary["backend"] = stage.removeprefix("mineru-") summary["caveat"] = ("Converted, not transcribed: the formulas are model " "output. Quotes from this cache are tier (b) with " "mineru-unchecked, and reach (a) only after being " From f7fce65db885d42e1ba966ebcdfabcfa787ddaf4 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 18:31:34 +0000 Subject: [PATCH 087/113] fix: inject six into the mineru tool venv mineru 3.4.5's pipeline imports six without declaring it, so every conversion died with "No module named 'six'" (measured on the first end-to-end run). uv tool install --with six is the workaround; the verification doc carries the same warning so a rebuild without it is diagnosed in one look. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .devcontainer/devcontainer.json | 3 ++- .devcontainer/gpu-verification.md | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d9f8cd5..c0f3563 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,7 +17,8 @@ }, "ghcr.io/thamaji/devcontainer-features/gitleaks:latest": {} }, - "onCreateCommand": "rm -rf .lake/ && lake exe cache get && uv sync && uv run lefthook install && uv tool install \"mineru[pipeline,vlm]\"", + // --with six: mineru 3.4.5's pipeline imports six without declaring it (measured). + "onCreateCommand": "rm -rf .lake/ && lake exe cache get && uv sync && uv run lefthook install && uv tool install --with six \"mineru[pipeline,vlm]\"", // Pass the host GPU through (Docker Desktop bundles the NVIDIA runtime). // If the container fails to start on a machine without a GPU, drop this line. "runArgs": [ diff --git a/.devcontainer/gpu-verification.md b/.devcontainer/gpu-verification.md index 5a0cf9e..c339791 100644 --- a/.devcontainer/gpu-verification.md +++ b/.devcontainer/gpu-verification.md @@ -13,8 +13,10 @@ Windows 側に NVIDIA ドライバが入っていればよく、**WSL やコン VS Code のコマンドパレット → **Dev Containers: Rebuild Container**。 -`onCreateCommand` が `lake exe cache get` と `uv tool install "mineru[pipeline,vlm]"` -を再実行する。mineru の wheel(torch 含む ~4GB)は `uv-cache` volume に、モデルは +`onCreateCommand` が `lake exe cache get` と +`uv tool install --with six "mineru[pipeline,vlm]"` を再実行する +(`--with six` は mineru 3.4.5 の未宣言依存の回避で、外すと変換が +`No module named 'six'` で全滅する。実測済み)。mineru の wheel(torch 含む ~4GB)は `uv-cache` volume に、モデルは `hf-models` volume にキャッシュされているので、2 回目以降の再ビルドは大幅に速い。 ## 2. GPU がコンテナに見えているか From 8f7464f9190318da00c638708916175638d7a40f Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 20:12:22 +0000 Subject: [PATCH 088/113] build: install mineru from a dependency group and pin torch to cu128 The converter moves from `uv tool install` into the `mineru` dependency group (in `default-groups`), so a plain `uv sync` provides it and the version is locked; ingest.py therefore looks in the project venv before PATH, because `uv run` with PEP 723 metadata does not put that venv on PATH. torch and torchvision are pinned to the cu128 index. The default PyPI wheel is built for CUDA 13 and needs driver 580+; this host runs 573.22 (CUDA 12.8), where it failed to initialise CUDA and silently ran on CPU. cu128 stops at torch 2.11, hence the `<2.12` cap. Both changes land together because they share one lockfile update. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../math-extract/references/ingestion.md | 25 +- .claude/skills/math-extract/scripts/ingest.py | 29 +- pyproject.toml | 31 + uv.lock | 1793 ++++++++++++++++- 4 files changed, 1834 insertions(+), 44 deletions(-) diff --git a/.claude/skills/math-extract/references/ingestion.md b/.claude/skills/math-extract/references/ingestion.md index bb1be00..80f1900 100644 --- a/.claude/skills/math-extract/references/ingestion.md +++ b/.claude/skills/math-extract/references/ingestion.md @@ -77,14 +77,9 @@ uv run .claude/skills/math-extract/scripts/ingest.py <file.pdf> --allow-mineru uv run .claude/skills/math-extract/scripts/ingest.py <file.pdf> --allow-mineru --pages 40-62 ``` -The devcontainer installs the converter in `onCreateCommand` -(`uv tool install --with six "mineru[pipeline,vlm]"` — the `--with six` works -around mineru 3.4.5's pipeline importing `six` without declaring it, which -otherwise fails every conversion with `No module named 'six'`); if the binary -is missing, the container predates that — run the same command by hand. It is a `uv tool`, not -a `pyproject.toml` dependency, on purpose: mineru drags torch and a few hundred -packages with hard version pins, and none of that belongs in the project venv -that the commit hooks run from. +The converter installs with a plain `uv sync` — it is the `mineru` dependency +group in `pyproject.toml`, which is in `default-groups`. To skip it deliberately, +`uv sync --no-group mineru` drops ~100 packages including torch. The script takes the largest Markdown file MinerU produces and writes `source.txt` and `source.flat.txt` from it exactly as for the other rungs — so @@ -94,9 +89,8 @@ tier consequence. ### GPU -The devcontainer passes the host GPU through (`"runArgs": ["--gpus", "all"]`, -Docker Desktop provides the runtime). **The setting takes effect on a container -rebuild**; the post-rebuild verification procedure lives in +The devcontainer passes the host GPU through. **The setting takes effect on a +container rebuild**; the post-rebuild verification procedure lives in `.devcontainer/gpu-verification.md` and is deliberately self-contained. - **The default backend stays `pipeline` even on GPU.** torch picks up CUDA by @@ -106,10 +100,11 @@ rebuild**; the post-rebuild verification procedure lives in path. **This machine's 8GB of VRAM is that backend's minimum, shared with the Windows desktop** — on `CUDA out of memory`, drop the flag and rerun; the pipeline result is the fallback, not a failure. -- Models land in `~/.cache/huggingface`, which is a named volume (`hf-models`), - so they survive rebuilds. `mineru-models-download` fetches them ahead of - time; `MINERU_MODEL_SOURCE` can force `huggingface`/`modelscope` (leave it - unset for auto). +- Models survive rebuilds in the `hf-models` named volume, and + `mineru-models-download` fetches them ahead of time. The devcontainer pins the + origin (see its comment on `MINERU_MODEL_SOURCE`); to fetch from elsewhere + once, prefix the single command — `MINERU_MODEL_SOURCE=modelscope mineru …` — + rather than unpinning. Things that are easy to get wrong, and cost a lot when got wrong: diff --git a/.claude/skills/math-extract/scripts/ingest.py b/.claude/skills/math-extract/scripts/ingest.py index a0f30ba..6bcaef5 100644 --- a/.claude/skills/math-extract/scripts/ingest.py +++ b/.claude/skills/math-extract/scripts/ingest.py @@ -257,20 +257,35 @@ def resolve_backend(opts: Options) -> str: return "pipeline" if opts.backend == "auto" else opts.backend +def find_mineru() -> str | None: + """Locate the converter: project venv first, then PATH. + + This script runs under `uv run` with its own PEP 723 metadata, so uv builds + it an isolated environment and the project venv is *not* on PATH. The + converter lives in that venv (installed by `uv sync`), so look there + explicitly before falling back to PATH. + """ + repo_root = Path(__file__).resolve().parents[4] + candidate = repo_root / ".venv" / "bin" / "mineru" + if candidate.is_file(): + return str(candidate) + return shutil.which("mineru") + + def rung_mineru(pdf_path: Path, out_dir: Path, opts: Options) -> tuple[str, str]: """Convert a PDF with MinerU. Never installs anything.""" - binary = shutil.which("mineru") + binary = find_mineru() if binary is None: report({ "ok": False, "reason": "mineru-missing", "target": str(pdf_path), - "message": "mineru is not on PATH. Install it with " - "`uv tool install \"mineru[pipeline,vlm]\"` — not [all], " - "which pulls the vllm/lmdeploy serving stacks. The " - "devcontainer installs it in onCreateCommand, so a missing " - "binary usually means the container predates that. This " - "script will not install it for you.", + "message": "The converter is not installed. Run `uv sync` from the " + "repository root — mineru is a locked dependency group in " + "pyproject.toml and is in default-groups, so a plain sync " + "installs it. If someone ran `uv sync --no-group mineru`, " + "that is what removed it. This script will not install it " + "for you.", }) raise SystemExit(5) diff --git a/pyproject.toml b/pyproject.toml index 182f3b0..8a03aed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,37 @@ dev = [ "commitizen>=4.17.0", "lefthook>=2.1.10", ] +# PDF conversion for the math-extract skill. Its own group so it can be skipped +# deliberately (`uv sync --no-group mineru`) -- it pulls torch and ~100 packages. +mineru = [ + "mineru[pipeline,vlm]>=3.4.5", + # mineru 3.4.5's pipeline imports six without declaring it (measured: every + # conversion fails with "No module named 'six'" otherwise). + "six>=1.17.0", + # Capped so the cu128 wheels below stay resolvable: cu128 stops at torch 2.11. + # mineru itself asks only for torch<3,>=2.6.0. + "torch>=2.6,<2.12", + "torchvision", +] + +[tool.uv] +# Both groups sync by default, so a bare `uv sync` cannot silently uninstall the +# converter. Skip the heavy one with `uv sync --no-group mineru`. +default-groups = ["dev", "mineru"] + +# torch must match the *host* NVIDIA driver, not the newest CUDA: the default +# PyPI wheel is built for CUDA 13 and needs driver 580+, while this host runs +# 573.22 (CUDA 12.8), where it fails with "The NVIDIA driver on your system is +# too old (found version 12080)" and falls back to CPU. cu128 wheels work there +# (measured). Bump this index only after the host driver moves past 580. +[[tool.uv.index]] +name = "pytorch-cu128" +url = "https://download.pytorch.org/whl/cu128" +explicit = true + +[tool.uv.sources] +torch = [{ index = "pytorch-cu128" }] +torchvision = [{ index = "pytorch-cu128" }] [tool.commitizen] name = "cz_conventional_commits" diff --git a/uv.lock b/uv.lock index 3743243..9ebd404 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,67 @@ version = 1 revision = 3 requires-python = ">=3.13" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version < '3.14'", +] + +[[package]] +name = "accelerate" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyyaml" }, + { name = "safetensors" }, + { name = "torch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8d/75/94cd5d389649578aca399e5aa822637eec18319a1dadc400ffe2f9a7493f/accelerate-1.14.0.tar.gz", hash = "sha256:41b9c4377a54e0b460a959b0defa1b736e4ca0a2373252d9a539964c2afe3c8d", size = 412167, upload-time = "2026-06-11T13:45:52.326Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/db/253133d7e7cb40d3af384bb2f5c0b4a2b7fdcffbc95c688cc67a20a3c103/accelerate-1.14.0-py3-none-any.whl", hash = "sha256:e94390c2863b873be18f623f9df48a0d8fe5eff13ea7f1a00092b0a7904888c6", size = 389246, upload-time = "2026-06-11T13:45:50.477Z" }, +] + +[[package]] +name = "aiofiles" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] [[package]] name = "argcomplete" @@ -11,6 +72,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl", hash = "sha256:6029205678bdd9c1c728a155f5f9ecf5812393f969eef58807641a2bc2aa5b19", size = 43294, upload-time = "2026-08-06T04:53:20.246Z" }, ] +[[package]] +name = "beautifulsoup4" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz", hash = "sha256:288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7", size = 632571, upload-time = "2026-06-07T16:44:20.453Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl", hash = "sha256:d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9", size = 109924, upload-time = "2026-06-07T16:44:21.566Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + [[package]] name = "charset-normalizer" version = "3.5.0" @@ -126,6 +209,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/c7/754d09943a616937df61e4ba367c409ded2a987e872972098d51a6fcf73b/charset_normalizer-3.5.0-py3-none-any.whl", hash = "sha256:993dfcbe75a85a3784abb5084f2c41b915767c90546fcc92803cffa28611baea", size = 67943, upload-time = "2026-08-12T14:35:30.363Z" }, ] +[[package]] +name = "click" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, +] + +[[package]] +name = "cobble" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/7a/a507c709be2c96e1bb6102eb7b7f4026c5e5e223ef7d745a17d239e9d844/cobble-0.1.4.tar.gz", hash = "sha256:de38be1539992c8a06e569630717c485a5f91be2192c461ea2b220607dfa78aa", size = 3805, upload-time = "2024-06-01T18:11:09.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/e1/3714a2f371985215c219c2a70953d38e3eed81ef165aed061d21de0e998b/cobble-0.1.4-py3-none-any.whl", hash = "sha256:36c91b1655e599fd428e2b95fdd5f0da1ca2e9f1abb0bc871dec21a0e78a2b44", size = 3984, upload-time = "2024-06-01T18:11:07.911Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -135,6 +239,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "colorlog" +version = "6.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8c/55/ba79756cb90c8d69d599d57785398ac87bba7b19c80e87f4e8a562197c93/colorlog-6.12.0.tar.gz", hash = "sha256:2a7924c1dadf18b22a0eb8b06d1c7b01d5341707ec1641eb6fcc4fde0c3e8e5f", size = 18151, upload-time = "2026-07-23T13:40:40.71Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/19/0b6647bf5e331521e55d2b63bfbdc210bd9cd605189273f03614a05f702d/colorlog-6.12.0-py3-none-any.whl", hash = "sha256:30d392604e9110045a2c2aeefc27d7a017abbab63f3a8aee594eac0801df784e", size = 12239, upload-time = "2026-07-23T13:40:39.562Z" }, +] + [[package]] name = "commitizen" version = "4.17.0" @@ -158,6 +274,75 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c5/a0/68f2683c1d736c20f48d8428a1db7486231f1b49928cf9cfaa9863b45998/commitizen-4.17.0-py3-none-any.whl", hash = "sha256:2e1842d12b7c29591bbeb2094d115aa47d10c6a92f5d6430bf24590434520726", size = 89566, upload-time = "2026-07-29T09:17:18.366Z" }, ] +[[package]] +name = "cuda-bindings" +version = "12.9.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-pathfinder" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/7b/f1575e41e1a17dc2f2a408b2e8e864c9324e41e3e23f6401e5efc54c152a/cuda_bindings-12.9.7-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:266379e4942051f544a8e7ea1a30ead8d7e8199b6b30fcdc8917cae2bf614e61", size = 6978549, upload-time = "2026-05-27T18:44:18.839Z" }, + { url = "https://files.pythonhosted.org/packages/9d/dc/62d62eb4f91eb721bcf46da51b13e9872ccd8fa7e60eb8ba7b7baeac72c6/cuda_bindings-12.9.7-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59cf4a37b0d662ba15037c9ceebe1a306ebf2c01a8235a09be13cd07094fdb74", size = 7457675, upload-time = "2026-05-27T18:44:20.637Z" }, + { url = "https://files.pythonhosted.org/packages/f9/77/94d9b85f26add6fe9c9cb7c4ec3b96bc598f7ea5cfbd7490cc0a36adf5be/cuda_bindings-12.9.7-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2dbcd4801954eb3508f4dc2fa0d0c8eb93eb3f45326fd61be2731418c371e7a0", size = 6870886, upload-time = "2026-05-27T18:44:24.164Z" }, + { url = "https://files.pythonhosted.org/packages/04/dd/3ec34b569e1b990b11276feba306bf8f446656cc38e8ed0f49b5facfeffa/cuda_bindings-12.9.7-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3747ea132642416786a8e31bf229032df3a7856911ae5426a7be53d032df183d", size = 7345663, upload-time = "2026-05-27T18:44:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/68/e4/075052d42872cf8162da53f14447a4b8abc004c3750e4b724ee502428da0/cuda_bindings-12.9.7-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:775960ac9e530717f3b48e165cc6f68684fa9a4141764fd923e4c1a9820acc73", size = 7060090, upload-time = "2026-05-27T18:44:30.281Z" }, + { url = "https://files.pythonhosted.org/packages/ec/cd/3289c810a4d45e5364a3387a74b4c9b6f6f57ee96ae0e5b537cc61dec242/cuda_bindings-12.9.7-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c47ec1a7a441d91aab32339951df7a1be53451121a12c094bba51467717a35a", size = 7504419, upload-time = "2026-05-27T18:44:31.992Z" }, + { url = "https://files.pythonhosted.org/packages/11/43/472a6281c3d94e71687e27c657a8f60718d3579b4d94c41deea503165f8a/cuda_bindings-12.9.7-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00a833d399b31071fab4cf3de2929840ae462dc4848116eeff033d09219e7116", size = 6899146, upload-time = "2026-05-27T18:44:35.556Z" }, + { url = "https://files.pythonhosted.org/packages/2b/13/10c1d0b32a9da65142d213e0733d748457fb3fd066aee4317335266f15c6/cuda_bindings-12.9.7-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11aeafa2b33995f890086b3fb0f062075176d956e9b6a6fe1a699dddc413f6ad", size = 7369087, upload-time = "2026-05-27T18:44:37.359Z" }, +] + +[[package]] +name = "cuda-pathfinder" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/b4/d088047afe39827556df21118cac9ffd20cc3f968c99a7681494d1eb333c/cuda_pathfinder-1.6.0-py3-none-any.whl", hash = "sha256:1503af579d8379c24bdd65528379bc57039b0455be9f5f9686cf8e473a1fce51", size = 54591, upload-time = "2026-07-21T15:03:56.224Z" }, +] + +[[package]] +name = "cuda-toolkit" +version = "12.8.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/c8/7dce3a0b15b42a3b58e7d96eb22a687d3bf2c44e01d149a6874629cd9938/cuda_toolkit-12.8.1-py2.py3-none-any.whl", hash = "sha256:adc7906af4ecbf9a352f9dca5734eceb21daec281ccfcf5675e1d2f724fc2cba", size = 2283, upload-time = "2025-08-13T02:03:07.842Z" }, +] + +[package.optional-dependencies] +cublas = [ + { name = "nvidia-cublas-cu12" }, +] +cudart = [ + { name = "nvidia-cuda-runtime-cu12" }, +] +cufft = [ + { name = "nvidia-cufft-cu12" }, +] +cufile = [ + { name = "nvidia-cufile-cu12" }, +] +cupti = [ + { name = "nvidia-cuda-cupti-cu12" }, +] +curand = [ + { name = "nvidia-curand-cu12" }, +] +cusolver = [ + { name = "nvidia-cusolver-cu12" }, +] +cusparse = [ + { name = "nvidia-cusparse-cu12" }, +] +nvjitlink = [ + { name = "nvidia-nvjitlink-cu12" }, +] +nvrtc = [ + { name = "nvidia-cuda-nvrtc-cu12" }, +] +nvtx = [ + { name = "nvidia-nvtx-cu12" }, +] + [[package]] name = "decli" version = "0.6.3" @@ -179,6 +364,225 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "et-xmlfile" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, +] + +[[package]] +name = "fast-langdetect" +version = "0.2.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fasttext-predict" }, + { name = "requests" }, + { name = "robust-downloader" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8d/17/2753b3d280e16f594e7a5d735568c021a355cd1edd3827f26cda5c9fd460/fast_langdetect-0.2.5.tar.gz", hash = "sha256:e5fe65973f5737107bb8314f3829280d196c87d4da0b4a6e95000175512cf2c3", size = 788620, upload-time = "2025-01-28T02:15:24.637Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/da/c621e64d4bc23f485468295bb7d4a5f2290ebb4d342c8dc448ab66808071/fast_langdetect-0.2.5-py3-none-any.whl", hash = "sha256:8d5ff640d94d5f30bb7653c761adbb9122b617b03fa1f166b7cc16c35e484d0e", size = 786618, upload-time = "2025-01-28T02:15:23.039Z" }, +] + +[[package]] +name = "fastapi" +version = "0.141.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/02/91e3416a8fdd715abb903a952a6bec7cdd8d14eed55d415fc8595524c319/fastapi-0.141.1.tar.gz", hash = "sha256:e8822fc40db1e1858054d7a949a888695bc9bdce70139178e33bd2871a453ca1", size = 425799, upload-time = "2026-07-29T17:18:05.568Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl", hash = "sha256:bfb91aa2d334c61cb35ba9a116fc123b3d3df31640b801cf57a7a78ec3f603b3", size = 131954, upload-time = "2026-07-29T17:18:04.364Z" }, +] + +[[package]] +name = "fasttext-predict" +version = "0.9.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0e/9defbb9385bcb1104cc1d686a14f7d9fafe5fe43f220cccb00f33d91bb47/fasttext_predict-0.9.2.4.tar.gz", hash = "sha256:18a6fb0d74c7df9280db1f96cb75d990bfd004fa9d669493ea3dd3d54f84dbc7", size = 16332, upload-time = "2024-11-23T17:24:44.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/fc/5cd65224c33e33d6faec3fa1047162dc266ed2213016139d936bd36fb7c3/fasttext_predict-0.9.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddb85e62c95e4e02d417c782e3434ef65554df19e3522f5230f6be15a9373c05", size = 104916, upload-time = "2024-11-23T17:23:43.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/53/8d542773e32c9d98dd8c680e390fe7e6d4fc92ab3439dc1bb8e70c46c7ad/fasttext_predict-0.9.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:102129d45cf98dda871e83ae662f71d999b9ef6ff26bc842ffc1520a1f82930c", size = 97502, upload-time = "2024-11-23T17:23:44.447Z" }, + { url = "https://files.pythonhosted.org/packages/50/99/049fd6b01937705889bd9a00c31e5c55f0ae4b7704007b2ef7a82bf2b867/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05ba6a0fbf8cb2141b8ca2bc461db97af8ac31a62341e4696a75048b9de39e10", size = 282951, upload-time = "2024-11-23T17:23:46.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/cb/79b71709edbb53c3c5f8a8b60fe2d3bc98d28a8e75367c89afedf3307aa9/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c7a779215571296ecfcf86545cb30ec3f1c6f43cbcd69f83cc4f67049375ea1", size = 307377, upload-time = "2024-11-23T17:23:47.685Z" }, + { url = "https://files.pythonhosted.org/packages/7c/4a/b15b7be003e76613173cc77d9c6cce4bf086073079354e0177deaa768f59/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddd2f03f3f206585543f5274b1dbc5f651bae141a1b14c9d5225c2a12e5075c2", size = 295746, upload-time = "2024-11-23T17:23:49.024Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d3/f030cd45bdd4b052fcf23e730fdf0804e024b0cad43d7c7f8704faaec2f5/fasttext_predict-0.9.2.4-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:748f9edc3222a1fb7a61331c4e06d3b7f2390ae493f91f09d372a00b81762a8d", size = 236939, upload-time = "2024-11-23T17:23:50.306Z" }, + { url = "https://files.pythonhosted.org/packages/a2/01/6f2985afd58fdc5f4ecd058d5d9427d03081d468960982df97316c03f6bb/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1aee47a40757cd24272b34eaf9ceeea86577fd0761b0fd0e41599c6549abdf04", size = 1214189, upload-time = "2024-11-23T17:23:51.647Z" }, + { url = "https://files.pythonhosted.org/packages/75/07/931bcdd4e2406e45e54d57e056c2e0766616a5280a18fbf6ef078aa439ab/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6ff0f152391ee03ffc18495322100c01735224f7843533a7c4ff33c8853d7be1", size = 1099889, upload-time = "2024-11-23T17:23:53.127Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/6521b4bbf387252a96a6dc0f54986f078a93db0a9d4ba77258dcf1fa8be7/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4d92f5265318b41d6e68659fd459babbff692484e492c5013995b90a56b517c9", size = 1383959, upload-time = "2024-11-23T17:23:54.521Z" }, + { url = "https://files.pythonhosted.org/packages/b7/6b/d56606761afb3a3912c52971f0f804e2e9065f049c412b96c47d6fca6218/fasttext_predict-0.9.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3a7720cce1b8689d88df76cac1425e84f9911c69a4e40a5309d7d3435e1bb97c", size = 1281097, upload-time = "2024-11-23T17:23:55.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/83/55bb4a37bb3b3a428941f4e1323c345a662254f576f8860b3098d9742510/fasttext_predict-0.9.2.4-cp313-cp313-win32.whl", hash = "sha256:d16acfced7871ed0cd55b476f0dbdddc7a5da1ffc9745a3c5674846cf1555886", size = 91137, upload-time = "2024-11-23T17:23:57.886Z" }, + { url = "https://files.pythonhosted.org/packages/9c/1d/c1ccc8790ce54200c84164d99282f088dddb9760aeefc8860856aafa40b4/fasttext_predict-0.9.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:96a23328729ce62a851f8953582e576ca075ee78d637df4a78a2b3609784849e", size = 104896, upload-time = "2024-11-23T17:23:59.028Z" }, + { url = "https://files.pythonhosted.org/packages/a4/c9/a1ccc749c59e2480767645ecc03bd842a7fa5b2b780d69ac370e6f8298d2/fasttext_predict-0.9.2.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b1357d0d9d8568db84668b57e7c6880b9c46f757e8954ad37634402d36f09dba", size = 109401, upload-time = "2024-11-23T17:24:00.191Z" }, + { url = "https://files.pythonhosted.org/packages/90/1f/33182b76eb0524155e8ff93e7939feaf5325385e5ff2a154f383d9a02317/fasttext_predict-0.9.2.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9604c464c5d86c7eba34b040080be7012e246ef512b819e428b7deb817290dae", size = 102131, upload-time = "2024-11-23T17:24:02.052Z" }, + { url = "https://files.pythonhosted.org/packages/2b/df/1886daea373382e573f28ce49e3fc8fb6b0ee0c84e2b0becf5b254cd93fb/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6da186c2e4497cbfaba9c5424e58c7b72728b25d980829eb96daccd7cface1", size = 287396, upload-time = "2024-11-23T17:24:03.294Z" }, + { url = "https://files.pythonhosted.org/packages/35/8f/d1c2c0f0251bee898d508253a437683b0480a1074cfb25ded1f7fdbb925a/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366ed2ca4f4170418f3585e92059cf17ee2c963bf179111c5b8ba48f06cd69d1", size = 311090, upload-time = "2024-11-23T17:24:04.625Z" }, + { url = "https://files.pythonhosted.org/packages/5d/52/07d6ed46148662fae84166bc69d944caca87fabc850ebfbd9640b20dafe7/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f1877edbb815a43e7d38cc7332202e759054cf0b5a4b7e34a743c0f5d6e7333", size = 300359, upload-time = "2024-11-23T17:24:06.486Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a1/751ff471a991e5ed0bae9e7fa6fc8d8ab76b233a7838a27d70d62bed0c8e/fasttext_predict-0.9.2.4-cp313-cp313t-manylinux_2_31_armv7l.whl", hash = "sha256:f63c31352ba6fc910290b0fe12733770acd8cfa0945fcb9cf3984d241abcfc9d", size = 241164, upload-time = "2024-11-23T17:24:08.501Z" }, + { url = "https://files.pythonhosted.org/packages/94/19/e251f699a0e9c001fa672ea0929c456160faa68ecfafc19e8def09982b6a/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:898e14b03fbfb0a8d9a5185a0a00ff656772b3baa37cad122e06e8e4d6da3832", size = 1218629, upload-time = "2024-11-23T17:24:10.04Z" }, + { url = "https://files.pythonhosted.org/packages/1d/46/1af2f779f8cfd746496a226581f747d3051888e3e3c5b2ca37231e5d04f8/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:a33bb5832a69fc54d18cadcf015677c1acb5ccc7f0125d261df2a89f8aff01f6", size = 1100535, upload-time = "2024-11-23T17:24:11.5Z" }, + { url = "https://files.pythonhosted.org/packages/4c/b7/900ccd74a9ba8be7ca6d04bba684e9c43fb0dbed8a3d12ec0536228e2c32/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7fe9e98bd0701d598bf245eb2fbf592145cd03551684a2102a4b301294b9bd87", size = 1387651, upload-time = "2024-11-23T17:24:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5a/99fdaed054079f7c96e70df0d7016c4eb6b9e487a614396dd8f849244a52/fasttext_predict-0.9.2.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dcb8c5a74c1785f005fd83d445137437b79ac70a2dfbfe4bb1b09aa5643be545", size = 1286189, upload-time = "2024-11-23T17:24:14.615Z" }, + { url = "https://files.pythonhosted.org/packages/87/6a/9114d65b3f7a9c20a62b9d2ca3b770ee65de849e4131cc7aa58cdc50cb07/fasttext_predict-0.9.2.4-cp313-cp313t-win32.whl", hash = "sha256:a85c7de3d4480faa12b930637fca9c23144d1520786fedf9ba8edd8642ed4aea", size = 95905, upload-time = "2024-11-23T17:24:15.868Z" }, + { url = "https://files.pythonhosted.org/packages/31/fb/6d251f3fdfe3346ee60d091f55106513e509659ee005ad39c914182c96f4/fasttext_predict-0.9.2.4-cp313-cp313t-win_amd64.whl", hash = "sha256:be0933fa4af7abae09c703d28f9e17c80e7069eb6f92100b21985b777f4ea275", size = 110325, upload-time = "2024-11-23T17:24:16.984Z" }, +] + +[[package]] +name = "filelock" +version = "3.32.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/64/a02e6765de08964ed371eca577870593245afc9dfac16d037de7c10d18e6/filelock-3.32.3.tar.gz", hash = "sha256:0ffa185a3540854c95caa7fa76b76cb219d907415e2c5dc9af25fd970563487f", size = 218135, upload-time = "2026-08-13T16:00:05.577Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/8e/50f46a9c0ce8d2861a394c1347caae037ea0431d2f67d7feb151cbc4649a/filelock-3.32.3-py3-none-any.whl", hash = "sha256:7f0ca4bcc0e181c60dbbd8aa9ab5b120ebb99e4e064e83636340056f833a1f09", size = 98901, upload-time = "2026-08-13T16:00:03.974Z" }, +] + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" }, +] + +[[package]] +name = "fsspec" +version = "2026.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/78/f34251dadb8f3921264a1d9b8946f5e542014ee2614b285261b4e40e6775/fsspec-2026.7.0.tar.gz", hash = "sha256:c803c40f4cf860b49dea58ee3e1c33cb9c790520e233537e1340049f89b82a88", size = 317040, upload-time = "2026-07-28T16:34:51.052Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl", hash = "sha256:b57ddbafedfaef7018c1ecab32aa200a9d7ca26b77965f64e48b70061249d279", size = 206583, upload-time = "2026-07-28T16:34:49.538Z" }, +] + +[[package]] +name = "ftfy" +version = "6.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927, upload-time = "2024-10-26T00:50:35.149Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821, upload-time = "2024-10-26T00:50:33.425Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ab/522a2ab67f27971a9d48ca666d4fca85ef7d5282d142e31fd087e27b1bbe/hf_xet-1.6.0.tar.gz", hash = "sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef", size = 920527, upload-time = "2026-08-03T22:33:13.243Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/62/3c062f593bd92ef4e77a0ef39541e3d82a0a1d3947c8a777a02a13a27828/hf_xet-1.6.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:70cbb9c896901600128cb9b6f06e132954fbede1db30f31f7c6c63f84cb7c31d", size = 4074584, upload-time = "2026-08-03T22:32:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:23379c2f9ec8696d952b16414a2bae72cad86a52df869b050698ba60f538c675", size = 3867381, upload-time = "2026-08-03T22:32:49.049Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ee/7c0d7b6ab336167531b1c30af2af003f054af4c749becbd7209ae33a77c3/hf_xet-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f2f7278c05c22fd60cb436cda1269649b3e81db65ecdc8496e5e164aa4143e7b", size = 4453982, upload-time = "2026-08-03T22:32:50.568Z" }, + { url = "https://files.pythonhosted.org/packages/63/06/ad8eab1c9525246650cbaa821caa3cdbaca734ab1a5b8c91bea09cbd8d69/hf_xet-1.6.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:948f15d3a9545cfe5932f6bd8b440f6ae630aee108f14b7bd6c561f7c2dcc522", size = 4249445, upload-time = "2026-08-03T22:32:52.391Z" }, + { url = "https://files.pythonhosted.org/packages/d8/26/1eee8aedb0dafc1ab9717dc9ac602cde33361b232dc06803f1f6ed18b58c/hf_xet-1.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5153e6bb103ad49d6ea9f1b2e230db5a2ea32551ad09a706d2f61d7c7c80d80e", size = 4451099, upload-time = "2026-08-03T22:32:54.114Z" }, + { url = "https://files.pythonhosted.org/packages/67/57/0b88af1f194ab6c9c650547d9cc06bfeaab836ae4dcdb331676bfb8be95a/hf_xet-1.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:35cec30d75c6f9eb9c16a77cef68e85a103b72e24d4b473714ec9ff06428bab9", size = 4664712, upload-time = "2026-08-03T22:32:55.547Z" }, + { url = "https://files.pythonhosted.org/packages/53/a0/26b717a9d1840e8abf48dcec64b5ed8fbe472671d38ad28d30e147132b33/hf_xet-1.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:5789835d7c6bc9436962853192082374297fb72d7eff7e7762ec25ceb7e25338", size = 4025906, upload-time = "2026-08-03T22:32:57.391Z" }, + { url = "https://files.pythonhosted.org/packages/49/f6/4a9966633c6fef83af997e2cff68ec1963676d412bdfd096df2a93b8e185/hf_xet-1.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:75765820ce4700db3750c94acc8fe27c5fae4c9ec000a0dbac3ca082acf97765", size = 3849221, upload-time = "2026-08-03T22:32:59.123Z" }, + { url = "https://files.pythonhosted.org/packages/a2/50/7afa2c9c787405864fc47a0d1bbc02c62e9101947ed43c1f43899fc7d91d/hf_xet-1.6.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:633dc0cd71d32da58ab8c03ad38e2fac452c15c2b0a2866ebf6ededfe0a5061d", size = 4071729, upload-time = "2026-08-03T22:33:00.721Z" }, + { url = "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:f0906082d9932ae0c0057fa194041c22b4e2cdb46b2592ef3b91f020d62a081a", size = 3876287, upload-time = "2026-08-03T22:33:02.251Z" }, + { url = "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f", size = 4464663, upload-time = "2026-08-03T22:33:03.802Z" }, + { url = "https://files.pythonhosted.org/packages/9a/69/1f0cbc2fb22ae6082d094f743d1b8945a3f36f6089cb95f42b7ee348cda7/hf_xet-1.6.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7", size = 4262538, upload-time = "2026-08-03T22:33:05.287Z" }, + { url = "https://files.pythonhosted.org/packages/d1/3a/4f4f2301ade26e404462d3336fa11f7958d914cabbabdd6e03c3c5d5658c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb", size = 4460520, upload-time = "2026-08-03T22:33:06.81Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/311725e2a905534dfee2dcb5b08414f249147f1f12252bfc2bd24caa075c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8fb4f71cba6129110c3374a33f919001ff130488fc23553698e34cc1c2a1198c", size = 4675937, upload-time = "2026-08-03T22:33:08.616Z" }, + { url = "https://files.pythonhosted.org/packages/98/b7/8c59a66d15205024662f1d66968136f13893f96df1ddc5087e2e281fc95f/hf_xet-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:fb4fadde1b2b70bf4c0c14a6dccbe7194b1c28947fefd5bbe3fed9d940676c3b", size = 4033128, upload-time = "2026-08-03T22:33:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/73/63/ca511b6f802f28cf3489b280fe77475bcca8de85e81a6299d7916b5b5555/hf_xet-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:3dc3e35441ba395006af5aaacc40ef2e603c51ef46c3530b9156185f00935ea3", size = 3859359, upload-time = "2026-08-03T22:33:11.725Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "httpx-retries" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/d3/b7a8bb09543af40009717a08a2ceba90b6d4c6f0cdf171404217d8f4c37d/httpx_retries-0.6.0.tar.gz", hash = "sha256:3e0b404969a564829d368417964fd21e6b400a10d17c92d29b8bc247ce8186e3", size = 21122, upload-time = "2026-07-06T00:52:30.093Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/c6/7f3d6ab3549267a1959161b38df4c0fb435eceaf2d531d8addfac01abaca/httpx_retries-0.6.0-py3-none-any.whl", hash = "sha256:d1e52a8f68a5df42de75ab89049d5020b2d0ab2f5f8bceacda008d12aa1257a3", size = 11776, upload-time = "2026-07-06T00:52:31.033Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -191,6 +595,65 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] +[[package]] +name = "jiter" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/1f/10936e16d8860c70698a1aa939a46aa0224813b782bce4e000e637da0b2d/jiter-0.16.0.tar.gz", hash = "sha256:7b24c3492c5f4f84a37946ad9cf504910cf6a782d6a4e0689b6673c5894b4a1c", size = 176431, upload-time = "2026-06-29T13:05:13.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/c0/555fc60473d30d66894ba825e63615e3be7524fac23858356afa7a38906c/jiter-0.16.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:41977aa5654023948c2dae2a81cbf9c43343954bef1cd59a154dd15a4d84c195", size = 306203, upload-time = "2026-06-29T13:03:36.243Z" }, + { url = "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d28bb3c26762358dadf3e5bf0bccd29ae987d65e6988d2e6f49829c76b003c09", size = 306489, upload-time = "2026-06-29T13:03:37.846Z" }, + { url = "https://files.pythonhosted.org/packages/96/3f/02fdfc6705cad96127d883af5c34e4867f554f29ec7705ec1a46156400a9/jiter-0.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0542a7189c26920778658fc8fcf2af8bae05bae9924577f71804acef37996536", size = 335453, upload-time = "2026-06-29T13:03:39.221Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a6/e4bda5920d4b0d7c5dfb7174ce4a6b2e4d3e11c9162c452ef0eab4cdbdbd/jiter-0.16.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8fb8de1e23a0cb2a7f53c335049c7b72b6db41aa6227cdcc0972a1de5cb39450", size = 361625, upload-time = "2026-06-29T13:03:40.597Z" }, + { url = "https://files.pythonhosted.org/packages/b7/97/4e6b59b2c6e55cbb3e183595f81ad65dcfb21c915fee5e19e335df21bc55/jiter-0.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b72d0b2990ca754a9102779ac98d8597b7cb31678958562214a007f909eab78e", size = 456958, upload-time = "2026-06-29T13:03:42.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/e0/97e9557686d2f94f4b93786eccb7eed28e9228ad132ea8237f44727314a7/jiter-0.16.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f91b1c27fc22a57993d5a5cb8a627cb8ed4b10502716fac1ffbfe1d19d84e8", size = 372017, upload-time = "2026-06-29T13:03:43.658Z" }, + { url = "https://files.pythonhosted.org/packages/0f/94/db768b6938e0df35c86beeba3dfbbb025c9ee5c19e1aa271f2396e50864d/jiter-0.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c682bea068a90b764577bdb78a60a4c1d1606daf9cd4c893832a37c7cc9d9026", size = 343320, upload-time = "2026-06-29T13:03:45.226Z" }, + { url = "https://files.pythonhosted.org/packages/c1/d6/5a59d938244a30735fe62d9433fd325f9021ea29d89780ea4596ea93bc89/jiter-0.16.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:8d031aabecc4f1b6276adfb42e3aabb77c89d468bf616600e8d3a11328929053", size = 350520, upload-time = "2026-06-29T13:03:46.671Z" }, + { url = "https://files.pythonhosted.org/packages/67/f8/c4a857f49c9af125f6bbcac7e3eee7f7978ed89682833062e2dbf62576b1/jiter-0.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eab2cd170150e70153de16896a1774e3a1dca80154c56b54d7a812c479a7165e", size = 387550, upload-time = "2026-06-29T13:03:48.361Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d6/5fbc2f7d6b67b754caa61a993a2e626e815dec47ffc2f9e35f01adfebec7/jiter-0.16.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:6edb63a46e65a82c26800a868e49b2cac30dd5a4218b88d74bc2c848c8ad60bb", size = 515424, upload-time = "2026-06-29T13:03:49.881Z" }, + { url = "https://files.pythonhosted.org/packages/ed/54/284f0164b64a5fed915fea6ba7e9ba9b3d8d37c67d59cf2e3bb99d45cdfe/jiter-0.16.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:659039cc50b5addcc35fcc87ae2c1833b7c0a8e5326ef631a75e4478447bcf84", size = 546981, upload-time = "2026-06-29T13:03:51.363Z" }, + { url = "https://files.pythonhosted.org/packages/13/c5/2a467585a576594384e1d2c43e1224deaafc085f24e243529cf98beef8e1/jiter-0.16.0-cp313-cp313-win32.whl", hash = "sha256:c9c53be232c2e206ef9cdbad81a48bfa74c3d3f08bcf8124630a8a748aad993e", size = 202853, upload-time = "2026-06-29T13:03:53.015Z" }, + { url = "https://files.pythonhosted.org/packages/88/6a/de61d04b9eec69c71719968d2f716532a3bc121170c44a39e14979c6be81/jiter-0.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:baad945ed47f163ad833314f8e3288c396118934f94e7bbb9e243ce4b341a4fd", size = 196160, upload-time = "2026-06-29T13:03:54.447Z" }, + { url = "https://files.pythonhosted.org/packages/19/4b/b390ed59bafb3f31d008d1218578f10327714484b334439947f7e5b11e7f/jiter-0.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:3c1fd2dbe1b0af19e987f03fe66c5f5bd105a2229c1aff4ab14890b24f41d21a", size = 189862, upload-time = "2026-06-29T13:03:55.754Z" }, + { url = "https://files.pythonhosted.org/packages/a7/89/bc4f1b57d5da938fd344a466396541e586d161320d70bffd929aaafcd8f4/jiter-0.16.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b2c61484666ad42726029af0c00ef4541f0f3b5cdc550221f56c2343208018ee", size = 308239, upload-time = "2026-06-29T13:03:57.205Z" }, + { url = "https://files.pythonhosted.org/packages/65/7a/c415453e5213001bf3b411ff65dec3d303b0e76a4a2cfea9768cd4960994/jiter-0.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:63efadc657488f45db1c676d81e704cac2abf3fdb892def1faea61db053127e2", size = 308928, upload-time = "2026-06-29T13:03:58.643Z" }, + { url = "https://files.pythonhosted.org/packages/11/fc/1f4fb7ebf9a724c7741994f4aae18fba1e2f3133df14521a79194952c34a/jiter-0.16.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf0d73f50e7b6935677854f6e8e31d499ca7064dd24734f703e060f5b237d883", size = 336998, upload-time = "2026-06-29T13:04:00.071Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8d/72cadaac05ccfa7cc3a0a2232862e6c72443ca40cf300ba8b57f9f18b69b/jiter-0.16.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf3ea07d9bc8e7d03a9fbc051295462e6dbc295b894fd72457c3136e3e43d898", size = 362112, upload-time = "2026-06-29T13:04:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/58/4a/c4b0d5f651fda90a24ffce9f8d56cde462a2e09d31ae3de3c68cef34c04e/jiter-0.16.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26798522707abb47d767db536e4148ceac1b14446bf028ee85e579a2e043cfe5", size = 459807, upload-time = "2026-06-29T13:04:03.214Z" }, + { url = "https://files.pythonhosted.org/packages/80/58/ef77879ea9aa56b50824edc5a445e226422c7a8d211f3fd2a56bcb9493cf/jiter-0.16.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bc837c1b9631be10abfe0191537fe8009838204cec7e44827401ace390ddb567", size = 373181, upload-time = "2026-06-29T13:04:04.629Z" }, + { url = "https://files.pythonhosted.org/packages/49/2e/ffbc3f254e4d8a66da3062c624a7df4b7c2b2cf9e1fe43cf394b3e104041/jiter-0.16.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49060fd70737fad59d33ba9dcc0d83247dc9e77187de26053a19c16c9f32bd69", size = 344927, upload-time = "2026-06-29T13:04:06.067Z" }, + { url = "https://files.pythonhosted.org/packages/9a/f6/0be5dc6d64a89f80aa8fec984f94dedb2973e251edcae55841d60786d578/jiter-0.16.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:adbb8edeadd431bc4477879d5d371ece7cb1334486584e0f252656dd7ffada29", size = 352754, upload-time = "2026-06-29T13:04:07.477Z" }, + { url = "https://files.pythonhosted.org/packages/da/6e/7d31243b3b91cd261dd19e9d3557fc3251a80883d3d8049c86174e7ab7af/jiter-0.16.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:31aaee5b80f672c1dc21272bcfb9cbdcfc1ea04ff50f00ed5af500b80c44fa93", size = 390553, upload-time = "2026-06-29T13:04:08.92Z" }, + { url = "https://files.pythonhosted.org/packages/25/33/51ae371fde3c88897520f62b4d5f8b27ad7103e2bb10812ff52195609853/jiter-0.16.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:6722bcef4ffc86c835574b1b2fac6b33b9fb4a889c781e67950e891591f3c55a", size = 516900, upload-time = "2026-06-29T13:04:10.407Z" }, + { url = "https://files.pythonhosted.org/packages/a0/45/6449b3d123ea439ba79507c657288f461d55049e7bcbdc2cf8eb8210f491/jiter-0.16.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:5ab4f50ff971b611d656554ea10b75f80097392c827bc32923c6eeb6386c8b00", size = 548754, upload-time = "2026-06-29T13:04:12.046Z" }, + { url = "https://files.pythonhosted.org/packages/9b/e7/fd2fb11ae3e2649333da3aa170d04d7b3000bbdc3b270f6513382fdf4e04/jiter-0.16.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:710cc51d4ebdcd3c1f70b232c1db1ea1344a075770422bbd4bede5708335acbe", size = 122381, upload-time = "2026-06-29T13:04:13.413Z" }, + { url = "https://files.pythonhosted.org/packages/26/80/f0b147a62c315a164ed2168908286ca302310824c218d3aae52b06c0c9a9/jiter-0.16.0-cp314-cp314-win32.whl", hash = "sha256:57b37fc887a32d44798e4d8ebfa7c9683ff3da1d5bf38f08d1bb3573ccb39106", size = 204578, upload-time = "2026-06-29T13:04:14.813Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e6/4758a14304b4523a6f5adb2419340086aa3593bd4327c2b25b5948a90548/jiter-0.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:cbd18dd5e2df96b580487b5745adf57ef64ad89ba2d9662fc3c19386acce7db8", size = 198154, upload-time = "2026-06-29T13:04:16.272Z" }, + { url = "https://files.pythonhosted.org/packages/26/be/41fa54a2e7ea41d6c99f1dc5b1f0fd4cb474680304b5d268dd518e81da3a/jiter-0.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:a32d2027a9fa67f109ff245a3252ece3ccc32cc56703e1deab6cc846a59e0585", size = 191458, upload-time = "2026-06-29T13:04:17.707Z" }, + { url = "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2577196f4474ef3fc4779a088a23b0897bbf86f9ea3679c372d45b8383b43207", size = 316739, upload-time = "2026-06-29T13:04:19.663Z" }, + { url = "https://files.pythonhosted.org/packages/2d/95/49461034d5388196d3dabf98748935f017b7785d8f3f5349f834bcc4ed0d/jiter-0.16.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e89e008a93c01104161c75b4988e58716b01d62307ebfe161e52a56d2a818", size = 340911, upload-time = "2026-06-29T13:04:21.257Z" }, + { url = "https://files.pythonhosted.org/packages/cd/97/a4369f2fb82cb3dda13b98622f31249b2e014b223fe64ee534413ad72294/jiter-0.16.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e2e9efbe042210df657bade597f66d6d75723e3d8f45a12ea6d8167ff8bbce3", size = 361747, upload-time = "2026-06-29T13:04:22.677Z" }, + { url = "https://files.pythonhosted.org/packages/28/51/49b6ed456261646e1906016a6760367a28aacd3c24805e4e5fe64116c1db/jiter-0.16.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f4d9e473a5ce7d27fef8b848df4dc16e283893d3f53b4a585e72c9595f3c284", size = 460225, upload-time = "2026-06-29T13:04:24.441Z" }, + { url = "https://files.pythonhosted.org/packages/33/b5/5689aff4f66c5b60be63106e591dbfcba2190df97d2c9c7cf052361ddb98/jiter-0.16.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d30a4a1c87713060c8d1cc59a7b6c8fb6b8ef0a6900368014c76c87922a2929", size = 373169, upload-time = "2026-06-29T13:04:25.884Z" }, + { url = "https://files.pythonhosted.org/packages/a2/96/3ae1b85ee0d6d6cab254fb7f8da018272b932bbf2d69b07e98aa2a96c746/jiter-0.16.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae96332410f866e5900d809298b1ed82735932986c672495f9701daacd80620", size = 350332, upload-time = "2026-06-29T13:04:27.302Z" }, + { url = "https://files.pythonhosted.org/packages/15/32/c99d7bafd78986556c95bf60ce84c6cc98786eac56066c12d7f828bb6747/jiter-0.16.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:da3d7ec75dc83bb18bca888b5edfae0656a26849056c59e05a7728badd17e7af", size = 353377, upload-time = "2026-06-29T13:04:28.731Z" }, + { url = "https://files.pythonhosted.org/packages/0e/4b/f99a8e571287c3dec766bcc18528bbe8e8fb5365522ab5e6d64c93e87066/jiter-0.16.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ee6162b77d49a9939229df666dfa8af3e656b6701b54c4c84966d740e189264e", size = 387746, upload-time = "2026-06-29T13:04:30.319Z" }, + { url = "https://files.pythonhosted.org/packages/75/69/c78a5b3f71040e34eb5917df26fb7ae9a2174cad1ccbf277512507c53a6e/jiter-0.16.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:63ffdbdae7d4499f4cda14eadc12ddcabef0fc0c081191bdc2247489cb698077", size = 517292, upload-time = "2026-06-29T13:04:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f7/095b38eda4c70d03651c403f29a5590f16d12ddc5d544aac9f9cddf72277/jiter-0.16.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:a111256a7193bea0759267b10385e5870949c239ed7b6ddbaaf57573edb38734", size = 549259, upload-time = "2026-06-29T13:04:33.721Z" }, + { url = "https://files.pythonhosted.org/packages/2e/c5/6a0207d90e5f656d95af98ebd0934f382d37674416f215aeda2ff8063e51/jiter-0.16.0-cp314-cp314t-win32.whl", hash = "sha256:de5ba8763e56b793561f43bed197c9ea55776daa5e9a6b91eed68a909bc9cdbf", size = 206523, upload-time = "2026-06-29T13:04:35.068Z" }, + { url = "https://files.pythonhosted.org/packages/a5/31/c757d5f30a8980fd945ce7b98be10be9e4ff59c7c42f5fd86804c2e87db8/jiter-0.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b8a3f9a6008048fe9def7bf465180564a6e458047d2ce499149cfbe73c3ae9db", size = 200366, upload-time = "2026-06-29T13:04:36.61Z" }, + { url = "https://files.pythonhosted.org/packages/7c/a2/d88de6d313d734a544a7901353ad5db67cb38dcfcd91713b7979dafc345d/jiter-0.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0fa25b09b13075c46f5bc174f2690525a925a4fc2f7c82969a2bbabff22386ce", size = 190516, upload-time = "2026-06-29T13:04:38.004Z" }, +] + +[[package]] +name = "json-repair" +version = "0.63.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/1b/c23bee35d532ea9c2038f31245fd2b50e6a8308d38a8b965bf0f9c6d49ba/json_repair-0.63.2.tar.gz", hash = "sha256:8385ca04afbf411eebd9f0ba064155d1afe37442aaad52f693825c65cc314586", size = 52426, upload-time = "2026-08-14T07:39:27.637Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/fe/edc09f67290861ab6b97dfd530189ae07092a708e90abe5a0e55f863f35c/json_repair-0.63.2-py3-none-any.whl", hash = "sha256:7354c2dd433bf15dedf98d2932ae9cd1ea197d7edc77e6c0538f08e34616580e", size = 50916, upload-time = "2026-08-14T07:39:26.339Z" }, +] + [[package]] name = "lefthook" version = "2.1.10" @@ -204,6 +667,109 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/01/054a0a18154dd8127276398a82d9797dd5534ebeeb1d8d61a9b19e6a8ef0/lefthook-2.1.10-py3-none-win_arm64.whl", hash = "sha256:be7b59b9e3483f62a217a632cb4177eaa3f75229916450bd12b99b608c51439d", size = 4858134, upload-time = "2026-07-08T12:03:37.421Z" }, ] +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + +[[package]] +name = "lxml" +version = "6.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz", hash = "sha256:ba96ae44888e0185281e937633a743ea90d5a196c6000f82565ebb0580012d40", size = 4197430, upload-time = "2026-05-18T19:19:06.424Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/eb/7e6f37c5584ccbb2ff267f56fd0339016938c1c8684cfefab9b33ffc2f36/lxml-6.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:68a9198d0fc122d14bb76837de9aa80cf84caed990b5b237f532ed87d3706736", size = 8559780, upload-time = "2026-05-18T19:17:57.661Z" }, + { url = "https://files.pythonhosted.org/packages/a1/36/587c2521cf23a2cd6c9c22108aa7528f683a1f195ed7ccd23a4b1786ad36/lxml-6.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7d47866cb32fb503450b6edc9df355d10dc49836af2e89901bd6ac6b0896d9d9", size = 4618006, upload-time = "2026-05-18T19:18:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ca/ab7bfe2bf4c972af5e7878262845ead3a24a929a9b04bc11c7c1ece6c82a/lxml-6.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb7c9811bfaa8b1ed5ed319f5d370dfbcaa59d52ea64be2a5a85e18195930354", size = 4924139, upload-time = "2026-05-18T19:19:04.873Z" }, + { url = "https://files.pythonhosted.org/packages/6b/55/a0c72851dfee5ecc689f949723a73dea457758912542cb955b108eaf0d8f/lxml-6.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:762ff394d5bd56da0cf034a23dcce4e13923f15321a2adfa2ac00201dc6d3fca", size = 5082329, upload-time = "2026-05-18T19:19:09.728Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b6/0608f7d61a3b96cc67e5648a3d906e31a5082093e10e7be65b3886289938/lxml-6.1.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a088f287f7d8275a33c07f2cac6c50b9319309a0200a39e7e75d80c707723099", size = 4993564, upload-time = "2026-05-18T19:19:13.608Z" }, + { url = "https://files.pythonhosted.org/packages/4c/66/ae227524b066d29d55bf0b453d93d2d793c40218657d643dcbbca13b8faf/lxml-6.1.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e902da4b04e6b52e5893900d4b8ab46068f75f3561f01bf1080957f9fd932ed6", size = 5613467, upload-time = "2026-05-18T19:19:16.228Z" }, + { url = "https://files.pythonhosted.org/packages/a6/76/dbe4a00b50385e40194231dcfe5a12c059de7cf90e89c83407d2b085b719/lxml-6.1.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d4962d4c66bf830a7e59ed6cfc17d148149898a3aefa8ec6e59763e6e3ed085", size = 5228304, upload-time = "2026-05-18T19:19:19.354Z" }, + { url = "https://files.pythonhosted.org/packages/1c/01/00b1b8442ed2041793336868ba0b9ea4b13d7da7c085c6404c207a63bf79/lxml-6.1.1-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:581d4c8ae690a6609e64862dd6b7c2489635c2d13907fc2b20f2bc200ff1d21e", size = 5341607, upload-time = "2026-05-18T19:19:22.297Z" }, + { url = "https://files.pythonhosted.org/packages/63/36/1ad29931e9a4638bb707869f01d423a6c815f82152138d1a40dfcfde2b95/lxml-6.1.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:876e1ff5930ed8bf295ec5ef9a8155e9b6b1876bbf1deed8b3a8069311875a8f", size = 4700168, upload-time = "2026-05-18T19:19:25.133Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d1/a9536cecf9be18a0dc72d32bead283a2332d1ffebd2dd3ac70ce444686e5/lxml-6.1.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9eb9b5a968f6e0f6d640092a567e14529ff8cea2e29d00da6f78a79fa49f013c", size = 5232487, upload-time = "2026-05-18T19:19:28.603Z" }, + { url = "https://files.pythonhosted.org/packages/0e/77/b4fb1e03bf5d130e879214d3100092e386418807fb74dd0adc4b0a48f351/lxml-6.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aa49e06d94aba782c6a02eecb7e507969e7e7a41b267f1b359bb35585f295d5b", size = 5044231, upload-time = "2026-05-18T19:18:42.246Z" }, + { url = "https://files.pythonhosted.org/packages/26/4c/d00daeeb0a5530c4028a9232aa1b93db3ef4ed2158c116ea73c79a9765b3/lxml-6.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:70cdfd80589d59e43e18005dd7244e8895e93db8ab6a620b7e23df5445a4e3d2", size = 4769450, upload-time = "2026-05-18T19:18:48.013Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6a/715a3a8d156ce42f29cf014706f5410c2ff3b02267774110fc23266409fe/lxml-6.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:aad9aa39483ed8ec44d6d2e59e5b98a0d80676ef0d92f44bfc374836111f62f5", size = 5635874, upload-time = "2026-05-18T19:18:51.914Z" }, + { url = "https://files.pythonhosted.org/packages/45/37/0544bc21dde2a88f3a17b504e6fc79c0e01d25a33c2f6079724e9e72b9c7/lxml-6.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d49514be2f28d895c38cf9d2b72d7b9a07d00314519f456c0b50b53cfcf4c785", size = 5223987, upload-time = "2026-05-18T19:18:59.715Z" }, + { url = "https://files.pythonhosted.org/packages/4d/f8/f6a5e8185bcb28c2befae3d31f8e3df3b811cb0f47746517a81279fcafe1/lxml-6.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:47402e62c52ff5988c1e8c6c63177f5708bccf48e366dea4e3dcf1e645e04947", size = 5250276, upload-time = "2026-05-18T19:19:03.834Z" }, + { url = "https://files.pythonhosted.org/packages/c7/f2/1a2b9f1b7a49d45495369be7ef9ad05b262930f2eab3e3145706fca8083f/lxml-6.1.1-cp313-cp313-win32.whl", hash = "sha256:3483644525531e1d5762b0c44a8e18b6efba321b6dcf8a8952de10b037618bca", size = 3596903, upload-time = "2026-05-18T19:17:29.863Z" }, + { url = "https://files.pythonhosted.org/packages/e6/99/f4ffb024f238eec2131aaa09f3278fb6129cf892741bf68e1fc1afb8c100/lxml-6.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:a10bd2fd62e8ce916ececb342f348f190724a098c1faa056fdfb2a22ad5e8660", size = 3995869, upload-time = "2026-05-18T19:18:02.596Z" }, + { url = "https://files.pythonhosted.org/packages/d1/53/70eb8c5c6037f27448f1e3c54ebede9545a801ae63f0a7254afca4fe8e45/lxml-6.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:424aa57aca0897eb922aef34395bd1289b3b6f04e6bae20ea123c0c7e333cffc", size = 3658490, upload-time = "2026-05-19T19:22:53.846Z" }, + { url = "https://files.pythonhosted.org/packages/13/e2/2e325795566de01d0d7c3bb57d3c370616b2d07b01214e84eec5d3b10963/lxml-6.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:19b7ab10b210b0b3ad7985d9ac4eb66ab09a90b20fe6e2f7ba55d01a234345d0", size = 8577146, upload-time = "2026-05-18T19:18:17.765Z" }, + { url = "https://files.pythonhosted.org/packages/93/cf/5630b5e4be7d2e6bee8efe83865c925221103cf0221303b104ce134b01e2/lxml-6.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:c08e5c694306507275f2290073350c4f32e383db15213b2c69e7ff39c1193840", size = 4623866, upload-time = "2026-05-18T19:18:30.669Z" }, + { url = "https://files.pythonhosted.org/packages/d2/51/3904907c063451cf8d4a5c9fe0cad95fa1f4ec57f4e3884fa0731bd7a305/lxml-6.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:74a9717fd0d82effef5c2854f0d917231d5324b5a3eb7275c43ac9fa32f97a14", size = 4950022, upload-time = "2026-05-18T19:19:31.958Z" }, + { url = "https://files.pythonhosted.org/packages/94/cd/9c7611a51c37a2830928405817cc5d56a97f64fab83cc3f628748b135749/lxml-6.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:efe0374196335f93b53269acd811b944f2e6bdc88e8894f214bd636455484909", size = 5086695, upload-time = "2026-05-18T19:19:34.764Z" }, + { url = "https://files.pythonhosted.org/packages/da/d6/24e3b5906abb0b674ff2ae195bc3ce59708df2bcd17cf17703b2d7dd643a/lxml-6.1.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac931cdc9442c1763b8a8f6cd62c0c938737eafc5be75eff88df55fc73bc0d00", size = 5031642, upload-time = "2026-05-18T19:19:37.771Z" }, + { url = "https://files.pythonhosted.org/packages/2d/db/6ec54f99019838bff54785c51da07f189eb4676861c5f2730962b0d8d665/lxml-6.1.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aee395f5d0927f947758b4ec119fd5fc8ec71f07a1c5c52077b30b04c0fa6955", size = 5647338, upload-time = "2026-05-18T19:19:40.553Z" }, + { url = "https://files.pythonhosted.org/packages/42/3d/ef4dcfffd22d27a61805d8ed9f7fb888495bc6aa88648fa07c1eaa5586b6/lxml-6.1.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9395002973c827b3ed67db77e6ec09f092919a587022174554096a269378fb13", size = 5239528, upload-time = "2026-05-18T19:19:43.657Z" }, + { url = "https://files.pythonhosted.org/packages/62/bb/37fb3f0dff146bdcfa78eec47879273820b2a0bf350ec236ce14bd0b1c26/lxml-6.1.1-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:73bc2086f141224ebddb7fc5c6a36ca58b31b94b561e1dfe8e073e3270fad1e7", size = 5350730, upload-time = "2026-05-18T19:19:46.307Z" }, + { url = "https://files.pythonhosted.org/packages/90/42/43253f168388df4fae1f38c01df36ddb9bee39e2048167b54cdcbae85ea3/lxml-6.1.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:3779def59032b81e44a5f70096ef6bf2082f8d901937dca354474ba09782e245", size = 4697530, upload-time = "2026-05-18T19:19:49.889Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a8/c5a8504f81bbdfc8e7094c2c850cdb4ed6777fc4d5ddd9e5ab819f3b0d54/lxml-6.1.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:86c89b9d55ebf820ad7c90bc533410f0d098054f293351f10603c0c46ff598f5", size = 5250670, upload-time = "2026-05-18T19:19:53.199Z" }, + { url = "https://files.pythonhosted.org/packages/77/b7/c7e76ab18744d75e21f320ebf9ff9d1ceae2b54dd431ea5a64caf26c9672/lxml-6.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19607c6bbff2a44cf3fe8250abccd20942d3462473e0a721d01d379ed017e462", size = 5084485, upload-time = "2026-05-18T19:19:08.422Z" }, + { url = "https://files.pythonhosted.org/packages/31/31/b35c53f8ef7b7c31cacd23d3638652fff7bcd1deb6eedb709ab43b685908/lxml-6.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c6ed5141a5c7507cf3ee76bd363b0d6f801e3321adc35b5d825a23115faa5465", size = 4737635, upload-time = "2026-05-18T19:19:12.321Z" }, + { url = "https://files.pythonhosted.org/packages/d9/06/31f23c813a7fe8e0cb1b175e915b08c9bf4e86d225b210feadbdbe519667/lxml-6.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:62aeb7e85b5d60320b9d77eef2e773994e2c0ce10121b277e0a19804e1654a5a", size = 5670681, upload-time = "2026-05-18T19:19:15.001Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bc/ce619bccc89b1fd9ad8a8e1330ee3f3beff9f2ff95b712d7bbcdd6e22fc3/lxml-6.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:b1b963fd8f5caa68e99dfae060d54de1fe9cba899b8718b44a00cdca53c3e590", size = 5238229, upload-time = "2026-05-18T19:19:18.131Z" }, + { url = "https://files.pythonhosted.org/packages/2f/5d/b329acbbedc0b619ebc2be6cf7ee9ed07e80892c88d4dfd612c33805789a/lxml-6.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63876be28efefa04a1df615b46770e82042cce445cfdce55160522f57b231ccb", size = 5264191, upload-time = "2026-05-18T19:19:21.118Z" }, + { url = "https://files.pythonhosted.org/packages/d6/85/be36fb1425b30db3c3f9df75fe86343ebffb79e6320bd7f588e25bfeac39/lxml-6.1.1-cp314-cp314-win32.whl", hash = "sha256:7f7a92e8583f06b1fd49d01158143b8461cfcd135dcb10ec807270a3051bd603", size = 3657202, upload-time = "2026-05-18T19:17:39.509Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ce/3cf9a827342269f54d405a6202397de63f07c69cbd6ce7d183a3f0cba1e9/lxml-6.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:b2d444f2e66624d68e9c6b211e28a76e22fff5fcabcfff4deac18b529b7d4137", size = 4064497, upload-time = "2026-05-18T19:18:14.662Z" }, + { url = "https://files.pythonhosted.org/packages/d9/3e/1a957bde8f0760039e627f94699f82caa782c9d838d86c3d28245ee67212/lxml-6.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:3fd9728a2735fda14f4e8235830c86b539e9661e849665bf926d3f867943b4bf", size = 3741991, upload-time = "2026-05-19T19:22:59.111Z" }, + { url = "https://files.pythonhosted.org/packages/78/b2/00ed55b3a2efa4658fb795c38d1090ec9b3e8a6c3683d4441fa517f09c3b/lxml-6.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:787b2496d0dbe8cd180984e8d29e3a6f76e7ea34db781cb3bd55e4ba1ef8b4ee", size = 8827545, upload-time = "2026-05-18T19:18:41.193Z" }, + { url = "https://files.pythonhosted.org/packages/c0/73/74573db19baa618d5f266f2407898b087ff6927115b00b71e5fc1b700847/lxml-6.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2c8daa471358dc2d6fcf02165e80ec68f77871a286df95bc5cc3816153b0fd2c", size = 4735736, upload-time = "2026-05-18T19:18:46.761Z" }, + { url = "https://files.pythonhosted.org/packages/16/02/6f7061f4f95f51e545d48e87647c54791d204a4e881be4156e7a26ba5338/lxml-6.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:acd7d70b64c0aae0c7922cca83d288a16f5f6da523637697872253415269baef", size = 4970291, upload-time = "2026-05-18T19:19:56.215Z" }, + { url = "https://files.pythonhosted.org/packages/b0/02/55fc057d8283427dea7d6edb102e7a840239c77a64a983d92f62a304c0e9/lxml-6.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4f0dd2f01f9f8a89f565d000e03abcf0a13d692a346c8d22f628d49af098777a", size = 5102822, upload-time = "2026-05-18T19:19:59.223Z" }, + { url = "https://files.pythonhosted.org/packages/e4/48/8e1cf78d89d66850121d9255a2a24414c98f775da93b90cf976956c24b14/lxml-6.1.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b7e8a14c8634bf6f7a568634cb395305a6d964aeb5b7ee32248094bed3a7e2c", size = 5027923, upload-time = "2026-05-18T19:20:01.549Z" }, + { url = "https://files.pythonhosted.org/packages/ed/00/0632a0647612c8af24d26997b3b961397daa9d5b2581444805933629a4cb/lxml-6.1.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:86281fbdd6a8162756f8d603f37e3435bfa38043adb79c6dc6a2dfee065e7525", size = 5595843, upload-time = "2026-05-18T19:20:03.93Z" }, + { url = "https://files.pythonhosted.org/packages/bc/86/ab008a7dc360711b66858d61c80a5979a70a09f2aa2b05d9698df80b803d/lxml-6.1.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5d7152ec39ca7c402d8fb9bad86140a15b9503bd0c54484e3f1bbe3dd37ceca", size = 5224515, upload-time = "2026-05-18T19:20:06.381Z" }, + { url = "https://files.pythonhosted.org/packages/75/c6/2702ff375e728e34f56d9a45339a9cf7e4427e917f542225242d63a05afa/lxml-6.1.1-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:88d8cb75b9d82858497a5393e3c63cfbf03035225e4b35a49ed7ccb151e4dc0e", size = 5312511, upload-time = "2026-05-18T19:20:09.308Z" }, + { url = "https://files.pythonhosted.org/packages/b7/57/a5807c98f87a86f10ef9ffab35516df7c0f0c4b6d5d33e9f608ab9c04a31/lxml-6.1.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f64ec5397ea6a41fc1b4af0380d79b44a755b5531dcaccd9940fb260dca93038", size = 4639206, upload-time = "2026-05-18T19:20:11.704Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e1/8a0a2c35734812395f4da4eaf33748a7e5705bfb2a58b128da764339d5ec/lxml-6.1.1-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d34bbf07dbc7ca5970671b1512e928991fb5e9d95365636c9b2d8b4f53af405e", size = 5232404, upload-time = "2026-05-18T19:20:14.064Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e2/0e6a4dd5ad84d01d99aa7bae7cfefd4a760a0e0f8176818241de17d9b6c0/lxml-6.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:17e0e18d4ad8adbd0399291bc44845b69d9dd68439a3cdebdf35ff902ec05072", size = 5083769, upload-time = "2026-05-18T19:19:23.758Z" }, + { url = "https://files.pythonhosted.org/packages/a0/7e/161f33d463f6ffc1c7679104b65086dea120080d49dde4d238f015aaee2f/lxml-6.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:3ab541146f1f6968c462d6c2ac495148e8cdba2f8347700b2141b6ec5a75bf52", size = 4758936, upload-time = "2026-05-18T19:19:27.256Z" }, + { url = "https://files.pythonhosted.org/packages/f1/fb/2369825e3f6ca99305bf9f7b7085fda91c8b0922a89e54d900974aa3ef85/lxml-6.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:2a0217714657e023ef4293500f65aa20fce6164c8fd6b08fa5bd4a859fb14b9b", size = 5620296, upload-time = "2026-05-18T19:19:29.993Z" }, + { url = "https://files.pythonhosted.org/packages/30/90/d61e383146f74c5ab683947ea14dc7b82778838ab9b95ea73a23b60d0191/lxml-6.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:05a82eb6e1530a64f26225b55cbd178113bd0b5af1c2b625f25e5296742c26d2", size = 5228598, upload-time = "2026-05-18T19:19:33.523Z" }, + { url = "https://files.pythonhosted.org/packages/76/2d/2dafd8149e94b05bb070690efd5bb2680720681e03ff03fc57d2b70a1105/lxml-6.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9e36f163528fc50cbef305f02a5fd66d404edf7049cdaff211dbc2cba5a7013e", size = 5247845, upload-time = "2026-05-18T19:19:36.649Z" }, + { url = "https://files.pythonhosted.org/packages/ce/68/b30e913340c380ddac9580c6e6230991fc37240ec4f64704833e4f3e2769/lxml-6.1.1-cp314-cp314t-win32.whl", hash = "sha256:649dda677cf3bd6ac9ae14007ba0c824ded8ce5808b53fc7431d9140399118c1", size = 3897345, upload-time = "2026-05-18T19:17:33.562Z" }, + { url = "https://files.pythonhosted.org/packages/3c/4e/9eb2af5335545f9fbcd7af57bcf87c6025d31eaa31b14ec184a6c8675328/lxml-6.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:793033d6c5cdf33a573f910d9bea14ef8f5771820411d118da8e1182edb53d5e", size = 4393350, upload-time = "2026-05-18T19:18:10.076Z" }, + { url = "https://files.pythonhosted.org/packages/7f/2c/0f1e93c636720e8a3eb59af2bfda99d98b55891e1c53bc30c2e0e865f01b/lxml-6.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:58bb955caba94e467d2a96da17660d2d704e0675894cba21ab8a775b8621fd1c", size = 3817223, upload-time = "2026-05-19T19:22:56.823Z" }, +] + +[[package]] +name = "magika" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "onnxruntime" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/be/fa7d512ec15763ad7d8ba083e39bb445fa969ce5159361fa449a02569cf9/magika-1.0.3.tar.gz", hash = "sha256:ad3216012f6dd337be34c23ae3dfab36f0623bc62fbfb329f9a1852c9ad40304", size = 3041970, upload-time = "2026-05-04T08:41:53.124Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/eb/24d94db0530029649b266ec3ca8221c07f2754f56046181f13237d2518f5/magika-1.0.3-py3-none-any.whl", hash = "sha256:938d8e033953f2ddeb8c35dc423aa289ca116bfa7a71a778f6e77460f9025803", size = 2969548, upload-time = "2026-05-04T08:41:45.071Z" }, + { url = "https://files.pythonhosted.org/packages/23/be/9d7c34b53ff1da4f43224c109eb1f8bcb9ac335cc948d2f5359ba7f788f3/magika-1.0.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:de9af9c96892e610eefc920cca9e71179661d39d9d1d7acc1f28f357bcc8805e", size = 13863615, upload-time = "2026-05-04T08:41:46.734Z" }, + { url = "https://files.pythonhosted.org/packages/d6/78/4f341c974130a464f08813d54113ed9e63d5e9c963fbe398300838922a67/magika-1.0.3-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:3e9b49134e8116ee40b431664dcbed9e199413efddcce1a173c734b4e0521529", size = 16244594, upload-time = "2026-05-04T08:41:48.763Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/d414195bab93835ce764cb7471e7bf94e0eed396e455e1ff14de7f17d2de/magika-1.0.3-py3-none-win_amd64.whl", hash = "sha256:8a817588c177e81efadf2efa3690bfd46000279fd32e5bfc814776b007ee5d89", size = 13057718, upload-time = "2026-05-04T08:41:50.884Z" }, +] + +[[package]] +name = "mammoth" +version = "1.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cobble" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/92/aca6c4208b3a8e56a788b224e6c9b7bb70fc68e6641124fcf784008338e1/mammoth-1.12.1.tar.gz", hash = "sha256:40521e02568583b671d9976b0fbeed50be734b40f73ca8e1939ab7146bf69bbe", size = 53797, upload-time = "2026-08-09T14:11:20.096Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/b4/e7907b278386ffec0cf631db93836e02de9a6386add4653a52d7ac6b43ae/mammoth-1.12.1-py2.py3-none-any.whl", hash = "sha256:2af047e3e796faa25740112310ddf11f8de2a24c96dc57de3c87dfd7cb6543b3", size = 55091, upload-time = "2026-08-09T14:11:18.854Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -257,42 +823,778 @@ wheels = [ ] [[package]] -name = "packaging" -version = "26.3" +name = "mineru" +version = "3.4.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "click" }, + { name = "fast-langdetect" }, + { name = "fastapi" }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "json-repair" }, + { name = "loguru" }, + { name = "lxml" }, + { name = "magika" }, + { name = "mammoth" }, + { name = "mineru-vl-utils" }, + { name = "modelscope" }, + { name = "numpy" }, + { name = "openai" }, + { name = "opencv-python" }, + { name = "openpyxl" }, + { name = "pdftext" }, + { name = "pillow" }, + { name = "pylatexenc" }, + { name = "pypdf" }, + { name = "pypdfium2" }, + { name = "pypptx-with-oxml" }, + { name = "python-docx" }, + { name = "python-multipart" }, + { name = "reportlab" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "uvicorn" }, +] wheels = [ - { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, + { url = "https://files.pythonhosted.org/packages/94/a6/d60b161482cdcc2a4a8d01994320c55b5f804e26fda07845440a9d3080a8/mineru-3.4.5-py3-none-any.whl", hash = "sha256:4a73b865920bb9109c1b8b1bc46567e296bf0133a67106a04effd219536ae72d", size = 1541914, upload-time = "2026-08-14T07:55:46.975Z" }, +] + +[package.optional-dependencies] +pipeline = [ + { name = "ftfy" }, + { name = "onnxruntime" }, + { name = "pyclipper" }, + { name = "pyyaml" }, + { name = "safetensors" }, + { name = "shapely" }, + { name = "torch" }, + { name = "torchvision" }, + { name = "transformers" }, +] +vlm = [ + { name = "accelerate" }, + { name = "torch" }, + { name = "transformers" }, ] [[package]] -name = "prompt-toolkit" -version = "3.0.53" +name = "mineru-vl-utils" +version = "1.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "wcwidth" }, + { name = "aiofiles" }, + { name = "httpx" }, + { name = "httpx-retries" }, + { name = "loguru" }, + { name = "pillow" }, + { name = "pydantic" }, + { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl", hash = "sha256:01c0891d7f9237d5e339f7d3e42cdae80b7534abb1c7c0e3352efba6231492f2", size = 392288, upload-time = "2026-07-26T20:56:12.512Z" }, + { url = "https://files.pythonhosted.org/packages/93/93/5f7917231b3f9349f1b1477b6206a5f6d984ef51bc78fd315a7074a95cda/mineru_vl_utils-1.2.1-py3-none-any.whl", hash = "sha256:9129b987c7b942af4c38b555a1cf41fa660f4efae222acd602e61f9a94ce27df", size = 98303, upload-time = "2026-08-13T11:55:07.65Z" }, ] [[package]] -name = "pyyaml" -version = "6.0.3" +name = "modelscope" +version = "1.39.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +dependencies = [ + { name = "filelock" }, + { name = "modelscope-hub" }, + { name = "packaging" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "tqdm" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/33/ae/5118b6b8cea49c4071dc54dba80e63ed20da920bde388bf1ed7916f5cd5c/modelscope-1.39.1.tar.gz", hash = "sha256:40cc02051e4cd67931c70f1956b2a22efc1b35f2a432b5110204406d4a28e17f", size = 4548222, upload-time = "2026-08-04T08:27:03.936Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/ee/c5/ff578b44a7ba5d86edfaae1ce7db9082f95477bd22ccb2514c1aee4636b7/modelscope-1.39.1-py3-none-any.whl", hash = "sha256:c1567b9d319b11d815832d13c11f71a6413b19cf6374cef6937c54d830552a97", size = 6038125, upload-time = "2026-08-04T08:27:01.121Z" }, +] + +[[package]] +name = "modelscope-hub" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/9d/3fabfd2b147d94e1980d670fecd3c183999db04a71b80a546bcf37cc6f89/modelscope_hub-0.2.0.tar.gz", hash = "sha256:00288d3e08ad7fadfdd7539f4dffa9d75f9006c43c73abd33ea51767317f001c", size = 163316, upload-time = "2026-08-01T15:00:08.694Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/be/3b0e14c296a622c920287fc6d2c1b5a8668c8e0d98662f7b2bd8f3fcc779/modelscope_hub-0.2.0-py3-none-any.whl", hash = "sha256:84668c80c1d36d1fb1ea1ce17b707d77e044b92255288618c3b7de5b13834418", size = 156023, upload-time = "2026-08-01T15:00:07.335Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "networkx" +version = "3.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/80/db0b4559e57ec36362bedbb05530a87fafbcb6067708c946967a41d449e7/numpy-2.5.2.tar.gz", hash = "sha256:d482d171c406ae88c5b19cad3b6a1c4c5209f886ab74bc44c2c865c23f52d860", size = 20773161, upload-time = "2026-08-09T13:48:27.962Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/d2/6b24738a0ef4557d189b150046cd07823c50e4273e8aebd651222e24306f/numpy-2.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8e4cb9a754c8a0c62eaa88273a5fba3391f4a610d1dee893c0755da31c083f15", size = 16886595, upload-time = "2026-08-09T13:45:27.323Z" }, + { url = "https://files.pythonhosted.org/packages/65/60/f2d208d366f263f39c6e69ed309290717aab41078b6d04c9be2a84fa2a07/numpy-2.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:52c808f96484f5571a5cc863775ce50247c17dfb3b0361f8ed6b4b0456f80080", size = 11896845, upload-time = "2026-08-09T13:45:31.638Z" }, + { url = "https://files.pythonhosted.org/packages/3c/79/81e0bf24f4d020a2b1d5cd297a9f60c3f24eeb116f9bba5870443f7b6a4a/numpy-2.5.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:29d81e97f668489cba8ebfd796b9bdd453525d35dd9e162e2daec94bf3fc7740", size = 5343880, upload-time = "2026-08-09T13:45:34.373Z" }, + { url = "https://files.pythonhosted.org/packages/ba/cc/e3141cf06d1a8a2c7e107543fe1269c1d1af760d4d683c0794a4ee1127c2/numpy-2.5.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afb3f0632d6b2e3ba04dbce8d1e48d321b369138b73830b5ca371a0e8d479d56", size = 6682264, upload-time = "2026-08-09T13:45:36.7Z" }, + { url = "https://files.pythonhosted.org/packages/29/f1/2a64a307d92c5d98f5255a4014eb43bb6103ee477087b61ecae44a3aa9b9/numpy-2.5.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0aadf13b60048d501e05fa699efaf7734e2494f3498a4c2a5521d822640324f3", size = 15609566, upload-time = "2026-08-09T13:45:39.518Z" }, + { url = "https://files.pythonhosted.org/packages/7b/44/59a1eb68e773c4098d107ef34a0dbdeca501d72ffcfbff9a7707343921ce/numpy-2.5.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29b86ff8a6cc556b47ec6b64b194815cc80e6bf5eedcc6cddfd65318cb0b4eee", size = 16709995, upload-time = "2026-08-09T13:45:43.661Z" }, + { url = "https://files.pythonhosted.org/packages/8a/4c/3e54d4ddbc359a1295f8b633e8106bcd4d7d4a206e82df051bdfb3058755/numpy-2.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6950c4b7dd562453090548ba7f5da7e59f57f85663f15d5dcc60e249192f7e59", size = 16972511, upload-time = "2026-08-09T13:45:47.094Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9f/02e371638ebf19b66d46231e4be52999e87f32d1961b113bc45656608b22/numpy-2.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9727f472d2f3888053b8a75ab0cb94745a9de224bb5846dbadc0092101bc71d", size = 18465609, upload-time = "2026-08-09T13:45:50.808Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ae/ad6645abc7a3510fe48e8ea1ab4598166f500057ef4ebf38bfad4f1577de/numpy-2.5.2-cp313-cp313-win32.whl", hash = "sha256:4f9744f9fbdcea0bc552e8f19e1f141f811a3f9bc2be2cc6e86d982cab23e3f4", size = 6070204, upload-time = "2026-08-09T13:45:54.111Z" }, + { url = "https://files.pythonhosted.org/packages/15/20/f3489f86d81ea460b2bcdceaed094142ca6579f6be0ec527b781d39afe68/numpy-2.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:85aaccb24182c25df891ad0ec333585967e115269d5f1b17f2c9ae005bc96657", size = 12460532, upload-time = "2026-08-09T13:45:57.167Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/35b31dde1b283b79de828b80f876afd8c94e28fe1e9c375f89e261cc4c0d/numpy-2.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:bd68ece1553d2023c09a4226d9e41c586ad2d20594d1a456186c33513d2cb3f2", size = 10396725, upload-time = "2026-08-09T13:46:00.478Z" }, + { url = "https://files.pythonhosted.org/packages/ac/f8/c3b222bf075b50afd8e949a07a15c4b312a4a84bd8102a332bcd953cbbb4/numpy-2.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d787cf769c3baeb5f6235e778edb52c08dfa923789b5958f28e6450f96107cb1", size = 16885180, upload-time = "2026-08-09T13:46:03.939Z" }, + { url = "https://files.pythonhosted.org/packages/17/e1/2c1d4b1987795a92b5bbf7c24fe249ab96aa2573ab0d7604802c189d7b86/numpy-2.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:24b9dc2e3d84aa58523798805194e23e736f3f6ce2d1a5b92583ae734e6dbda8", size = 11907878, upload-time = "2026-08-09T13:46:07.045Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ee/d08226fc858044355983a6e5b94f08ff6f3969e0a2b160a4a89f0ddb3445/numpy-2.5.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:9e9413326d726c2545bfa65d2c0876871e8d8386e77f992c1d426e180bbd4323", size = 5354922, upload-time = "2026-08-09T13:46:10.04Z" }, + { url = "https://files.pythonhosted.org/packages/94/f0/6d3d933056440ebbc5e6bad92065fc6c26a48a84a36b1208580e94eea76c/numpy-2.5.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:60e902ac295855348a5ca2ea4c89108989a9f5fddfad3dfc0a8f36b10358567e", size = 6679168, upload-time = "2026-08-09T13:46:12.275Z" }, + { url = "https://files.pythonhosted.org/packages/c4/3b/ecd49dd90033cceb2704d88ca905d4d7d89b0e8c739608754ffd325fa820/numpy-2.5.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50e500dc868e9313530ce12ba470fe50ff3afe3d62993ed6eff652dacd555b65", size = 15624501, upload-time = "2026-08-09T13:46:15.322Z" }, + { url = "https://files.pythonhosted.org/packages/c7/99/461bd36dbdfac6c1c53efa370bd55a83227542d0d118f1677dbf1a3dacd5/numpy-2.5.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318b9a4c845dbea06708a29c84ee429cc3065048db34cdb799047643492050ee", size = 16713701, upload-time = "2026-08-09T13:46:18.949Z" }, + { url = "https://files.pythonhosted.org/packages/f9/9c/2b251df9e8a5d647b62b0cbc1b90a91850c1cf4859ecb532fd0b4eacff6c/numpy-2.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:34c319e2963be042673fb46570501b2f06c41924e17e3563d58646b4380dfb68", size = 16986065, upload-time = "2026-08-09T13:46:23.006Z" }, + { url = "https://files.pythonhosted.org/packages/8f/25/20de43f53ff1390534a124475055a19f01fe10c920a0fd11b8e18d6d6052/numpy-2.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f06571a052127dc1b4e8b83029b4d1b20daa2b64a31cdd181fc6bc774e9000eb", size = 18470031, upload-time = "2026-08-09T13:46:27.102Z" }, + { url = "https://files.pythonhosted.org/packages/56/5e/0c577ca308d6da5eb79b546ba10bbe5b60148192194e2da060913b1de4f1/numpy-2.5.2-cp314-cp314-win32.whl", hash = "sha256:2cc779226e476d1e1f08c74068c419e60f41a9e0e069c92f6671d31d5c985e98", size = 6121028, upload-time = "2026-08-09T13:46:30.046Z" }, + { url = "https://files.pythonhosted.org/packages/15/5c/7bcbd5b11f94199073320410cddcbb80cee62415bfeb540874b265c2d922/numpy-2.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:7587f53dfbd5edc0f7b87c6217b4c6d2d1f2ef9c3da70bc1315e7db5f8d7ec9d", size = 12597627, upload-time = "2026-08-09T13:46:32.886Z" }, + { url = "https://files.pythonhosted.org/packages/87/bc/4d0b06fba0da90ccc75af62823cb9dcedb6c9ea0cffa058cb2c9ee773a77/numpy-2.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:3e4c367352d3747784248a227fbec218e193b56f7e6692e3b64fc805478ecfdf", size = 10680414, upload-time = "2026-08-09T13:46:36.036Z" }, + { url = "https://files.pythonhosted.org/packages/cd/17/f429aac9dc08833a0d0f188eba38c532a751b1a1f2ca6018a37b455cb321/numpy-2.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b879fb674276e331513fb136b78dbc6bd3c848309e0d841cfd63be3896c4cfc1", size = 12026967, upload-time = "2026-08-09T13:46:39.084Z" }, + { url = "https://files.pythonhosted.org/packages/ca/9f/d0849de96a2a4ceaa16662f18ee13eaa9c0aa418269fdc8c4857c56b11da/numpy-2.5.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:fd0d703772bba096843785bd38371e31bb4a0c1151497ad5739d182114a73f7f", size = 5473874, upload-time = "2026-08-09T13:46:42.075Z" }, + { url = "https://files.pythonhosted.org/packages/89/3c/8df216d4a4a5422a3de045301cf7df8ea47286d76f5cb7160b0128ac26b7/numpy-2.5.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:3a2f061cebd9e3d23bdcfaaded5e2293a4c6a5b60fa42df85d410a725ce621bf", size = 6789276, upload-time = "2026-08-09T13:46:44.387Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3a/20d7e9891c4ddfadd6ff8d95bf4b29f353d8e1770553de2099880551dfb9/numpy-2.5.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6df895598c0edcb41030126c89e0f353b07d93238116143b7405e937359736c4", size = 15659154, upload-time = "2026-08-09T13:46:47.538Z" }, + { url = "https://files.pythonhosted.org/packages/aa/d6/f3aa3d2688bf501b858835c6bd087ae9b51a56ae6fca8e2b0990abd177af/numpy-2.5.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ab3d4a901f844ea836c3e80bf463c6a27d7f3c14e8e292fcf28d348b25b9bce", size = 16748909, upload-time = "2026-08-09T13:46:51.442Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8f/1c5cae8d2baf86ab802ae97a00be55bc7e21ebc11b12bbc33376c5f05342/numpy-2.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:cebc2d6dbb605a7703d59751dea4bd6b0ab127a5a4338a6f432df1936fef8b26", size = 17027685, upload-time = "2026-08-09T13:46:55.095Z" }, + { url = "https://files.pythonhosted.org/packages/5c/27/71d3467404aedc1c24ce79610f91b52b0b0f466c43a701aa56fc75c145ab/numpy-2.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:eaca7ff36f0f52e2111ec71f169d8fd3e889e7ddc0d2592e0d703fd8d3ce8fac", size = 18501181, upload-time = "2026-08-09T13:46:59.09Z" }, + { url = "https://files.pythonhosted.org/packages/14/2f/42921d27c40aea7e077f4a423ae509fd9220b028cd787bafefd8ab2b3a5f/numpy-2.5.2-cp314-cp314t-win32.whl", hash = "sha256:ddf47472af2e4280d79bac82304f5e80150211f1b9e614b760061d5fdfbb6eba", size = 6271085, upload-time = "2026-08-09T13:47:01.903Z" }, + { url = "https://files.pythonhosted.org/packages/75/e6/bad5f5d56de9b1971bac959963dda276d35c40f1854475005434bbe08692/numpy-2.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:44ef9675d908e65f9953063837c3277730f3f4437615a4cdab67b366cabaf884", size = 12787971, upload-time = "2026-08-09T13:47:04.963Z" }, + { url = "https://files.pythonhosted.org/packages/df/05/f608795cb34391acd67e38d94a3c36abd8d8576293a3a80727d7595c372c/numpy-2.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:eaa088384c46f519dacb93b7ec483a6d6b19a4a2085ae4f25ab9b1c43d387d1e", size = 10750306, upload-time = "2026-08-09T13:47:07.976Z" }, + { url = "https://files.pythonhosted.org/packages/33/c6/28de0191c5f82b7d42a0a51390ba98587048aa93a39fafb05bdbe6e8d00c/numpy-2.5.2-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:078f9b027b478c9379b9677babbf0f8b8f1ecfada27636d7b9a93990c638739f", size = 16885274, upload-time = "2026-08-09T13:47:11.439Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d1/973ca116000d244897e468ea1aff30b589e5022e3c8744b71706fe33bd57/numpy-2.5.2-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:50a68f4bacd8a2b33d8da3d2269d0d78500f86ea582e4786dc10f5ef2c2c6842", size = 11907846, upload-time = "2026-08-09T13:47:15.128Z" }, + { url = "https://files.pythonhosted.org/packages/78/d9/8c4b3937ef204cb2fd88d389ccd0f265a2ffb11f35a01d2064cf46714bd6/numpy-2.5.2-cp315-cp315-macosx_14_0_arm64.whl", hash = "sha256:e79aba74ffaf5f78a050d777c184cddf8fdffabab38acf5f3ef1fecbc17895d6", size = 5354892, upload-time = "2026-08-09T13:47:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/b6ee65ea2999fdb7023935e108e6fb776ee4082aa15f159acfa857e578c8/numpy-2.5.2-cp315-cp315-macosx_14_0_x86_64.whl", hash = "sha256:9a0731745a72a184490a582fb4af2533512bd071ace67785b5fdffc0ae58dce8", size = 6679309, upload-time = "2026-08-09T13:47:20.456Z" }, + { url = "https://files.pythonhosted.org/packages/43/f3/acb18d8b137a393c8e7803a8c994c9e64bde3930692a69d826993113a159/numpy-2.5.2-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ec954036759bcee3aa484f8603bd9c14f3e776293b85578b8734c2d72777c69", size = 15625850, upload-time = "2026-08-09T13:47:24.365Z" }, + { url = "https://files.pythonhosted.org/packages/a9/bf/a8e9bb0db815a0e265b5744ebedd3af0bd5faad8604e5b50a1cd012f3c91/numpy-2.5.2-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc649493697006bc90614a5f0bbc8cb3cb1866715c474e473694968d7e6b99ab", size = 16713664, upload-time = "2026-08-09T13:47:27.965Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/6e913736b3dd6582344af32418b5fb9dab34282e8a8174ae1d54ceb0fc13/numpy-2.5.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:cf7de32f486e4ac9e2d93b810f9e9ac72a728dd46a32a0bb403222f27f653514", size = 16986749, upload-time = "2026-08-09T13:47:31.541Z" }, + { url = "https://files.pythonhosted.org/packages/80/09/7d3b23eff5c7428ef6c01e6f7052bb60d504c4d33e317b36b8959c24ad97/numpy-2.5.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2ffa7bacab3e2ee1b19ed31766bb60bb380b68c23f051e199c5cc598afd68710", size = 18470495, upload-time = "2026-08-09T13:47:35.364Z" }, + { url = "https://files.pythonhosted.org/packages/a5/a4/68a321d825374f6eb677ffe8ef8c6b9a328304e6fd2e39d9530822776607/numpy-2.5.2-cp315-cp315-win32.whl", hash = "sha256:6b588cc8f902d6bff201c19fd00c43ab8545671e3554d014e12e14139e5e8617", size = 6120696, upload-time = "2026-08-09T13:47:38.561Z" }, + { url = "https://files.pythonhosted.org/packages/c8/23/deafbb1700f79fae9cd1e91220f133d124cc267de1b584da3fbf6db2f6cd/numpy-2.5.2-cp315-cp315-win_amd64.whl", hash = "sha256:07d4e89f3a9ab0a9ba24264ccdb642b3dd951b2281e8883a5481a4aa79cc31a7", size = 12597324, upload-time = "2026-08-09T13:47:41.401Z" }, + { url = "https://files.pythonhosted.org/packages/33/cd/3272ba105e3bbbdaeb11357eda31e7a6825ffe159e8171665660299a948f/numpy-2.5.2-cp315-cp315-win_arm64.whl", hash = "sha256:a610dc7e3c52edd39c2bc2375ff9c3fd59cb3ad00e4472d36f83bc1457145788", size = 10680466, upload-time = "2026-08-09T13:47:44.873Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0e/58370637b1bb70a5c9ce2b43f4b521ccb224e36ccb76a6596b17ae4b447c/numpy-2.5.2-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:40f4d451aed46a8046a1aae41c4e55fb3612273df9c502480135e1501576a34b", size = 16993947, upload-time = "2026-08-09T13:47:48.97Z" }, + { url = "https://files.pythonhosted.org/packages/10/93/2abcb807712b289d6d60fe4cf30532f98974a8396d885650f3ba5a13026e/numpy-2.5.2-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c081cbe16ba1ab53078e5ff29013621e33c509eedab055775d956427712c236e", size = 12025331, upload-time = "2026-08-09T13:47:52.646Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3a/2898e003a5fbaf87e76c039b4ee1f5eb390471b4ffe74887c1f34c4e791e/numpy-2.5.2-cp315-cp315t-macosx_14_0_arm64.whl", hash = "sha256:0090ccdd57ec2703e9b49d0bf554767370581c1dd0a6b2bb2b2d9def317d042a", size = 5472336, upload-time = "2026-08-09T13:47:55.403Z" }, + { url = "https://files.pythonhosted.org/packages/61/a5/23f69d07c544597b29758b31b55c27dc9d541012a2c1496189fef702aec2/numpy-2.5.2-cp315-cp315t-macosx_14_0_x86_64.whl", hash = "sha256:6a9bb119fb8dd21ba30b3f0e555b7e2b081bd9883af21ec9c1c633d161cda3a8", size = 6788387, upload-time = "2026-08-09T13:47:58.192Z" }, + { url = "https://files.pythonhosted.org/packages/15/ea/c0dbdbcf22f43782510a3e492dd3da73c6112b69cac8929d16d127536fc4/numpy-2.5.2-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a839318485284a6fb31be4f8f2c91c8f2cb22f4543c4a8903f12b0671ffe07cc", size = 15667096, upload-time = "2026-08-09T13:48:01.562Z" }, + { url = "https://files.pythonhosted.org/packages/fc/5e/29c73c31748cdb0f7566642125ba17fd5b56780cddf891b085dab27e4466/numpy-2.5.2-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba0a474801b8dc67b66bf465548abc90e82b44d2611b5770f33008dcabffe8ec", size = 16751730, upload-time = "2026-08-09T13:48:05.706Z" }, + { url = "https://files.pythonhosted.org/packages/47/95/02501e8454796bb58dadf7a99d3181e0b464bf264e1003039572f9779fac/numpy-2.5.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:0a4035ae1129ff8777f08bfbd44f1e5d8e9c049ce0c2dd78fc0d92c13e7251c0", size = 17038686, upload-time = "2026-08-09T13:48:09.627Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b5/53a681d91b5c82687067d8ea5035e02d917b5509d6f334cb06484a954714/numpy-2.5.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:77843ca236b777e67f8d6b3660ea116e499612703a0ecd7093f316201eb9d8e2", size = 18507727, upload-time = "2026-08-09T13:48:13.744Z" }, + { url = "https://files.pythonhosted.org/packages/42/06/6e11443f7b64ee376c860506091103bf68f92d2cab9e8d96d4501babf07c/numpy-2.5.2-cp315-cp315t-win32.whl", hash = "sha256:7354826bc6f8f69402e9b7fe28d15fcd34feebd74f856f111585c5b0c9fb0251", size = 6269775, upload-time = "2026-08-09T13:48:17.543Z" }, + { url = "https://files.pythonhosted.org/packages/f1/18/195d6b86cd72dbbc501edfa778005fa6b87afd34c153e46028cd3a0938f4/numpy-2.5.2-cp315-cp315t-win_amd64.whl", hash = "sha256:e5651f3f87add730ee6608d915009e19c911fba0cb000c7e3ea994b7d768eb12", size = 12782559, upload-time = "2026-08-09T13:48:21.023Z" }, + { url = "https://files.pythonhosted.org/packages/b4/07/458c344f0f0c178f4481dad5cca790626ffe4c34eabf9467069d06ee4999/numpy-2.5.2-cp315-cp315t-win_arm64.whl", hash = "sha256:5f8e00be2ec6f45f4e8a41a527f68d44a7d96fee92a650e4d8b1326f77f61e6e", size = 10748103, upload-time = "2026-08-09T13:48:24.21Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124, upload-time = "2025-03-07T01:43:53.556Z" }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318, upload-time = "2025-03-07T01:40:10.421Z" }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076, upload-time = "2025-03-07T01:41:59.817Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265, upload-time = "2025-03-07T01:39:43.533Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.19.0.56" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/b8/277c51962ee46fa3e5b203ac5f76107c650f781d6891e681e28e6f3e9fe6/nvidia_cudnn_cu12-9.19.0.56-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:08caaf27fe556aca82a3ee3b5aa49a77e7de0cfcb7ff4e5c29da426387a8267e", size = 656910700, upload-time = "2026-02-03T20:40:25.508Z" }, + { url = "https://files.pythonhosted.org/packages/c5/41/65225d42fba06fb3dd3972485ea258e7dd07a40d6e01c95da6766ad87354/nvidia_cudnn_cu12-9.19.0.56-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:ac6ad90a075bb33a94f2b4cf4622eac13dd4dc65cf6dd9c7572a318516a36625", size = 657906812, upload-time = "2026-02-03T20:44:12.638Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211, upload-time = "2025-03-07T01:44:56.873Z" }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705, upload-time = "2025-03-07T01:45:41.434Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754, upload-time = "2025-03-07T01:46:10.735Z" }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841, upload-time = "2025-03-07T01:46:54.356Z" }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129, upload-time = "2025-03-07T01:47:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557, upload-time = "2025-02-26T00:16:54.265Z" }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.28.9" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/c4/120d2dfd92dff2c776d68f361ff8705fdea2ca64e20b612fab0fd3f581ac/nvidia_nccl_cu12-2.28.9-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:50a36e01c4a090b9f9c47d92cec54964de6b9fcb3362d0e19b8ffc6323c21b60", size = 296766525, upload-time = "2025-11-18T05:49:16.094Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4e/44dbb46b3d1b0ec61afda8e84837870f2f9ace33c564317d59b70bc19d3e/nvidia_nccl_cu12-2.28.9-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:485776daa8447da5da39681af455aa3b2c2586ddcf4af8772495e7c532c7e5ab", size = 296782137, upload-time = "2025-11-18T05:49:34.248Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204, upload-time = "2025-03-07T01:49:43.612Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/6a/03aa43cc9bd3ad91553a88b5f6fb25ed6a3752ae86ce2180221962bc2aa5/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b48363fc6964dede448029434c6abed6c5e37f823cb43c3bcde7ecfc0457e15", size = 138936938, upload-time = "2025-09-06T00:32:05.589Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161, upload-time = "2025-03-07T01:42:23.922Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, +] + +[[package]] +name = "onnxruntime" +version = "1.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flatbuffers" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "protobuf" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/12/3807e2b17d9eb71d3cb78ed2ba76869b05c637c9b9d6112e636098b0c97a/onnxruntime-1.28.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:31410f544674f534c2f27348af52ef81682ca9c8719154bf4d48f0ef23823b1e", size = 19141759, upload-time = "2026-07-25T01:21:53.765Z" }, + { url = "https://files.pythonhosted.org/packages/c0/23/b46045c3bf67a9cf54c12f5df0f018a422c65fbb9d6072b10071bebfaae2/onnxruntime-1.28.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f649dd6f6452d12a8059888aa489fe519e062e18793dac72b9efa0f9fdb64135", size = 17049339, upload-time = "2026-07-25T01:21:43.005Z" }, + { url = "https://files.pythonhosted.org/packages/78/b6/8c5396e7894e77c5a7d1e026f3acb9dd39c4b5644e412e37a0055eaa3bc5/onnxruntime-1.28.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54fa221d669282bd8f582708ce4c96010a7e9fb0661f9006b37fe2fedafb73fe", size = 19214329, upload-time = "2026-07-25T01:22:04.133Z" }, + { url = "https://files.pythonhosted.org/packages/56/f1/51225c202edba4dfc94e1ea03f3d78f1aaf307da75fd792c0ce1946b2514/onnxruntime-1.28.0-cp313-cp313-win_amd64.whl", hash = "sha256:1a1a19175464665c9b8d50bc916f216cc0b569110045b7bbca8f9f290b186f58", size = 13755033, upload-time = "2026-07-25T01:22:29.302Z" }, + { url = "https://files.pythonhosted.org/packages/f4/db/f59f715edfdd96a051f32b5ef0e680a20a8755d4ecd75f63090e960e347a/onnxruntime-1.28.0-cp313-cp313-win_arm64.whl", hash = "sha256:cfab507abe09d6ffeb817eee07944d452fdc0b00fdcef34cab4db10a45e378c7", size = 13454175, upload-time = "2026-07-25T01:22:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/47/28/810314fa88647af9f4cdaf438a30ad1cfebebb53ded55499232d7a0094e6/onnxruntime-1.28.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac301f53b1930402fc46c368e268acfed02f3207272aaff05070d7e09f96f031", size = 17057307, upload-time = "2026-07-25T01:21:45.492Z" }, + { url = "https://files.pythonhosted.org/packages/3d/cc/9e9f193cc0f29f263a8f09ec08487aed6c96ee856d5fd77da32a425c1949/onnxruntime-1.28.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7f022a1103cae591c75fc4565589a515f2ddd14a6ac8e8a05812dfeda142e28", size = 19222954, upload-time = "2026-07-25T01:22:06.952Z" }, + { url = "https://files.pythonhosted.org/packages/4e/eb/952314c451d9463e5c9aed9978eec76cf32930d407d9ab8700dd0f4ea1ea/onnxruntime-1.28.0-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:8adff67a3f28257b37cfe945a7e952e4122666aa8c91a0380862e9fd4c2ed19f", size = 19143748, upload-time = "2026-07-25T01:21:56.297Z" }, + { url = "https://files.pythonhosted.org/packages/3f/e9/139180b4dd810329aaa42c238b4e6383c906202d98609ae29d66eb7c32b1/onnxruntime-1.28.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc2565e487b4896fb988d6383577d875d958e071fc5f6c3550bd5d02ae98264b", size = 17051950, upload-time = "2026-07-25T01:21:48.606Z" }, + { url = "https://files.pythonhosted.org/packages/03/88/9432428273356ad3c8aa01f52c1b3e7f53c4c0192748f41ad983872b436b/onnxruntime-1.28.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6afdc83f1317c136e92fc29f5ee9f058de59d87c0b22cee3fdbfbaa0ccc2098a", size = 19214924, upload-time = "2026-07-25T01:22:09.727Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e2/6feb3a43517aaf2b1bf7e46897ba5eb81a29717f7d7901420614d5ee4653/onnxruntime-1.28.0-cp314-cp314-win_amd64.whl", hash = "sha256:f2a3b9e30ce880d4ca54999cb313569e36da4f62eefe25f87be18f43e9a3a4d5", size = 14093738, upload-time = "2026-07-25T01:22:31.629Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8f/83974a1e201dc2e58e5e7111bcaeb1ca2413e9c41f505d26419ee9e3dddf/onnxruntime-1.28.0-cp314-cp314-win_arm64.whl", hash = "sha256:07fb3cbe990d6bf0ab3c22bfbbfb0e314151266046ea6edb4a07f556b4258c5f", size = 13821117, upload-time = "2026-07-25T01:22:22.387Z" }, + { url = "https://files.pythonhosted.org/packages/0d/83/00e606bc25c756d76a267370c39b7516ad52f9cf134d7ff2bff8b6108bc4/onnxruntime-1.28.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e562d6e36a749f6764481c0ddb0f2af3d0b5a3c164291361d08803c557f369af", size = 17055518, upload-time = "2026-07-25T01:21:51.08Z" }, + { url = "https://files.pythonhosted.org/packages/94/a9/68707e1ce345cbdbcd4df65932ebc82a673e917d63eda0007ebcff948691/onnxruntime-1.28.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f6e92367ddce1e4d33cf295024f40192be6c6171a09208f515ba169ced06c8e", size = 19222976, upload-time = "2026-07-25T01:22:12.474Z" }, +] + +[[package]] +name = "openai" +version = "2.54.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/9a/8c75e8c8a5b407a0586faeb2afac91674ff955c191ecc1d6d3b6669f6788/openai-2.54.0.tar.gz", hash = "sha256:e3e6f8bc1ba30ddf381ace1a14340eed381cb984a1a59bd0f34b5be3b5d49cfa", size = 1100285, upload-time = "2026-08-11T18:46:59.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl", hash = "sha256:89089789197ccdb87f173a03145ed1598d00795220c93e96cf712b1cbf5e5f2b", size = 1660351, upload-time = "2026-08-11T18:46:56.684Z" }, +] + +[[package]] +name = "opencv-python" +version = "5.0.0.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/4c/a438d23e09ce2033c09f7b784ad2fbdb0adf529e434101ed28f142226f98/opencv_python-5.0.0.93.tar.gz", hash = "sha256:66aac3e5b5faa48d4025816592f3af19e4bfc2c68dec067bae2dbb4ca10aa9e2", size = 81802749, upload-time = "2026-07-02T06:59:53.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/75/76f6ade78f6102c61034f828e2a22616708df2c9504bc8d6af9dd8f73dc5/opencv_python-5.0.0.93-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:198a75138241810206a17c829dbcc40a7cb1841cda538ca86cbbfc6c7d95f898", size = 48322443, upload-time = "2026-07-02T05:50:25.466Z" }, + { url = "https://files.pythonhosted.org/packages/15/8c/bc1bda6aae69a32e9d84fc34153ba104cd25226861eb4aea33b2cea4860d/opencv_python-5.0.0.93-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:6bbc32f59e1b1a7db7b39c81f63d00625f041d333037fd8702f6da52cc39108b", size = 34782755, upload-time = "2026-07-02T05:51:30.556Z" }, + { url = "https://files.pythonhosted.org/packages/f4/8a/b04776ec45d2dea08a1b176f1829201db3515d4ed16c35f8fcc9fa7beb16/opencv_python-5.0.0.93-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2b4272e736836f66c2d176e43ab8101f3a00d45654916399f52e150c58981ac", size = 50614064, upload-time = "2026-07-02T06:53:22.604Z" }, + { url = "https://files.pythonhosted.org/packages/95/54/eb47866b94f2b5b42dde17644b78055ef1ee05aae59962c7290e55270803/opencv_python-5.0.0.93-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f8b6d0a212253dd26ad338c812f1f23ca118fdf05a9c8c6b9444f161aa8c5881", size = 71064711, upload-time = "2026-07-02T06:54:13.148Z" }, + { url = "https://files.pythonhosted.org/packages/93/da/962579f1e703cbf8c5422fd1f576467dcb3b5b0b0b81c1471c979764353a/opencv_python-5.0.0.93-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:08d5d91d967b58d6db86073b2ad3eaef88ca4ebdfd45c9059bf59f5ded0c7ad2", size = 49798576, upload-time = "2026-07-02T06:54:33.781Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4c/c73f828fdbcd37eaf21d08fa852544a3ca7c2dbb3ea76873d64f2ea413d1/opencv_python-5.0.0.93-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c8de2dec111122a02e8beb28e16c31904992dfd6186560b142a92c71403c1039", size = 73783032, upload-time = "2026-07-02T06:55:03.415Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4b/edaf83b996ca5a1a3d8ccad485706b9c6d4742b13b9c4586bf1c1e7d9423/opencv_python-5.0.0.93-cp37-abi3-win32.whl", hash = "sha256:4b4b1a34c79bf8d3738e3cfe9a9e67b51a79663f6b692cbdad8c31f570da4157", size = 35564734, upload-time = "2026-07-02T05:49:57.704Z" }, + { url = "https://files.pythonhosted.org/packages/21/f0/9fa6e85cb10c8eb36a0222d27e50fe381b86ce49a55446bf39f491727564/opencv_python-5.0.0.93-cp37-abi3-win_amd64.whl", hash = "sha256:f90ba04b8f73bc5c3814037699739f0156f597338a98f05956c684e7c3ca10d2", size = 44000345, upload-time = "2026-07-02T05:49:54.971Z" }, +] + +[[package]] +name = "openpyxl" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "et-xmlfile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pdftext" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "numpy" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pypdfium2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b5/48/6c12661234ef71a9349bb1fbdd0259a6d8189376f664492e2c206ab3c397/pdftext-0.7.1.tar.gz", hash = "sha256:7484add28d48d8c04aab0076769f2d626454233de95de00c7b348cb6398045bd", size = 28483, upload-time = "2026-07-08T21:57:14.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/5d/997add0ca9f74d77afd9ab355b301a495420ce0b3258bf6954b00aa47465/pdftext-0.7.1-py3-none-any.whl", hash = "sha256:ffb47a36e7f0c9a295e16c0e0a9f6a323026f88416f8045330746604f7212986", size = 29712, upload-time = "2026-07-08T21:57:15.209Z" }, +] + +[[package]] +name = "pillow" +version = "12.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size = 4161684, upload-time = "2026-07-01T11:54:25.934Z" }, + { url = "https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size = 4255487, upload-time = "2026-07-01T11:54:27.935Z" }, + { url = "https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size = 3696433, upload-time = "2026-07-01T11:54:29.813Z" }, + { url = "https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size = 5345889, upload-time = "2026-07-01T11:54:31.97Z" }, + { url = "https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size = 4780109, upload-time = "2026-07-01T11:54:34.026Z" }, + { url = "https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size = 6263736, upload-time = "2026-07-01T11:54:36.131Z" }, + { url = "https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size = 6937129, upload-time = "2026-07-01T11:54:38.216Z" }, + { url = "https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size = 6339562, upload-time = "2026-07-01T11:54:40.354Z" }, + { url = "https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size = 7049439, upload-time = "2026-07-01T11:54:42.489Z" }, + { url = "https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size = 6473287, upload-time = "2026-07-01T11:54:44.9Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size = 7239691, upload-time = "2026-07-01T11:54:47.141Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size = 2568185, upload-time = "2026-07-01T11:54:49.137Z" }, + { url = "https://files.pythonhosted.org/packages/dc/01/001f65b68192f0228cc1dbbc8d2530ab5d58b61037ba0587f946fea607cd/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330", size = 4161736, upload-time = "2026-07-01T11:54:51.156Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d2/0219746d0fd16fc8a84498e79452375be3797d3ce4044596ce565164b84f/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217", size = 4255435, upload-time = "2026-07-01T11:54:53.414Z" }, + { url = "https://files.pythonhosted.org/packages/c8/02/8d0bc62ef0302318c46ff2a512822d2610e81c7aa46c9b3abe6cbaca5ad0/pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930", size = 3696262, upload-time = "2026-07-01T11:54:55.739Z" }, + { url = "https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8", size = 5350344, upload-time = "2026-07-01T11:54:57.657Z" }, + { url = "https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0", size = 4780131, upload-time = "2026-07-01T11:54:59.713Z" }, + { url = "https://files.pythonhosted.org/packages/b1/9d/8b2c807dbef61a5197c047afe99823787eb66f63daf9fb2432f91d6f0462/pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321", size = 6263757, upload-time = "2026-07-01T11:55:01.778Z" }, + { url = "https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b", size = 6936962, upload-time = "2026-07-01T11:55:03.93Z" }, + { url = "https://files.pythonhosted.org/packages/18/7e/e483414b35800b86b6f08dbbc7803fb5cd52c4d6f897f47d53ea2c7e6f65/pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198", size = 6339171, upload-time = "2026-07-01T11:55:05.989Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f4/68c491844841ede6bed70189546b3ee9731cf9f2cbad396faff5e1ccba45/pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130", size = 7048116, upload-time = "2026-07-01T11:55:08.131Z" }, + { url = "https://files.pythonhosted.org/packages/a3/34/77f3f793fed8efc7d243f21b33c5a3f0d1c97ee70346d3db855587e155ff/pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a", size = 6467209, upload-time = "2026-07-01T11:55:10.408Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e0/492879f69d94f91f60fc8cd05ba03650e9520afebb2fb7aa12777d7c7f38/pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d", size = 7237707, upload-time = "2026-07-01T11:55:12.745Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ac/6b11f2875f1c2ac040d84e1bbf9cf22a88038f901ca1037898b280b38365/pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838", size = 2565995, upload-time = "2026-07-01T11:55:14.736Z" }, + { url = "https://files.pythonhosted.org/packages/52/69/c2208e56af9bfc1913afb24020297a691eb1d4ef688474c8a04913f65e04/pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e", size = 5352503, upload-time = "2026-07-01T11:55:17.076Z" }, + { url = "https://files.pythonhosted.org/packages/07/70/e5686d753e898a45d778ff1718dba8516ead6ab6b95d85fc8c4b70650cf2/pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17", size = 4782956, upload-time = "2026-07-01T11:55:19.448Z" }, + { url = "https://files.pythonhosted.org/packages/d5/37/25c6692f06927ee973ff18c8d9ee98ad0b4d84ee67a09610c2dd1447958e/pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385", size = 6322855, upload-time = "2026-07-01T11:55:21.613Z" }, + { url = "https://files.pythonhosted.org/packages/cc/91/420637fcb8f1bc11029e403b4538e6694744428d8246118e45719f944556/pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c", size = 6989642, upload-time = "2026-07-01T11:55:24.006Z" }, + { url = "https://files.pythonhosted.org/packages/10/08/b94d7811281ccf0d143a1cf768d1c49e1e54af63e7b708ab2ee3eb87face/pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d", size = 6391281, upload-time = "2026-07-01T11:55:26.252Z" }, + { url = "https://files.pythonhosted.org/packages/d2/87/24233f785f55474dc02ce3e739c5528a77e3a862e9333d1dd7a25cc31f70/pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931", size = 7096716, upload-time = "2026-07-01T11:55:28.318Z" }, + { url = "https://files.pythonhosted.org/packages/23/26/fcb2f6e37175b04f53570b59937867e2b80ee1685e744023153028fc14f9/pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7", size = 6474125, upload-time = "2026-07-01T11:55:30.956Z" }, + { url = "https://files.pythonhosted.org/packages/90/de/3634abee5f1c9e13c56787b7d5517b0ba8d6de51700b95578cf338349c9f/pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c", size = 7242939, upload-time = "2026-07-01T11:55:34.044Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2a/fd13f8eb24de5714a6eb444a3d67e2842c6c576e159a43793adf23051351/pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45", size = 2567506, upload-time = "2026-07-01T11:55:35.988Z" }, + { url = "https://files.pythonhosted.org/packages/5d/dc/8fdce34ec725a33c81c6ba122b904d6b9024e50ea9ac7bede62fab54506c/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139", size = 4162063, upload-time = "2026-07-01T11:55:37.941Z" }, + { url = "https://files.pythonhosted.org/packages/76/66/2044b9a63d3b84ff048228dfcb7cd9bf0df983e8470971bf7d4c57b693de/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402", size = 4255549, upload-time = "2026-07-01T11:55:40.022Z" }, + { url = "https://files.pythonhosted.org/packages/52/7e/1f67e6f4ece6b582ee4b539decbcc9f848dc245a93ed8cd7338bafef72f1/pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c", size = 3696331, upload-time = "2026-07-01T11:55:41.98Z" }, + { url = "https://files.pythonhosted.org/packages/12/40/d306fc2c8e4d45d7f175c77edca7063be7b86fe7fe6e68f4353bf71d808c/pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f", size = 5350370, upload-time = "2026-07-01T11:55:44.028Z" }, + { url = "https://files.pythonhosted.org/packages/dd/44/668fb1437e8ce420f62d6106eb66e44a5971602a4d794615bdf79315d82d/pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701", size = 4780147, upload-time = "2026-07-01T11:55:46.073Z" }, + { url = "https://files.pythonhosted.org/packages/0c/08/93fa2e70e30a2d81547e481b6ee2bb9522117221fb1e0ce4b5df70967677/pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace", size = 6273659, upload-time = "2026-07-01T11:55:48.264Z" }, + { url = "https://files.pythonhosted.org/packages/f8/6d/043e96ff814fc31a33077e4cba86082167db520c93632afdf2042febbb0c/pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4", size = 6947439, upload-time = "2026-07-01T11:55:50.503Z" }, + { url = "https://files.pythonhosted.org/packages/af/92/ba71d2ee2ac0edf3fa33bd9d5ee9ee080da70b1766f3ca3934f9938ddac9/pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39", size = 6353577, upload-time = "2026-07-01T11:55:52.697Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ce/e63064e2122923ff687c8ad792d0d736a7b3920a56a46982e81a7fdd25d6/pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71", size = 7060394, upload-time = "2026-07-01T11:55:55.149Z" }, + { url = "https://files.pythonhosted.org/packages/54/76/a09cc3ccc8d773a7283d34c38bec1708f9e3cc932093cbc4c5e71ac4060b/pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827", size = 6467375, upload-time = "2026-07-01T11:55:57.769Z" }, + { url = "https://files.pythonhosted.org/packages/3e/03/1846c49ba3b1d5550392a4bbd06d6fb4578e1cd91a803198b5c90f5f7d53/pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5", size = 7237048, upload-time = "2026-07-01T11:55:59.975Z" }, + { url = "https://files.pythonhosted.org/packages/fb/bb/89f35dcc79610423f9f195504d7def7f0d1416a711541b42867e25fe3412/pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658", size = 2566006, upload-time = "2026-07-01T11:56:02.143Z" }, + { url = "https://files.pythonhosted.org/packages/30/88/707027ba09942dfa2c28759b5c222d769290a41c6d20ea60ec250801941f/pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf", size = 5352509, upload-time = "2026-07-01T11:56:04.2Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6d/00352fa25332c2569cd387851f568cc5a4b75a9adbfb37ac4fbce4c02eec/pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64", size = 4783167, upload-time = "2026-07-01T11:56:06.631Z" }, + { url = "https://files.pythonhosted.org/packages/13/4f/9e049dfa21af7c22427275720e2490267ba8138120add5c4c574deb69782/pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e", size = 6329237, upload-time = "2026-07-01T11:56:08.868Z" }, + { url = "https://files.pythonhosted.org/packages/36/16/cf6eeaae8d0fce8dd390a33437cf68c5d5bd73834a2bc6e2f14efda0ab45/pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777", size = 6997047, upload-time = "2026-07-01T11:56:11.379Z" }, + { url = "https://files.pythonhosted.org/packages/1e/69/dbf769bdd55f48bf5733cac28edc6364ffaa072ec9ba336266e4fe66be55/pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1", size = 6400440, upload-time = "2026-07-01T11:56:13.908Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e1/ffc9cfc2eea0d178da8018e18e959301ad9d6bc9f3edb7181e748a474b97/pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9", size = 7105895, upload-time = "2026-07-01T11:56:16.575Z" }, + { url = "https://files.pythonhosted.org/packages/18/f0/a5595c1e8c3ae44b9828cb2f0fa8155e5095ef04d6327b8f61cf44a3df85/pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8", size = 6474384, upload-time = "2026-07-01T11:56:18.855Z" }, + { url = "https://files.pythonhosted.org/packages/e4/04/62bcd9f844984c5938d3b05264a61d797a29d3e0812341a8204af70bbdee/pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418", size = 7243537, upload-time = "2026-07-01T11:56:21.214Z" }, + { url = "https://files.pythonhosted.org/packages/3d/68/1f3066acedf37673694a7141381d8f811ae97f30d34413d236abe7d489f1/pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59", size = 2567491, upload-time = "2026-07-01T11:56:23.506Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.53" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl", hash = "sha256:01c0891d7f9237d5e339f7d3e42cdae80b7534abb1c7c0e3352efba6231492f2", size = 392288, upload-time = "2026-07-26T20:56:12.512Z" }, +] + +[[package]] +name = "protobuf" +version = "7.35.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/01/9ef0afd7999eb9badb3a768b4aedd78c86d4c65cfaf1958ab276199e76b4/protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a", size = 458717, upload-time = "2026-06-11T21:55:40.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6", size = 433226, upload-time = "2026-06-11T21:55:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/dfb89eb0e652a1ff073c39a59fb5e3a83cfe9b57a2c83fa6d78270101767/protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799", size = 328847, upload-time = "2026-06-11T21:55:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/0f/58/dc12f2cd484951524af6e3382c785869b9b3fb5e52ee95ae23add53ee8f9/protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4", size = 344030, upload-time = "2026-06-11T21:55:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4", size = 327130, upload-time = "2026-06-11T21:55:35.921Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bc/6d6c7ba8709c85f8f2c390b2b118d6fb08a783676a572271851bf45a7d22/protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30", size = 428945, upload-time = "2026-06-11T21:55:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/8d0cb6f20a1ef7b18f1c8986ad5783f22f84cce39c6ce9a6e645ea55192e/protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87", size = 439996, upload-time = "2026-06-11T21:55:38.123Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9", size = 171659, upload-time = "2026-06-11T21:55:39.155Z" }, +] + +[[package]] +name = "psutil" +version = "7.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz", hash = "sha256:0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372", size = 493740, upload-time = "2026-01-28T18:14:54.428Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/08/510cbdb69c25a96f4ae523f733cdc963ae654904e8db864c07585ef99875/psutil-7.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2edccc433cbfa046b980b0df0171cd25bcaeb3a68fe9022db0979e7aa74a826b", size = 130595, upload-time = "2026-01-28T18:14:57.293Z" }, + { url = "https://files.pythonhosted.org/packages/d6/f5/97baea3fe7a5a9af7436301f85490905379b1c6f2dd51fe3ecf24b4c5fbf/psutil-7.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e78c8603dcd9a04c7364f1a3e670cea95d51ee865e4efb3556a3a63adef958ea", size = 131082, upload-time = "2026-01-28T18:14:59.732Z" }, + { url = "https://files.pythonhosted.org/packages/37/d6/246513fbf9fa174af531f28412297dd05241d97a75911ac8febefa1a53c6/psutil-7.2.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a571f2330c966c62aeda00dd24620425d4b0cc86881c89861fbc04549e5dc63", size = 181476, upload-time = "2026-01-28T18:15:01.884Z" }, + { url = "https://files.pythonhosted.org/packages/b8/b5/9182c9af3836cca61696dabe4fd1304e17bc56cb62f17439e1154f225dd3/psutil-7.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:917e891983ca3c1887b4ef36447b1e0873e70c933afc831c6b6da078ba474312", size = 184062, upload-time = "2026-01-28T18:15:04.436Z" }, + { url = "https://files.pythonhosted.org/packages/16/ba/0756dca669f5a9300d0cbcbfae9a4c30e446dfc7440ffe43ded5724bfd93/psutil-7.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:ab486563df44c17f5173621c7b198955bd6b613fb87c71c161f827d3fb149a9b", size = 139893, upload-time = "2026-01-28T18:15:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/1c/61/8fa0e26f33623b49949346de05ec1ddaad02ed8ba64af45f40a147dbfa97/psutil-7.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:ae0aefdd8796a7737eccea863f80f81e468a1e4cf14d926bd9b6f5f2d5f90ca9", size = 135589, upload-time = "2026-01-28T18:15:08.03Z" }, + { url = "https://files.pythonhosted.org/packages/81/69/ef179ab5ca24f32acc1dac0c247fd6a13b501fd5534dbae0e05a1c48b66d/psutil-7.2.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:eed63d3b4d62449571547b60578c5b2c4bcccc5387148db46e0c2313dad0ee00", size = 130664, upload-time = "2026-01-28T18:15:09.469Z" }, + { url = "https://files.pythonhosted.org/packages/7b/64/665248b557a236d3fa9efc378d60d95ef56dd0a490c2cd37dafc7660d4a9/psutil-7.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7b6d09433a10592ce39b13d7be5a54fbac1d1228ed29abc880fb23df7cb694c9", size = 131087, upload-time = "2026-01-28T18:15:11.724Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2e/e6782744700d6759ebce3043dcfa661fb61e2fb752b91cdeae9af12c2178/psutil-7.2.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fa4ecf83bcdf6e6c8f4449aff98eefb5d0604bf88cb883d7da3d8d2d909546a", size = 182383, upload-time = "2026-01-28T18:15:13.445Z" }, + { url = "https://files.pythonhosted.org/packages/57/49/0a41cefd10cb7505cdc04dab3eacf24c0c2cb158a998b8c7b1d27ee2c1f5/psutil-7.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e452c464a02e7dc7822a05d25db4cde564444a67e58539a00f929c51eddda0cf", size = 185210, upload-time = "2026-01-28T18:15:16.002Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/ff9bfb544f283ba5f83ba725a3c5fec6d6b10b8f27ac1dc641c473dc390d/psutil-7.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c7663d4e37f13e884d13994247449e9f8f574bc4655d509c3b95e9ec9e2b9dc1", size = 141228, upload-time = "2026-01-28T18:15:18.385Z" }, + { url = "https://files.pythonhosted.org/packages/f2/fc/f8d9c31db14fcec13748d373e668bc3bed94d9077dbc17fb0eebc073233c/psutil-7.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:11fe5a4f613759764e79c65cf11ebdf26e33d6dd34336f8a337aa2996d71c841", size = 136284, upload-time = "2026-01-28T18:15:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/e7/36/5ee6e05c9bd427237b11b3937ad82bb8ad2752d72c6969314590dd0c2f6e/psutil-7.2.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ed0cace939114f62738d808fdcecd4c869222507e266e574799e9c0faa17d486", size = 129090, upload-time = "2026-01-28T18:15:22.168Z" }, + { url = "https://files.pythonhosted.org/packages/80/c4/f5af4c1ca8c1eeb2e92ccca14ce8effdeec651d5ab6053c589b074eda6e1/psutil-7.2.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:1a7b04c10f32cc88ab39cbf606e117fd74721c831c98a27dc04578deb0c16979", size = 129859, upload-time = "2026-01-28T18:15:23.795Z" }, + { url = "https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:076a2d2f923fd4821644f5ba89f059523da90dc9014e85f8e45a5774ca5bc6f9", size = 155560, upload-time = "2026-01-28T18:15:25.976Z" }, + { url = "https://files.pythonhosted.org/packages/63/65/37648c0c158dc222aba51c089eb3bdfa238e621674dc42d48706e639204f/psutil-7.2.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b0726cecd84f9474419d67252add4ac0cd9811b04d61123054b9fb6f57df6e9e", size = 156997, upload-time = "2026-01-28T18:15:27.794Z" }, + { url = "https://files.pythonhosted.org/packages/8e/13/125093eadae863ce03c6ffdbae9929430d116a246ef69866dad94da3bfbc/psutil-7.2.2-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fd04ef36b4a6d599bbdb225dd1d3f51e00105f6d48a28f006da7f9822f2606d8", size = 148972, upload-time = "2026-01-28T18:15:29.342Z" }, + { url = "https://files.pythonhosted.org/packages/04/78/0acd37ca84ce3ddffaa92ef0f571e073faa6d8ff1f0559ab1272188ea2be/psutil-7.2.2-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b58fabe35e80b264a4e3bb23e6b96f9e45a3df7fb7eed419ac0e5947c61e47cc", size = 148266, upload-time = "2026-01-28T18:15:31.597Z" }, + { url = "https://files.pythonhosted.org/packages/b4/90/e2159492b5426be0c1fef7acba807a03511f97c5f86b3caeda6ad92351a7/psutil-7.2.2-cp37-abi3-win_amd64.whl", hash = "sha256:eb7e81434c8d223ec4a219b5fc1c47d0417b12be7ea866e24fb5ad6e84b3d988", size = 137737, upload-time = "2026-01-28T18:15:33.849Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" }, +] + +[[package]] +name = "pyclipper" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/21/3c06205bb407e1f79b73b7b4dfb3950bd9537c4f625a68ab5cc41177f5bc/pyclipper-1.4.0.tar.gz", hash = "sha256:9882bd889f27da78add4dd6f881d25697efc740bf840274e749988d25496c8e1", size = 54489, upload-time = "2025-12-01T13:15:35.015Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/d0/cbce7d47de1e6458f66a4d999b091640134deb8f2c7351eab993b70d2e10/pyclipper-1.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d49df13cbb2627ccb13a1046f3ea6ebf7177b5504ec61bdef87d6a704046fd6e", size = 264342, upload-time = "2025-12-01T13:15:12.697Z" }, + { url = "https://files.pythonhosted.org/packages/ce/cc/742b9d69d96c58ac156947e1b56d0f81cbacbccf869e2ac7229f2f86dc4e/pyclipper-1.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37bfec361e174110cdddffd5ecd070a8064015c99383d95eb692c253951eee8a", size = 139839, upload-time = "2025-12-01T13:15:13.911Z" }, + { url = "https://files.pythonhosted.org/packages/db/48/dd301d62c1529efdd721b47b9e5fb52120fcdac5f4d3405cfc0d2f391414/pyclipper-1.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:14c8bdb5a72004b721c4e6f448d2c2262d74a7f0c9e3076aeff41e564a92389f", size = 972142, upload-time = "2025-12-01T13:15:15.477Z" }, + { url = "https://files.pythonhosted.org/packages/07/bf/d493fd1b33bb090fa64e28c1009374d5d72fa705f9331cd56517c35e381e/pyclipper-1.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f2a50c22c3a78cb4e48347ecf06930f61ce98cf9252f2e292aa025471e9d75b1", size = 952789, upload-time = "2025-12-01T13:15:17.042Z" }, + { url = "https://files.pythonhosted.org/packages/cf/88/b95ea8ea21ddca34aa14b123226a81526dd2faaa993f9aabd3ed21231604/pyclipper-1.4.0-cp313-cp313-win32.whl", hash = "sha256:c9a3faa416ff536cee93417a72bfb690d9dea136dc39a39dbbe1e5dadf108c9c", size = 94817, upload-time = "2025-12-01T13:15:18.724Z" }, + { url = "https://files.pythonhosted.org/packages/ba/42/0a1920d276a0e1ca21dc0d13ee9e3ba10a9a8aa3abac76cd5e5a9f503306/pyclipper-1.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:d4b2d7c41086f1927d14947c563dfc7beed2f6c0d9af13c42fe3dcdc20d35832", size = 104007, upload-time = "2025-12-01T13:15:19.763Z" }, + { url = "https://files.pythonhosted.org/packages/1a/20/04d58c70f3ccd404f179f8dd81d16722a05a3bf1ab61445ee64e8218c1f8/pyclipper-1.4.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:7c87480fc91a5af4c1ba310bdb7de2f089a3eeef5fe351a3cedc37da1fcced1c", size = 265167, upload-time = "2025-12-01T13:15:20.844Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2e/a570c1abe69b7260ca0caab4236ce6ea3661193ebf8d1bd7f78ccce537a5/pyclipper-1.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81d8bb2d1fb9d66dc7ea4373b176bb4b02443a7e328b3b603a73faec088b952e", size = 139966, upload-time = "2025-12-01T13:15:22.036Z" }, + { url = "https://files.pythonhosted.org/packages/e8/3b/e0859e54adabdde8a24a29d3f525ebb31c71ddf2e8d93edce83a3c212ffc/pyclipper-1.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:773c0e06b683214dcfc6711be230c83b03cddebe8a57eae053d4603dd63582f9", size = 968216, upload-time = "2025-12-01T13:15:23.18Z" }, + { url = "https://files.pythonhosted.org/packages/f6/6b/e3c4febf0a35ae643ee579b09988dd931602b5bf311020535fd9e5b7e715/pyclipper-1.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bc45f2463d997848450dbed91c950ca37c6cf27f84a49a5cad4affc0b469e39", size = 954198, upload-time = "2025-12-01T13:15:24.522Z" }, + { url = "https://files.pythonhosted.org/packages/fc/74/728efcee02e12acb486ce9d56fa037120c9bf5b77c54bbdbaa441c14a9d9/pyclipper-1.4.0-cp314-cp314-win32.whl", hash = "sha256:0b8c2105b3b3c44dbe1a266f64309407fe30bf372cf39a94dc8aaa97df00da5b", size = 96951, upload-time = "2025-12-01T13:15:25.79Z" }, + { url = "https://files.pythonhosted.org/packages/e3/d7/7f4354e69f10a917e5c7d5d72a499ef2e10945312f5e72c414a0a08d2ae4/pyclipper-1.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:6c317e182590c88ec0194149995e3d71a979cfef3b246383f4e035f9d4a11826", size = 106782, upload-time = "2025-12-01T13:15:26.945Z" }, + { url = "https://files.pythonhosted.org/packages/63/60/fc32c7a3d7f61a970511ec2857ecd09693d8ac80d560ee7b8e67a6d268c9/pyclipper-1.4.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:f160a2c6ba036f7eaf09f1f10f4fbfa734234af9112fb5187877efed78df9303", size = 269880, upload-time = "2025-12-01T13:15:28.117Z" }, + { url = "https://files.pythonhosted.org/packages/49/df/c4a72d3f62f0ba03ec440c4fff56cd2d674a4334d23c5064cbf41c9583f6/pyclipper-1.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a9f11ad133257c52c40d50de7a0ca3370a0cdd8e3d11eec0604ad3c34ba549e9", size = 141706, upload-time = "2025-12-01T13:15:30.134Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0b/cf55df03e2175e1e2da9db585241401e0bc98f76bee3791bed39d0313449/pyclipper-1.4.0-cp314-cp314t-win32.whl", hash = "sha256:bbc827b77442c99deaeee26e0e7f172355ddb097a5e126aea206d447d3b26286", size = 105308, upload-time = "2025-12-01T13:15:31.225Z" }, + { url = "https://files.pythonhosted.org/packages/8f/dc/53df8b6931d47080b4fe4ee8450d42e660ee1c5c1556c7ab73359182b769/pyclipper-1.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:29dae3e0296dff8502eeb7639fcfee794b0eec8590ba3563aee28db269da6b04", size = 117608, upload-time = "2025-12-01T13:15:32.69Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, + { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, + { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, + { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, + { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, + { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, + { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, + { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, + { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, + { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, + { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, + { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, + { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, + { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, + { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, + { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, + { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, + { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, + { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/ca/31c57507b13119d7d3cfa1576dad2911a4861e3be07b579395f4e9d393f9/pydantic_settings-2.15.0.tar.gz", hash = "sha256:694b793e84f766ba76a90ebdefc01d0a9a045dab0382bee70393da93712ad117", size = 261253, upload-time = "2026-08-07T09:24:57.419Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl", hash = "sha256:0ba092c291c94baceb5eff768aa0d56400a457585bc0175925a5a5510303da42", size = 69413, upload-time = "2026-08-07T09:24:55.839Z" }, +] + +[[package]] +name = "pylatexenc" +version = "2.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/45/ddb0fb04acf95fe9cf9c369814dbdd08651bd2c9ee455f142651e06f4488/pylatexenc-2.11.tar.gz", hash = "sha256:305a072a99ce736246049c9da05841b9d718c0f7ea8888f5f596cf15cb621053", size = 165743, upload-time = "2026-07-25T17:26:31.534Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/06/3d67bd912ef337aa4856b466121d03f304aa1bb4d804f9298b6227cd227e/pylatexenc-2.11-py2.py3-none-any.whl", hash = "sha256:e78e7391d6c104f1ed150e21cfaa58016cdb50aa54406a2eecb793649ffdfdd0", size = 137533, upload-time = "2026-07-25T17:26:30.141Z" }, +] + +[[package]] +name = "pypdf" +version = "6.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/5a/df92d1c1ef8806ca28f20f978ee059894868d93de797a7e2edebe7fe1a43/pypdf-6.16.1.tar.gz", hash = "sha256:c4d1b43ddae921387321cf63936cd16a7743b91d2da92f165c149a195c972ba9", size = 7003737, upload-time = "2026-08-14T12:24:04.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/a1/724b18d6757ab7253a8fecd3a430eb8d980ed26872ba16651e7b5ddfc63f/pypdf-6.16.1-py3-none-any.whl", hash = "sha256:63fec31c4092ae50b6729beedcb469055b60d20c834bde1c402df241f371f644", size = 382924, upload-time = "2026-08-14T12:24:02.854Z" }, +] + +[[package]] +name = "pypdfium2" +version = "5.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/78/d9b45abb97a3686643f7c6472a5f7688f2013a373226121dc76b9debbacf/pypdfium2-5.10.1.tar.gz", hash = "sha256:f257d2011eb43c846b7e9f5a802e28646b29732763e4a35dd6ca76f9be580538", size = 272963, upload-time = "2026-06-15T10:09:16.179Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/49/0b85fcc0d236582143a25cf275b0b4f5d786f51eb07a89ec9c79d43efe18/pypdfium2-5.10.1-py3-none-android_23_arm64_v8a.whl", hash = "sha256:13abf7a9f5e0ddebc8bbcccea5f13ae5abe8a298ea219e125b0fc24c1d2171b4", size = 3409176, upload-time = "2026-06-15T10:08:36.017Z" }, + { url = "https://files.pythonhosted.org/packages/20/d2/2f522c5b2ad5166edf256bb4dbab97de5d07b2573f8a5630ddfcd1f8d4ee/pypdfium2-5.10.1-py3-none-android_23_armeabi_v7a.whl", hash = "sha256:a0dc52b56631e2f7edcdb22bae3b155aa840bec32c5bd05781e90baaecee88e7", size = 2866175, upload-time = "2026-06-15T10:08:37.955Z" }, + { url = "https://files.pythonhosted.org/packages/a7/be/477548c026c2badfdbf4afc3358b7135121fb5bec2e2effcb67e3a674d0b/pypdfium2-5.10.1-py3-none-macosx_12_0_arm64.whl", hash = "sha256:ebb9e63f92d15fc41b359fe7a187233dfae37548800e1fa09cb2fc466ac89951", size = 3621427, upload-time = "2026-06-15T10:08:39.969Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9b/0131c7f711b62c6edd6b200e9eb6340be6de4f6dc5baae625e3394d8d5fb/pypdfium2-5.10.1-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:d04f2050b6b32bb18624688b600543342a4ab3aacf64bf66521a5af72bbc7de1", size = 3682825, upload-time = "2026-06-15T10:08:42.181Z" }, + { url = "https://files.pythonhosted.org/packages/9d/3d/bddfceb6e67e54d6dd1ab6c0f1feff796a89596e40f6345a3b4cc6a3d408/pypdfium2-5.10.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0de53d2710ca9509fc2812340acc57c3f043697609068592d87de654f8cabf44", size = 3682206, upload-time = "2026-06-15T10:08:44.087Z" }, + { url = "https://files.pythonhosted.org/packages/58/08/dedeb25c6645fc8a5eda24f54e0b1d083b7334ababf5f518bb939d729cc0/pypdfium2-5.10.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:10a26ce04795f8ec079e81c707fcb5737061e8a78025babc3d6e36642e9c903a", size = 3413720, upload-time = "2026-06-15T10:08:45.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/69e1fc8b1216005243c6415183bbf6de1cda3f5a06758b3fa4a26a7385c6/pypdfium2-5.10.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be6d2a8d1bcfd777188e7aa55a25c83f34d54e8350ad8810fb32017787d9b0d9", size = 3812913, upload-time = "2026-06-15T10:08:47.45Z" }, + { url = "https://files.pythonhosted.org/packages/72/7f/132455a58ad736d76815c6cd1307532c3f433299d945b9d2f8cc2387c309/pypdfium2-5.10.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf4d2527f79f31c550490cc74c9f32e19385a944630a3ef4cd4d9b6f961fbf77", size = 4223220, upload-time = "2026-06-15T10:08:49.099Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8c/4d5804eca598bbe894e0a9a510807e221c1623e7276ce6b68fa2660dc933/pypdfium2-5.10.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ba127750bc3f4161461538d532d74491cd976f584f1753a6cee9cb821338ec1", size = 3738950, upload-time = "2026-06-15T10:08:50.821Z" }, + { url = "https://files.pythonhosted.org/packages/d1/7f/baac59bf14ff914d97789ee0368c22ae233aa857aa9c0726bcb515dbc4d7/pypdfium2-5.10.1-py3-none-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:80f30517ee089dfbbc6e9de6da365b6e8c0ce8f80c40b7d4025a3b1d3bbd8a70", size = 4029869, upload-time = "2026-06-15T10:08:52.494Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d7/a5d58a0bcba31a0e37ed636a76ef3d2d215733f28af61637287d061b0c54/pypdfium2-5.10.1-py3-none-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ad5f5de15febb788c6eb3853e58aceda9cd8c5187c92472abaeecf9558deb0cf", size = 3990927, upload-time = "2026-06-15T10:08:54.555Z" }, + { url = "https://files.pythonhosted.org/packages/da/1a/98eebd14b36812176297cf765d504ebeebc982f895c8a3a9fbd2717797de/pypdfium2-5.10.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8947fa3cd808da33960bdf8ff9e5247aa94ccd94f0b09bb3402e99498d83bcc9", size = 4989624, upload-time = "2026-06-15T10:08:56.284Z" }, + { url = "https://files.pythonhosted.org/packages/1c/20/f2e124d607b8bb90a9f1ce976afff38c70e215cd7ea86af784cb2e8a19dd/pypdfium2-5.10.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:139a6387a3a2652f288e53164268bb03af4fa221d78484ee18407053a60082a3", size = 4535124, upload-time = "2026-06-15T10:08:58.214Z" }, + { url = "https://files.pythonhosted.org/packages/59/ef/469ea87f668a32ff3280ea15e522e3a7858d2c80f1ecc320ece1244624c9/pypdfium2-5.10.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:172ff3e10358d66456e27fb0b8b5098e28ec24e51072eb4b5b86077d550e21bb", size = 5229373, upload-time = "2026-06-15T10:09:00.702Z" }, + { url = "https://files.pythonhosted.org/packages/c3/48/c7ed3001f0c5e28114c98bf918c8121e422a65ba7323e1e12f3f28e2d278/pypdfium2-5.10.1-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:09fda0609dc4749c9865a0315c447d6f2583a580693bcabd69980d3fbb22ad51", size = 5140010, upload-time = "2026-06-15T10:09:02.734Z" }, + { url = "https://files.pythonhosted.org/packages/b2/bc/00b731bfc1fdc0f3c7d91108fceb54978ff4f5a92336820e5ed6c12535ff/pypdfium2-5.10.1-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:6b01adcfe9aaf7a635a59bed5687fd4fd7b0da292664f050d4ebd2bfa5c70584", size = 4643310, upload-time = "2026-06-15T10:09:04.794Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e8/3ad242233f657c19092a8c83684c8154b8d02a826535a6a2591d91aa5dde/pypdfium2-5.10.1-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:610e14c37d2090b826dccc0604fc7e7612c0ce591190780ae228abdb9abb971e", size = 5087879, upload-time = "2026-06-15T10:09:06.861Z" }, + { url = "https://files.pythonhosted.org/packages/80/3f/9d0747a02ac3021ed3db7ac27c5187d97e78b0253a4bdfbf386666968474/pypdfium2-5.10.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f2803020952afa57e1e148adc19369b835154e1fa251a1ca85008ab6466a710f", size = 5047369, upload-time = "2026-06-15T10:09:08.883Z" }, + { url = "https://files.pythonhosted.org/packages/9e/41/7d5187e9527eae81890a3b13193442112ef788d61ddaa68a6d59ac447bec/pypdfium2-5.10.1-py3-none-win32.whl", hash = "sha256:8702bb4f01ddfc8e7757b41b4c2c8392ac17c9f0234476e1e69672ea7c6d6aa0", size = 3680056, upload-time = "2026-06-15T10:09:10.95Z" }, + { url = "https://files.pythonhosted.org/packages/16/1d/c62bd59dd8345cc4b640f942f465633f6b07b859d01ddb648610a7bf5c7c/pypdfium2-5.10.1-py3-none-win_amd64.whl", hash = "sha256:58da5b51fb7884c7d21a05062ab13edb011d1a08dfd9694f3d5d685df62796b9", size = 3812105, upload-time = "2026-06-15T10:09:12.684Z" }, + { url = "https://files.pythonhosted.org/packages/10/d5/21bac39125df8a93e99c04583486b58a62b5997d6b3541e3ad0f69053392/pypdfium2-5.10.1-py3-none-win_arm64.whl", hash = "sha256:e3301c2f7a66fb8cb57dba857d0c9e90215e178f6602a87c5a306cd98513dab8", size = 3600043, upload-time = "2026-06-15T10:09:14.606Z" }, +] + +[[package]] +name = "pypptx-with-oxml" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lxml" }, + { name = "pillow" }, + { name = "typing-extensions" }, + { name = "xlsxwriter" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/17/7a499cea9e03b37ef5a502a7792431b5e609328908e2e11b02453071367b/pypptx_with_oxml-1.0.3.tar.gz", hash = "sha256:a093d8c8e99dfcd0131ea98b4dbc0a0a40adf44869edbb74c57d0cb87b8e4208", size = 9767175, upload-time = "2026-01-30T08:51:32.511Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/d8/940fcaa6a1f3763d72751b6bc8054f40beeacd6e9e5b19069c6c73dab5af/pypptx_with_oxml-1.0.3-py3-none-any.whl", hash = "sha256:4b3ccf51185e0f9e60ebf2884e74153d7fcb00e7e4f0461404e96e0260d7bba1", size = 493041, upload-time = "2026-01-30T08:51:25.797Z" }, +] + +[[package]] +name = "python-docx" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lxml" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.32" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, @@ -323,6 +1625,12 @@ dev = [ { name = "commitizen" }, { name = "lefthook" }, ] +mineru = [ + { name = "mineru", extra = ["pipeline", "vlm"] }, + { name = "six" }, + { name = "torch" }, + { name = "torchvision" }, +] [package.metadata] @@ -331,6 +1639,12 @@ dev = [ { name = "commitizen", specifier = ">=4.17.0" }, { name = "lefthook", specifier = ">=2.1.10" }, ] +mineru = [ + { name = "mineru", extras = ["pipeline", "vlm"], specifier = ">=3.4.5" }, + { name = "six", specifier = ">=1.17.0" }, + { name = "torch", specifier = ">=2.6,<2.12", index = "https://download.pytorch.org/whl/cu128" }, + { name = "torchvision", index = "https://download.pytorch.org/whl/cu128" }, +] [[package]] name = "questionary" @@ -344,6 +1658,247 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/26/1062c7ec1b053db9e499b4d2d5bc231743201b74051c973dadeac80a8f43/questionary-2.1.1-py3-none-any.whl", hash = "sha256:a51af13f345f1cdea62347589fbb6df3b290306ab8930713bfae4d475a7d4a59", size = 36753, upload-time = "2025-08-28T19:00:19.56Z" }, ] +[[package]] +name = "regex" +version = "2026.7.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/3d/84165e4299ff76f3a40fe1f2abf939e976f693383a08d2beea6af62bd2c1/regex-2026.7.19-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f035d9dc1d25eff9d361456572231c7d27b5ccd473ca7dc0adfce732bd006d40", size = 496552, upload-time = "2026-07-19T00:17:36.808Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/a65293e6e4cf28eb7ee1be5335a5386c40d6742e9f47fafc8fec785e16c7/regex-2026.7.19-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42572142ed0b9d5d261ba727157c426510da78e20828b66bbb855098b8a4e38", size = 296983, upload-time = "2026-07-19T00:17:38.816Z" }, + { url = "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40b34dd88658e4fedd2fddbf0275ac970d00614b731357f425722a3ed1983d11", size = 291832, upload-time = "2026-07-19T00:17:40.726Z" }, + { url = "https://files.pythonhosted.org/packages/07/cd/42dfbabff3dfc9603c501c0e2e2c5adbb09d127b267bf5348de0af338c15/regex-2026.7.19-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c41c63992bf1874cebb6e7f56fd7d3c007924659a604ae3d90e427d40d4fd13", size = 796775, upload-time = "2026-07-19T00:17:42.382Z" }, + { url = "https://files.pythonhosted.org/packages/df/5d/f6a4839f2b934e3eed5973fd07f5929ee97d4c98939fb275ea23c274ee16/regex-2026.7.19-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d3372064506b94dd2c67c845f2db8062e9e9ba84d04e33cb96d7d33c11fe1ae", size = 865687, upload-time = "2026-07-19T00:17:44.185Z" }, + { url = "https://files.pythonhosted.org/packages/14/b0/b47d6c36049bc59806a50bd4c86ced70bbe058d787f80281b1d7a9b0e024/regex-2026.7.19-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fce7760bf283405b2c7999cab3da4e72f7deca6396013115e3f7a955db9760da", size = 911962, upload-time = "2026-07-19T00:17:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/2a/be/ff61f28f9273658cfe23acbbac5217221f6519960ed401e61dfdab12bc35/regex-2026.7.19-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0d702548d89d572b2929879bc883bb7a4c4709efafe4512cadee56c55c9bd15", size = 801817, upload-time = "2026-07-19T00:17:48.25Z" }, + { url = "https://files.pythonhosted.org/packages/c3/bb/8b4f7f26b333f9f79e1b453613c39bb4776f51d38ae66dd0ba31d6b354ca/regex-2026.7.19-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d446c6ac40bb6e05025ccee55b84d80fe9bf8e93010ffc4bb9484f13d498835f", size = 776908, upload-time = "2026-07-19T00:17:50.183Z" }, + { url = "https://files.pythonhosted.org/packages/09/13/610110fc5921d380516d03c26b652555f08aa0d23ea78a771231873c3638/regex-2026.7.19-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4c3501bfa814ab07b5580741f9bf78dfdfe146a04057f82df9e2402d2a975939", size = 784426, upload-time = "2026-07-19T00:17:52.454Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f5/1ef9e2a83a5947c57ebff0b377cb5727c3d5ec1992317a320d035cd0dbb6/regex-2026.7.19-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c4585c3e64b4f9e583b4d2683f18f5d5d872b3d71dcf24594b74ecc23602fa96", size = 860600, upload-time = "2026-07-19T00:17:54.229Z" }, + { url = "https://files.pythonhosted.org/packages/a0/02/073af33a3ec149241d11c80acea91e722aa0adbf05addd50f251c4fe89c3/regex-2026.7.19-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:571fde9741eb0ccde23dd4e0c1d50fbae910e901fa7e629faf39b2dda740d220", size = 765950, upload-time = "2026-07-19T00:17:56.041Z" }, + { url = "https://files.pythonhosted.org/packages/81/a9/d1e9f819dc394a568ef370cd56cf25394e957a2235f8370f23b576e5a475/regex-2026.7.19-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:15b364b9b98d6d2fe1a85034c23a3180ff913f46caddc3895f6fd65186255ccc", size = 851794, upload-time = "2026-07-19T00:17:57.897Z" }, + { url = "https://files.pythonhosted.org/packages/03/3a/8ae83eda7579feacdf984e71fb9e70635fb6f832eeddca58427ec4fca926/regex-2026.7.19-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffd8893ccc1c2fce6e0d6ca402d716fe1b29db70c7132609a05955e31b2aa8f2", size = 789845, upload-time = "2026-07-19T00:17:59.97Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/c195cbfe5a75fdec64d8f6554fd15237b837919d2c61bdc141d7c807b08b/regex-2026.7.19-cp313-cp313-win32.whl", hash = "sha256:f0fa4fa9c3632d708742baf2282f2055c11d888a790362670a403cbf48a2c404", size = 267135, upload-time = "2026-07-19T00:18:01.958Z" }, + { url = "https://files.pythonhosted.org/packages/b2/80/a11de8404b7272b70acb45c1c05987cce60b45d5693da2e176f0e390d564/regex-2026.7.19-cp313-cp313-win_amd64.whl", hash = "sha256:d51ffd3427640fa2da6ade574ceba932f210ad095f65fcc450a2b0a0d454868e", size = 277747, upload-time = "2026-07-19T00:18:04.121Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/0f5c8eff1b4f1f3d83276d365fccecf666afcc7d947420943bf394d07adb/regex-2026.7.19-cp313-cp313-win_arm64.whl", hash = "sha256:c670fe7be5b6020b76bc6e8d2196074657e1327595bca93a389e1a76ab130ad8", size = 277129, upload-time = "2026-07-19T00:18:05.821Z" }, + { url = "https://files.pythonhosted.org/packages/dc/4c/44b74742052cedda40f9ae469532a037112f7311a36669a891fba8984bb0/regex-2026.7.19-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db47b561c9afd884baa1f96f797c9ca369872c4b65912bc691cfa99e68340af2", size = 501134, upload-time = "2026-07-19T00:18:07.567Z" }, + { url = "https://files.pythonhosted.org/packages/f0/45/bbd038b5e39ee5613a5a689290145b40058cc152c41de9cc23639d2b9734/regex-2026.7.19-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65dcd28d3eba2ab7c2fd906485cc301392b47cc2234790d27d4e4814e02cdfda", size = 299418, upload-time = "2026-07-19T00:18:09.38Z" }, + { url = "https://files.pythonhosted.org/packages/65/38/c5bde94b4cedfd5850d64c3f08222d8e1600e84f6ee71d9b44b4b8163f74/regex-2026.7.19-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f2e7f8e2ab6c2922be02c7ec45185aa5bd771e2e57b95455ee343a44d8130dff", size = 294486, upload-time = "2026-07-19T00:18:11.188Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6a/2f5e107cb26c960b781967178899daf2787a7ab151844ed3c01d6fc95474/regex-2026.7.19-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe31f28c94402043161876a258a9c6f757cb485905c7614ce8d6cd40e6b7bdc1", size = 811643, upload-time = "2026-07-19T00:18:12.975Z" }, + { url = "https://files.pythonhosted.org/packages/37/d4/a2f963406d7d73a62eed84ba05a258afb6cad1b21aa4517443ce40506b78/regex-2026.7.19-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8f6fa298bb4f7f58a33334406218ba74716e68feddf5e4e54cd5d8082705abf", size = 871081, upload-time = "2026-07-19T00:18:14.733Z" }, + { url = "https://files.pythonhosted.org/packages/45/a3/44be546340bedb15f13063f5e7fe16793ea4d9ea2e805d09bd174ac27724/regex-2026.7.19-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cc1b2440423a851fad781309dd87843868f4f66a6bcd1ddb9225cf4ec2c84732", size = 917372, upload-time = "2026-07-19T00:18:16.724Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f6/e0870b0fd2a40dba0074e4b76e514b21313d37946c9248453e34ec43923e/regex-2026.7.19-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ac59a0900474a52b7c04af8196affc22bd9842acb0950df12f7b813e983609a", size = 816089, upload-time = "2026-07-19T00:18:18.617Z" }, + { url = "https://files.pythonhosted.org/packages/ae/27/957e8e22690ad6634572b39b71f130a6105f4d0718bb16849eac00fff147/regex-2026.7.19-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4896db1f4ce0576765b8272aa922df324e0f5b9bb2c3d03044ff32a7234a9aba", size = 785206, upload-time = "2026-07-19T00:18:20.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/a4/186e410941e731037c01166069ab86da9f65e8f8110c18009ccf4bd623ee/regex-2026.7.19-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4e6883a021db30511d9fb8cfb0f222ce1f2c369f7d4d8b0448f449a93ba0bdfc", size = 800431, upload-time = "2026-07-19T00:18:22.716Z" }, + { url = "https://files.pythonhosted.org/packages/73/9f/e4e10e023d291d64a33e246610b724493bf1ce98e0e59c9b7c837e5acfb7/regex-2026.7.19-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:09523a592938aa9f587fb74467c63ff0cf88fc3df14c82ab0f0517dcf76aaa62", size = 864906, upload-time = "2026-07-19T00:18:24.772Z" }, + { url = "https://files.pythonhosted.org/packages/24/57/ccb20b6be5f1f52a053d1ba2a8f7a077edb9d918248b8490d7506c6832b3/regex-2026.7.19-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:1ebac3474b8589fce2f9b225b650afd61448f7c73a5d0255a10cc6366471aed1", size = 773559, upload-time = "2026-07-19T00:18:27.008Z" }, + { url = "https://files.pythonhosted.org/packages/a3/82/f3b263cf8fad927dc102891da8502e718b7ff9d19af7a2a07c03865d7188/regex-2026.7.19-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4a0530bb1b8c1c985e7e2122e2b4d3aedd8a3c21c6bfddae6767c4405668b56e", size = 857739, upload-time = "2026-07-19T00:18:29.107Z" }, + { url = "https://files.pythonhosted.org/packages/47/2e/1687bd1b6c2aed5e672ccf845fc11557821fe7366d921b50889ea5ce57bf/regex-2026.7.19-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef7eeb108c47ce7bcc9513e51bcb1bf57e8f483d52fce68a8642e3527141ae0", size = 804522, upload-time = "2026-07-19T00:18:31.362Z" }, + { url = "https://files.pythonhosted.org/packages/76/7c/cc4e7655181b2d9235b704f2c5e19d8eff002bbc437bae59baee0e381aca/regex-2026.7.19-cp313-cp313t-win32.whl", hash = "sha256:64b6ca7391a1395c2638dd5c7456d67bea44fc6c5e8e92c5dc8aa6a8f23292b4", size = 269141, upload-time = "2026-07-19T00:18:33.479Z" }, + { url = "https://files.pythonhosted.org/packages/bb/14/961b4c7b05a2391c32dbc85e27773076671ef8f97f36cec70fe414734c02/regex-2026.7.19-cp313-cp313t-win_amd64.whl", hash = "sha256:f04b9f56b0e0614c0126be12c2c2d9f8850c1e57af302bd0a63bed379d4af974", size = 280036, upload-time = "2026-07-19T00:18:35.419Z" }, + { url = "https://files.pythonhosted.org/packages/ce/67/795644550d788ddbb6dc458c95895f8009978ea6d6ea76b005eb3f45e8c9/regex-2026.7.19-cp313-cp313t-win_arm64.whl", hash = "sha256:fcee38cd8e5089d6d4f048ba1233b3ad76e5954f545382180889112ff5cb712d", size = 279394, upload-time = "2026-07-19T00:18:37.454Z" }, + { url = "https://files.pythonhosted.org/packages/d2/25/0c4c452f8ef3efe456745b2f33195f5904b573fb4c2ff3f0cb9ec188461e/regex-2026.7.19-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a81758ed242b861b72e778ba34d41366441a2e10b16b472784c88da2dea7e2dd", size = 496750, upload-time = "2026-07-19T00:18:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/24/9e/b70ca6c1704f6c7cd32a9e143c86cc5968d10981eca284bad670c245ea7d/regex-2026.7.19-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4aa5435cdb3eb6f55fe98a171b05e3fbcd95fadaa4aa32acf62afd9b0cfdbcac", size = 297093, upload-time = "2026-07-19T00:18:41.583Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/0b692da2520d51fbff19c88b83d97e4c702909dd02386c585998b7e2dbed/regex-2026.7.19-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:60be8693a1dadc210bbcbc0db3e26da5f7d01d1d5a3da594e99b4fa42df404f5", size = 292043, upload-time = "2026-07-19T00:18:43.347Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a7/1d478e614016045a33feae57446215f9fd65b665a5ceb2f891fb3183bc52/regex-2026.7.19-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d19662dbedbe783d323196312d38f5ba53cf56296378252171985da6899887d3", size = 797214, upload-time = "2026-07-19T00:18:45.362Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ae/11b9c9411d92c30e3d2db32df5a31133e4a99a8fc397a604fd08f6c4bffb/regex-2026.7.19-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d15df07081d91b76ff20d43f94592ee110330152d617b730fdbe5ef9fb680053", size = 866433, upload-time = "2026-07-19T00:18:47.315Z" }, + { url = "https://files.pythonhosted.org/packages/b1/62/2b2efc4992f91d6d204b24c647c9f9412e85379d92b7c0ab9fdae622327e/regex-2026.7.19-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:56ad4d9f77df871a99e25c37091052a02528ec0eb059de928ee33956b854b45b", size = 911360, upload-time = "2026-07-19T00:18:49.588Z" }, + { url = "https://files.pythonhosted.org/packages/14/71/986ceea9aa3da548bf1357cad89b63915ec6d21ec957c8113b29ece567df/regex-2026.7.19-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7322ec6cc9fba9d49ab888bb82d67ac5625627aa168f0165139b17018df3fb8a", size = 801275, upload-time = "2026-07-19T00:18:51.767Z" }, + { url = "https://files.pythonhosted.org/packages/15/be/ce9d9534b2cda96eab32c548261224b9b4e220a4126f098f60f42ae7b4cd/regex-2026.7.19-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9c7472192ebfad53a6be7c4a8bfb2d64b81c0e93a1fc8c57e1dd0b638297b5d1", size = 777131, upload-time = "2026-07-19T00:18:54.053Z" }, + { url = "https://files.pythonhosted.org/packages/61/2b/58b5c710f2c3929515a25f3a1ca0dad0dcd4518d4fff3cf23bc7adb8dcd2/regex-2026.7.19-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c10b82c2634df08dfb13b1f04e38fe310d086ee092f4f69c0c8da234251e556e", size = 785020, upload-time = "2026-07-19T00:18:56.579Z" }, + { url = "https://files.pythonhosted.org/packages/84/03/5fe091935b74f15fe0f97998c215cae418d1c0413f6258c7d4d2e83aa37f/regex-2026.7.19-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:17ed5692f6acc4183e98331101a5f9e4f64d72fe58b753da4d444a2c77d05b12", size = 861263, upload-time = "2026-07-19T00:18:58.64Z" }, + { url = "https://files.pythonhosted.org/packages/d8/fa/d60bf82e10841eef62a9e32aac401468f05fddfbcb2942e342b1ba3d2433/regex-2026.7.19-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:22a992de9a0d91bda927bf02b94351d737a0302905432c88a53de7c4b9ce62e2", size = 766199, upload-time = "2026-07-19T00:19:00.705Z" }, + { url = "https://files.pythonhosted.org/packages/bf/5d/11e64d151b0662b81d6bf644c74dc118d461df85bdf2577fadbbf751788a/regex-2026.7.19-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:618a0aed532be87294c4477b0481f3aa0f1520f4014a4374dd4cf789b4cd2c97", size = 851317, upload-time = "2026-07-19T00:19:03.015Z" }, + { url = "https://files.pythonhosted.org/packages/7c/34/532efb87488d90807bae6a443d357ee5e2728a478c597619c8aaa17cc0bd/regex-2026.7.19-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ce9e679f776649746729b6c86382da519ef649c8e34cc41df0d2e5e0f6c36d4", size = 789557, upload-time = "2026-07-19T00:19:05.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/90/3a8d5ca977171ec3ae21a71207d2228b2663bde14d7f7ef0e6363ecf9290/regex-2026.7.19-cp314-cp314-win32.whl", hash = "sha256:73f272fba87b8ccfe70a137d02a54af386f6d27aa509fbffdd978f5947aae1aa", size = 272531, upload-time = "2026-07-19T00:19:07.487Z" }, + { url = "https://files.pythonhosted.org/packages/96/e1/8862885e70409de70e8c005f57fb2e7be8d9ef0317250d60f4c9660a300d/regex-2026.7.19-cp314-cp314-win_amd64.whl", hash = "sha256:d721e53758b2cca74990185eb0671dd466d7a388a1a45d0c6f4c13cef41a68ac", size = 280831, upload-time = "2026-07-19T00:19:09.46Z" }, + { url = "https://files.pythonhosted.org/packages/08/82/2693e53e29f9104d9de95d37ce4dd826bd32d5f9c0085d3aa6ac042675c4/regex-2026.7.19-cp314-cp314-win_arm64.whl", hash = "sha256:65fa6cb38ed5e9c3637e68e544f598b39c3b86b808ed0627a67b68320384b459", size = 281099, upload-time = "2026-07-19T00:19:11.398Z" }, + { url = "https://files.pythonhosted.org/packages/92/b7/9a01aa16461a18cde9d7b9c3ab21e501db2ce33725f53014342b91df2b0a/regex-2026.7.19-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:5a2721c8720e2cb3c209925dfb9200199b4b07361c9e01d321719404b21458b3", size = 501121, upload-time = "2026-07-19T00:19:13.425Z" }, + { url = "https://files.pythonhosted.org/packages/f3/5e/bbaeca815dc9191c424c94a4fdc5c87c75748a64a6271821212ebdd4e1a3/regex-2026.7.19-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:199535629f25caf89698039af3d1ad5fcae7f933e2112c73f1cdf49165c99518", size = 299415, upload-time = "2026-07-19T00:19:15.43Z" }, + { url = "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9b60d7814174f059e5de4ab98271cc5ba9259cfea55273a81544dceea32dc8d9", size = 294483, upload-time = "2026-07-19T00:19:17.879Z" }, + { url = "https://files.pythonhosted.org/packages/92/5f/40bacf91d0904f812e13bbbab3864604c463eced8afdc54aeaa50492ea95/regex-2026.7.19-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbece16025afda5e3031af0c4059207e61dcf73ef13af844964f57f387d1c435", size = 811833, upload-time = "2026-07-19T00:19:20.102Z" }, + { url = "https://files.pythonhosted.org/packages/94/7c/4902744261f775aeede8b5627314b38482da29cf49a57b66a6fb753246c5/regex-2026.7.19-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d24ecb4f5e009ea0bd275ee37ad9953b32005e2e5e60f8bbae16da0dbbf0d3a0", size = 871270, upload-time = "2026-07-19T00:19:22.365Z" }, + { url = "https://files.pythonhosted.org/packages/16/70/6980c9be6bf21c0a60ed3e0aea39cf419ecf3b08d1d9947bc56e196ef186/regex-2026.7.19-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8cae6fd77a5b72dae505084b1a2ee0360139faf72fedbab667cd7cc65aae7a6a", size = 917534, upload-time = "2026-07-19T00:19:24.529Z" }, + { url = "https://files.pythonhosted.org/packages/52/92/8b2bd872782ce8c42691e39acb38eb8efe014e5ddb78ad7d943d6f197ce9/regex-2026.7.19-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9724e6cb5e478cd7d8cabf027826178739cb18cf0e117d0e32814d479fa02276", size = 816135, upload-time = "2026-07-19T00:19:26.919Z" }, + { url = "https://files.pythonhosted.org/packages/de/2d/33a602f657bdc4041f17d79f92ab18261d255d91a06117a6e29df023e5e2/regex-2026.7.19-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:572fc57b0009c735ee56c175ea021b637a15551a312f56734277f923d6fd0f6c", size = 785492, upload-time = "2026-07-19T00:19:29.192Z" }, + { url = "https://files.pythonhosted.org/packages/9e/36/0987cf4cb271680064a70d24a475873775a151d0b7058698a006cb0cae4a/regex-2026.7.19-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:20568e182eb82d39a6bf7cff3fd58566f14c75c6f74b2c8c96537eecf9010e3a", size = 800658, upload-time = "2026-07-19T00:19:31.392Z" }, + { url = "https://files.pythonhosted.org/packages/a8/24/c14f31c135e1ba55fa4f9a58ca98d0842512bf6188230763c31c8f449e3b/regex-2026.7.19-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:1d58561843f0ff7dc78b4c28b5e2dc388f3eff94ebc8a232a3adba961fc00009", size = 865073, upload-time = "2026-07-19T00:19:33.485Z" }, + { url = "https://files.pythonhosted.org/packages/14/85/181a12211f22469f24d2de1ebddfe397d2396e2c29013b9a58134a91069a/regex-2026.7.19-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:61bb1bd45520aacd56dd80943bd34991fb5350afdd1f36f2282230fd5154a218", size = 773684, upload-time = "2026-07-19T00:19:35.599Z" }, + { url = "https://files.pythonhosted.org/packages/23/58/bd1a0c1a62251366f8d21f41b1ea3c76994962071b8b6ea42f72d505c0f0/regex-2026.7.19-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:cd3584591ea4429026cdb931b054342c2bcf189b44ff367f8d5c15bc092a2966", size = 857769, upload-time = "2026-07-19T00:19:37.738Z" }, + { url = "https://files.pythonhosted.org/packages/e4/4f/f7e2dad6756b2fe1fe75dd90a628c3b45f249d39f948dd90cd2476325417/regex-2026.7.19-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5cc26a66e212fa5d6c6170c3a40d99d888db3020c6fdab1523250d4341382e44", size = 804546, upload-time = "2026-07-19T00:19:40.229Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d7/01d31d5bdb09bc026fab77f59a371fdf8f9b292e4810546c56182ca70498/regex-2026.7.19-cp314-cp314t-win32.whl", hash = "sha256:2c4e61e2e1be56f63ec3cc618aa9e0de81ef6f43d177205451840022e24f5b78", size = 274526, upload-time = "2026-07-19T00:19:42.398Z" }, + { url = "https://files.pythonhosted.org/packages/52/0e/cea4ce73bc0a8247a0748228ae6669984c7e1f8134b6fa66e59c0572e0ea/regex-2026.7.19-cp314-cp314t-win_amd64.whl", hash = "sha256:c639ea314df70a7b2811e8020448c75af8c9445f5a60f8a4ced81c306a9380c2", size = 283763, upload-time = "2026-07-19T00:19:44.644Z" }, + { url = "https://files.pythonhosted.org/packages/6f/b6/26e41975febae63b7a6e3e02f32cff6cff2e4f10d19c929082f56aebf7c6/regex-2026.7.19-cp314-cp314t-win_arm64.whl", hash = "sha256:9a15e785f244f3e07847b984ce8773fc3da10a9f3c131cc49a4c5b4d672b4547", size = 283451, upload-time = "2026-07-19T00:19:46.639Z" }, +] + +[[package]] +name = "reportlab" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "charset-normalizer" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/d6/4b7b0cf56880eb96533e607967be6a939e344675601e033d113a0bfa1f4e/reportlab-5.0.0.tar.gz", hash = "sha256:e4494a0c6623ae213bb856fba523171b2b54a7bf629fda02d5e525a7b899a784", size = 3701928, upload-time = "2026-06-18T11:34:31.145Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/07/70085c17a369605f15e301d10ab902115019b1126c7253d964afc230c7d6/reportlab-5.0.0-py3-none-any.whl", hash = "sha256:9d5a3affa84919e1111ede580031266a570e93b1ce388219621347965ff1d93c", size = 1956710, upload-time = "2026-06-18T11:34:29.07Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "robust-downloader" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorlog" }, + { name = "requests" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/20/8d28efa080f58fa06f6378875ac482ee511c076369e5293a2e65128cf9a0/robust-downloader-0.0.2.tar.gz", hash = "sha256:08c938b96e317abe6b037e34230a91bda9b5d613f009bca4a47664997c61de90", size = 15785, upload-time = "2023-11-13T03:00:20.637Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/a1/779e9d0ebbdc704411ce30915a1105eb01aeaa9e402d7e446613ff8fb121/robust_downloader-0.0.2-py3-none-any.whl", hash = "sha256:8fe08bfb64d714fd1a048a7df6eb7b413eb4e624309a49db2c16fbb80a62869d", size = 15534, upload-time = "2023-11-13T03:00:18.957Z" }, +] + +[[package]] +name = "safetensors" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/a0/f718cda65b05407d228f97602cf60dca269c979867aa5beb25410de26cd3/safetensors-0.8.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c554f85858e05226d3c2828e32395e677434685d6d94594a41643361c5e837f0", size = 473568, upload-time = "2026-06-09T07:52:18.829Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b1/fa7c600e7dceae12e9606c7578cbc9ff1e1ed55844883ee5c92205e86226/safetensors-0.8.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:c80201d22cbf405b80647a60ada77bba06c8fba2da2743ba1e89cdcc39a81f25", size = 484562, upload-time = "2026-06-09T07:52:17.518Z" }, + { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" }, + { url = "https://files.pythonhosted.org/packages/91/4f/3175c9d75634e0e0dda0082794193521035edd7c70a6f212bf33ca06ddf4/safetensors-0.8.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4124502b78f03534117c848f87a39b8f31e577b15eff423bf8bfb95f2a8c30d0", size = 511823, upload-time = "2026-06-09T07:52:09.565Z" }, + { url = "https://files.pythonhosted.org/packages/20/87/846c289e7aa2299eff406335717cf43ce8777194ece8aad75772e0411615/safetensors-0.8.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc0a787ba8a35be368ee3574edfa2b1ad389eebd0a72e482ae275490e3f6c98", size = 633461, upload-time = "2026-06-09T07:52:11.128Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/8d64d9df2c45d5ded401df889d0ad90882804ca172d79ec4f0df8f727fe0/safetensors-0.8.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040070828e36dc8e122178bbbd5830ff9e97920affb84cbe0f46442497bed358", size = 545148, upload-time = "2026-06-09T07:52:13.603Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774", size = 516040, upload-time = "2026-06-09T07:52:16.29Z" }, + { url = "https://files.pythonhosted.org/packages/46/fb/cdaed17ceb2948784fd9c36b6fd3e951b608547cea81a48e8ee6f8cfdfcb/safetensors-0.8.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:fcdd41ec4628fee5799f807c73c353629130fbd942aa23d83c623dd6c9d52d78", size = 513832, upload-time = "2026-06-09T07:52:12.37Z" }, + { url = "https://files.pythonhosted.org/packages/0d/49/1e15de264dcc3b77943d2d0c56a95809956883b1c2d6d585c792523f180b/safetensors-0.8.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e9f537aa183a38ace122d27303dcd986b26bd2a7591f9181d7f0c396f4677ca", size = 559930, upload-time = "2026-06-09T07:52:14.743Z" }, + { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" }, + { url = "https://files.pythonhosted.org/packages/72/e3/68cd3fa5b48488e84add63e04cb12f3bc28ae4638c06d4508c6e88823d0e/safetensors-0.8.0-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:4a95ae2b05d7726d751da4ebf626a2ca782b706e101bd894c95bc2450b1cffcc", size = 786679, upload-time = "2026-06-09T07:52:21.322Z" }, + { url = "https://files.pythonhosted.org/packages/29/4b/1c19c509d56e01f4fbb3d0a2e597450f6cc04d1d56cf52defb0a62dfd715/safetensors-0.8.0-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:3ae091f16662658bdc019a4ff6cb4c085bb7d725eb5978b183ffd265863b6d2d", size = 765683, upload-time = "2026-06-09T07:52:22.594Z" }, + { url = "https://files.pythonhosted.org/packages/27/43/41c1621732edd934d868a00d1b891584c892a7b62a9aab82ea5a0a5623ee/safetensors-0.8.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8e080062fcde23be189565e1c3305d16751a218ecf9412c8601e64204eb6f846", size = 722361, upload-time = "2026-06-09T07:52:23.924Z" }, + { url = "https://files.pythonhosted.org/packages/8e/3f/73ccf82579412b4a71c4ca673f10b5f1f888d7cf5af7fe24f27d30307be4/safetensors-0.8.0-cp310-abi3-win32.whl", hash = "sha256:2ddf52eac562eda224f99acfa7889d02968c1fd59a5b011ae7d8137c37e9c02d", size = 342401, upload-time = "2026-06-09T07:52:28.895Z" }, + { url = "https://files.pythonhosted.org/packages/1b/6d/3fba214c1e5e0f69991677ec3bc17023f0421776975e1de0c682dca475e2/safetensors-0.8.0-cp310-abi3-win_amd64.whl", hash = "sha256:096ec1a98435df7beb08853bb5aa9081a84f23d0adc67ed1a0a10550f608373f", size = 355540, upload-time = "2026-06-09T07:52:27.832Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fc/7eedc3510d97878876e32774eebbeb61c43f148a96e915c84229a3e967aa/safetensors-0.8.0-cp310-abi3-win_arm64.whl", hash = "sha256:f7838e5135a406ad3e02efdcb8cf2e5397d368b0154537c4fec682dbc544d452", size = 340500, upload-time = "2026-06-09T07:52:26.745Z" }, +] + +[[package]] +name = "setuptools" +version = "81.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/1c/73e719955c59b8e424d015ab450f51c0af856ae46ea2da83eba51cc88de1/setuptools-81.0.0.tar.gz", hash = "sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a", size = 1198299, upload-time = "2026-02-06T21:10:39.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl", hash = "sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6", size = 1062021, upload-time = "2026-02-06T21:10:37.175Z" }, +] + +[[package]] +name = "shapely" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9", size = 315489, upload-time = "2025-09-24T13:51:41.432Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/90/98ef257c23c46425dc4d1d31005ad7c8d649fe423a38b917db02c30f1f5a/shapely-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b510dda1a3672d6879beb319bc7c5fd302c6c354584690973c838f46ec3e0fa8", size = 1832644, upload-time = "2025-09-24T13:50:44.886Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ab/0bee5a830d209adcd3a01f2d4b70e587cdd9fd7380d5198c064091005af8/shapely-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8cff473e81017594d20ec55d86b54bc635544897e13a7cfc12e36909c5309a2a", size = 1642887, upload-time = "2025-09-24T13:50:46.735Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5e/7d7f54ba960c13302584c73704d8c4d15404a51024631adb60b126a4ae88/shapely-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe7b77dc63d707c09726b7908f575fc04ff1d1ad0f3fb92aec212396bc6cfe5e", size = 2970931, upload-time = "2025-09-24T13:50:48.374Z" }, + { url = "https://files.pythonhosted.org/packages/f2/a2/83fc37e2a58090e3d2ff79175a95493c664bcd0b653dd75cb9134645a4e5/shapely-2.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ed1a5bbfb386ee8332713bf7508bc24e32d24b74fc9a7b9f8529a55db9f4ee6", size = 3082855, upload-time = "2025-09-24T13:50:50.037Z" }, + { url = "https://files.pythonhosted.org/packages/44/2b/578faf235a5b09f16b5f02833c53822294d7f21b242f8e2d0cf03fb64321/shapely-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a84e0582858d841d54355246ddfcbd1fce3179f185da7470f41ce39d001ee1af", size = 3979960, upload-time = "2025-09-24T13:50:51.74Z" }, + { url = "https://files.pythonhosted.org/packages/4d/04/167f096386120f692cc4ca02f75a17b961858997a95e67a3cb6a7bbd6b53/shapely-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc3487447a43d42adcdf52d7ac73804f2312cbfa5d433a7d2c506dcab0033dfd", size = 4142851, upload-time = "2025-09-24T13:50:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/48/74/fb402c5a6235d1c65a97348b48cdedb75fb19eca2b1d66d04969fc1c6091/shapely-2.1.2-cp313-cp313-win32.whl", hash = "sha256:9c3a3c648aedc9f99c09263b39f2d8252f199cb3ac154fadc173283d7d111350", size = 1541890, upload-time = "2025-09-24T13:50:55.337Z" }, + { url = "https://files.pythonhosted.org/packages/41/47/3647fe7ad990af60ad98b889657a976042c9988c2807cf322a9d6685f462/shapely-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:ca2591bff6645c216695bdf1614fca9c82ea1144d4a7591a466fef64f28f0715", size = 1722151, upload-time = "2025-09-24T13:50:57.153Z" }, + { url = "https://files.pythonhosted.org/packages/3c/49/63953754faa51ffe7d8189bfbe9ca34def29f8c0e34c67cbe2a2795f269d/shapely-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2d93d23bdd2ed9dc157b46bc2f19b7da143ca8714464249bef6771c679d5ff40", size = 1834130, upload-time = "2025-09-24T13:50:58.49Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ee/dce001c1984052970ff60eb4727164892fb2d08052c575042a47f5a9e88f/shapely-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01d0d304b25634d60bd7cf291828119ab55a3bab87dc4af1e44b07fb225f188b", size = 1642802, upload-time = "2025-09-24T13:50:59.871Z" }, + { url = "https://files.pythonhosted.org/packages/da/e7/fc4e9a19929522877fa602f705706b96e78376afb7fad09cad5b9af1553c/shapely-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8d8382dd120d64b03698b7298b89611a6ea6f55ada9d39942838b79c9bc89801", size = 3018460, upload-time = "2025-09-24T13:51:02.08Z" }, + { url = "https://files.pythonhosted.org/packages/a1/18/7519a25db21847b525696883ddc8e6a0ecaa36159ea88e0fef11466384d0/shapely-2.1.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:19efa3611eef966e776183e338b2d7ea43569ae99ab34f8d17c2c054d3205cc0", size = 3095223, upload-time = "2025-09-24T13:51:04.472Z" }, + { url = "https://files.pythonhosted.org/packages/48/de/b59a620b1f3a129c3fecc2737104a0a7e04e79335bd3b0a1f1609744cf17/shapely-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:346ec0c1a0fcd32f57f00e4134d1200e14bf3f5ae12af87ba83ca275c502498c", size = 4030760, upload-time = "2025-09-24T13:51:06.455Z" }, + { url = "https://files.pythonhosted.org/packages/96/b3/c6655ee7232b417562bae192ae0d3ceaadb1cc0ffc2088a2ddf415456cc2/shapely-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6305993a35989391bd3476ee538a5c9a845861462327efe00dd11a5c8c709a99", size = 4170078, upload-time = "2025-09-24T13:51:08.584Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8e/605c76808d73503c9333af8f6cbe7e1354d2d238bda5f88eea36bfe0f42a/shapely-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:c8876673449f3401f278c86eb33224c5764582f72b653a415d0e6672fde887bf", size = 1559178, upload-time = "2025-09-24T13:51:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/36/f7/d317eb232352a1f1444d11002d477e54514a4a6045536d49d0c59783c0da/shapely-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:4a44bc62a10d84c11a7a3d7c1c4fe857f7477c3506e24c9062da0db0ae0c449c", size = 1739756, upload-time = "2025-09-24T13:51:12.105Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c4/3ce4c2d9b6aabd27d26ec988f08cb877ba9e6e96086eff81bfea93e688c7/shapely-2.1.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:9a522f460d28e2bf4e12396240a5fc1518788b2fcd73535166d748399ef0c223", size = 1831290, upload-time = "2025-09-24T13:51:13.56Z" }, + { url = "https://files.pythonhosted.org/packages/17/b9/f6ab8918fc15429f79cb04afa9f9913546212d7fb5e5196132a2af46676b/shapely-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ff629e00818033b8d71139565527ced7d776c269a49bd78c9df84e8f852190c", size = 1641463, upload-time = "2025-09-24T13:51:14.972Z" }, + { url = "https://files.pythonhosted.org/packages/a5/57/91d59ae525ca641e7ac5551c04c9503aee6f29b92b392f31790fcb1a4358/shapely-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f67b34271dedc3c653eba4e3d7111aa421d5be9b4c4c7d38d30907f796cb30df", size = 2970145, upload-time = "2025-09-24T13:51:16.961Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cb/4948be52ee1da6927831ab59e10d4c29baa2a714f599f1f0d1bc747f5777/shapely-2.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:21952dc00df38a2c28375659b07a3979d22641aeb104751e769c3ee825aadecf", size = 3073806, upload-time = "2025-09-24T13:51:18.712Z" }, + { url = "https://files.pythonhosted.org/packages/03/83/f768a54af775eb41ef2e7bec8a0a0dbe7d2431c3e78c0a8bdba7ab17e446/shapely-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1f2f33f486777456586948e333a56ae21f35ae273be99255a191f5c1fa302eb4", size = 3980803, upload-time = "2025-09-24T13:51:20.37Z" }, + { url = "https://files.pythonhosted.org/packages/9f/cb/559c7c195807c91c79d38a1f6901384a2878a76fbdf3f1048893a9b7534d/shapely-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cf831a13e0d5a7eb519e96f58ec26e049b1fad411fc6fc23b162a7ce04d9cffc", size = 4133301, upload-time = "2025-09-24T13:51:21.887Z" }, + { url = "https://files.pythonhosted.org/packages/80/cd/60d5ae203241c53ef3abd2ef27c6800e21afd6c94e39db5315ea0cbafb4a/shapely-2.1.2-cp314-cp314-win32.whl", hash = "sha256:61edcd8d0d17dd99075d320a1dd39c0cb9616f7572f10ef91b4b5b00c4aeb566", size = 1583247, upload-time = "2025-09-24T13:51:23.401Z" }, + { url = "https://files.pythonhosted.org/packages/74/d4/135684f342e909330e50d31d441ace06bf83c7dc0777e11043f99167b123/shapely-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:a444e7afccdb0999e203b976adb37ea633725333e5b119ad40b1ca291ecf311c", size = 1773019, upload-time = "2025-09-24T13:51:24.873Z" }, + { url = "https://files.pythonhosted.org/packages/a3/05/a44f3f9f695fa3ada22786dc9da33c933da1cbc4bfe876fe3a100bafe263/shapely-2.1.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5ebe3f84c6112ad3d4632b1fd2290665aa75d4cef5f6c5d77c4c95b324527c6a", size = 1834137, upload-time = "2025-09-24T13:51:26.665Z" }, + { url = "https://files.pythonhosted.org/packages/52/7e/4d57db45bf314573427b0a70dfca15d912d108e6023f623947fa69f39b72/shapely-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5860eb9f00a1d49ebb14e881f5caf6c2cf472c7fd38bd7f253bbd34f934eb076", size = 1642884, upload-time = "2025-09-24T13:51:28.029Z" }, + { url = "https://files.pythonhosted.org/packages/5a/27/4e29c0a55d6d14ad7422bf86995d7ff3f54af0eba59617eb95caf84b9680/shapely-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b705c99c76695702656327b819c9660768ec33f5ce01fa32b2af62b56ba400a1", size = 3018320, upload-time = "2025-09-24T13:51:29.903Z" }, + { url = "https://files.pythonhosted.org/packages/9f/bb/992e6a3c463f4d29d4cd6ab8963b75b1b1040199edbd72beada4af46bde5/shapely-2.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a1fd0ea855b2cf7c9cddaf25543e914dd75af9de08785f20ca3085f2c9ca60b0", size = 3094931, upload-time = "2025-09-24T13:51:32.699Z" }, + { url = "https://files.pythonhosted.org/packages/9c/16/82e65e21070e473f0ed6451224ed9fa0be85033d17e0c6e7213a12f59d12/shapely-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:df90e2db118c3671a0754f38e36802db75fe0920d211a27481daf50a711fdf26", size = 4030406, upload-time = "2025-09-24T13:51:34.189Z" }, + { url = "https://files.pythonhosted.org/packages/7c/75/c24ed871c576d7e2b64b04b1fe3d075157f6eb54e59670d3f5ffb36e25c7/shapely-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:361b6d45030b4ac64ddd0a26046906c8202eb60d0f9f53085f5179f1d23021a0", size = 4169511, upload-time = "2025-09-24T13:51:36.297Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f7/b3d1d6d18ebf55236eec1c681ce5e665742aab3c0b7b232720a7d43df7b6/shapely-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:b54df60f1fbdecc8ebc2c5b11870461a6417b3d617f555e5033f1505d36e5735", size = 1602607, upload-time = "2025-09-24T13:51:37.757Z" }, + { url = "https://files.pythonhosted.org/packages/9a/f6/f09272a71976dfc138129b8faf435d064a811ae2f708cb147dccdf7aacdb/shapely-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:0036ac886e0923417932c2e6369b6c52e38e0ff5d9120b90eef5cd9a5fc5cae9", size = 1796682, upload-time = "2025-09-24T13:51:39.233Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/99/a6ca3beb3ccacb41fb3321d8a60e5566f9e6467601ef8eba6a17e1b89778/soupsieve-2.9.2.tar.gz", hash = "sha256:4a55d8cf158a9c2e587fa4922f1bbb91d68ac829e2d6f25403a85747c71daf74", size = 122445, upload-time = "2026-08-07T00:57:24.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/dc/ad025c1ee131eba60c69f4dd5779b18fcf1e6b21a343e2162a84d5d133c7/soupsieve-2.9.2-py3-none-any.whl", hash = "sha256:8089a26fd974ca7a1f30276d3d8492ab266ab15af581642dfe8aa162e0c1c823", size = 37370, upload-time = "2026-08-07T00:57:23.524Z" }, +] + +[[package]] +name = "starlette" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b5/b4/205b0d5241d934e8add0c38aa924c4f9fb7330834ff11e5444db964ec3f9/starlette-1.6.0.tar.gz", hash = "sha256:d4e3ac5e546444960c710297a3c9fc3f7ebae1b7e963f3d36173b49da535be9b", size = 2716969, upload-time = "2026-08-08T18:27:57.512Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl", hash = "sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c", size = 75969, upload-time = "2026-08-08T18:27:56.196Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + [[package]] name = "termcolor" version = "3.3.0" @@ -353,6 +1908,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, ] +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, +] + [[package]] name = "tomlkit" version = "0.15.1" @@ -362,6 +1943,156 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/13/bc/8c13eb66537dce1d2bd3a57132902f38d0e7f5bb46fa9f4daed9fe9d76ee/tomlkit-0.15.1-py3-none-any.whl", hash = "sha256:177a05aece5a8ca5266fd3c448abb47b8d352f09d477d3ca8332db4d89b24304", size = 49449, upload-time = "2026-07-17T01:48:05.728Z" }, ] +[[package]] +name = "torch" +version = "2.11.0+cu128" +source = { registry = "https://download.pytorch.org/whl/cu128" } +dependencies = [ + { name = "cuda-bindings", marker = "sys_platform == 'linux'" }, + { name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" }, + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cudnn-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "sys_platform == 'linux'" }, + { name = "setuptools" }, + { name = "sympy" }, + { name = "triton", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7db3580106bba044da5b8950f3fb8fe5f31999eaab3f6a3aa2ac5d202c3684d2", upload-time = "2026-04-27T17:45:35Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:db964b33c55035a72ab3e2162287af8f1cc276039c65d015740cc88c26dcedf7", upload-time = "2026-04-27T17:46:18Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp313-cp313-win_amd64.whl", hash = "sha256:6f367e62fd81b75cdf23ca4b75ced834d2db2cf98d1588ac935bde345de9de23", upload-time = "2026-04-27T17:48:09Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd1cf1005c5fe419194ee294b7b584ba5ad0f2fb1778b3fe5a7b9c3f4617ddbc", upload-time = "2026-04-27T17:50:01Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:74b628dbc71603977b09f4e140792c6e997081a35ef3421555f3f6e201b81210", upload-time = "2026-04-27T17:50:42Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp313-cp313t-win_amd64.whl", hash = "sha256:c2a5984deba8e001d166bf9cb83b8351f63a28b009e1a2fa0e4bbf08c90b259b", upload-time = "2026-04-27T17:52:32Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:baa52f7b8a53cab16587b10f1c27d1000ca033f97236878b685b75d5a1b92408", upload-time = "2026-04-27T17:54:24Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d389a850677f0d24dafae1573644034428d8d3b9c80b51d55ba62fed7e6c8777", upload-time = "2026-04-27T17:55:03Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314-win_amd64.whl", hash = "sha256:d6c21797ff75271b4fbdd905e2d703be4ecea5ea5bbdde4d1c201e9c71bc411d", upload-time = "2026-04-27T17:56:46Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:06849e9311dbb0617c97557d9c26c99a9e1c4f2ac9cb8e9b6d9b420d522acb91", upload-time = "2026-04-27T17:58:48Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:169a9987e1f84f0c5eee07544b3a34827a163ac9180e23abf0c3548f1335762c", upload-time = "2026-04-27T17:59:26Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314t-win_amd64.whl", hash = "sha256:d86c125d720c2c368c53bd1a4ef062916d91fa965c10448c74c78b5d039faf2d", upload-time = "2026-04-27T18:01:14Z" }, +] + +[[package]] +name = "torchvision" +version = "0.26.0+cu128" +source = { registry = "https://download.pytorch.org/whl/cu128" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, + { name = "torch" }, +] +wheels = [ + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c4a9cacd521f2a4df0bcd9d8e96704771b928f478f1f3067e4085bb53a1da298", upload-time = "2026-04-09T23:21:37Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:cb1f6184a7ba30fba40580e1a01a6604a86c55e79fdda187f40116ee680441ec", upload-time = "2026-03-23T15:36:22Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp313-cp313-win_amd64.whl", hash = "sha256:0232cb219927a52d6c98ff202f32d1cdf4802c2195a85fc1f1a0c1b0b4983a4d", upload-time = "2026-04-09T23:21:38Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e594732552a8c2fee2ace9c6475c6c6904fc44ccca622ee6765a89a045416a44", upload-time = "2026-04-09T23:21:38Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6168abc019803ac9e97efce27eafd2fdb33db04dcc54a86039537729e5047b29", upload-time = "2026-03-23T15:36:23Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp313-cp313t-win_amd64.whl", hash = "sha256:367d42ea703844ecdb516e9d5eb09929012a58705d2622cf4e9e3c37f278cb85", upload-time = "2026-04-09T23:21:39Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:b3865fa227661dd75b7b28c96d3d14e739bd08bf0614132758922fe0e7206f91", upload-time = "2026-04-09T23:21:39Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:aac647c9130f1f25f5c8f5bca3d95cfd96bdfac93ab54529690b088e64e4fa64", upload-time = "2026-03-23T15:36:23Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314-win_amd64.whl", hash = "sha256:6319e1ba49c6f62ac9902f73d0eab207b8a4dc6b4d3392fe9edd9903fff1be0a", upload-time = "2026-04-09T23:21:40Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:e2ee9e16ee4518292694537fcbd20d2d27044e381d92b864f637e82795796a84", upload-time = "2026-04-09T23:21:40Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:b5772c55bfda4377df8f1930d43c4e0231ef231b0228eade4b227c8d3ba6e34e", upload-time = "2026-03-23T15:36:23Z" }, + { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314t-win_amd64.whl", hash = "sha256:f160dc552a086244f7102c898f7be8ef46a41b36bce5ea80a4f2493cb30ca1fc", upload-time = "2026-04-09T23:21:41Z" }, +] + +[[package]] +name = "tqdm" +version = "4.70.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" }, +] + +[[package]] +name = "transformers" +version = "4.57.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "huggingface-hub" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "regex" }, + { name = "requests" }, + { name = "safetensors" }, + { name = "tokenizers" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912, upload-time = "2026-01-16T10:38:39.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" }, +] + +[[package]] +name = "triton" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/12/34d71b350e89a204c2c7777a9bba0dcf2f19a5bfdd70b57c4dbc5ffd7154/triton-3.6.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448e02fe6dc898e9e5aa89cf0ee5c371e99df5aa5e8ad976a80b93334f3494fd", size = 176133521, upload-time = "2026-01-20T16:16:13.321Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0b/37d991d8c130ce81a8728ae3c25b6e60935838e9be1b58791f5997b24a54/triton-3.6.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c7f76c6e72d2ef08df639e3d0d30729112f47a56b0c81672edc05ee5116ac9", size = 188289450, upload-time = "2026-01-20T16:00:49.136Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4e/41b0c8033b503fd3cfcd12392cdd256945026a91ff02452bef40ec34bee7/triton-3.6.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1722e172d34e32abc3eb7711d0025bb69d7959ebea84e3b7f7a341cd7ed694d6", size = 176276087, upload-time = "2026-01-20T16:16:18.989Z" }, + { url = "https://files.pythonhosted.org/packages/35/f8/9c66bfc55361ec6d0e4040a0337fb5924ceb23de4648b8a81ae9d33b2b38/triton-3.6.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d002e07d7180fd65e622134fbd980c9a3d4211fb85224b56a0a0efbd422ab72f", size = 188400296, upload-time = "2026-01-20T16:00:56.042Z" }, + { url = "https://files.pythonhosted.org/packages/49/55/5ecf0dcaa0f2fbbd4420f7ef227ee3cb172e91e5fede9d0ecaddc43363b4/triton-3.6.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef5523241e7d1abca00f1d240949eebdd7c673b005edbbce0aca95b8191f1d43", size = 176138577, upload-time = "2026-01-20T16:16:25.426Z" }, + { url = "https://files.pythonhosted.org/packages/df/3d/9e7eee57b37c80cec63322c0231bb6da3cfe535a91d7a4d64896fcb89357/triton-3.6.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a17a5d5985f0ac494ed8a8e54568f092f7057ef60e1b0fa09d3fd1512064e803", size = 188273063, upload-time = "2026-01-20T16:01:07.278Z" }, + { url = "https://files.pythonhosted.org/packages/48/db/56ee649cab5eaff4757541325aca81f52d02d4a7cd3506776cad2451e060/triton-3.6.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b3a97e8ed304dfa9bd23bb41ca04cdf6b2e617d5e782a8653d616037a5d537d", size = 176274804, upload-time = "2026-01-20T16:16:31.528Z" }, + { url = "https://files.pythonhosted.org/packages/f6/56/6113c23ff46c00aae423333eb58b3e60bdfe9179d542781955a5e1514cb3/triton-3.6.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46bd1c1af4b6704e554cad2eeb3b0a6513a980d470ccfa63189737340c7746a7", size = 188397994, upload-time = "2026-01-20T16:01:14.236Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47", size = 76928, upload-time = "2026-08-12T12:37:25.997Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147", size = 14750, upload-time = "2026-08-12T12:37:24.648Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.52.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/28/64ca011edf31c715b4fad359c587ea52391aaffa125065695590241ff617/uvicorn-0.52.3.tar.gz", hash = "sha256:18857b9e6579300be55c91c0a1cfd37d9a2cf0cabea33b88275f199eb73b8b58", size = 100621, upload-time = "2026-08-13T16:50:02.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/2b/ebd108734a8204c6b4b93c681c9a38c5273b3ccd5d129fee4ffc1d97772c/uvicorn-0.52.3-py3-none-any.whl", hash = "sha256:116af2710dbf47c80f463cd20ee4884b6662f4c9f227d797ddc7279d2fcc2c7c", size = 79859, upload-time = "2026-08-13T16:50:01.323Z" }, +] + [[package]] name = "wcwidth" version = "0.8.2" @@ -371,6 +2102,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" }, ] +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +] + [[package]] name = "wrapt" version = "2.3.0" @@ -423,3 +2163,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/b3/af176d79a8515a8a720eccdad9a96f6e31a30abf2865430c8c42adf2fd13/wrapt-2.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b1e5aa486e269b00ed35e64771c7d0ab8096cfd2643405ca8cd60ebedc099a51", size = 81774, upload-time = "2026-07-28T06:05:53.902Z" }, { url = "https://files.pythonhosted.org/packages/00/39/3daf9f47be208606586de4568ba6713db53ebc8fd7a575aea1fe57983b69/wrapt-2.3.0-py3-none-any.whl", hash = "sha256:d8c7ed08477429752b8c44991f40ad7838b18332a160698740a6bfbc10d998a2", size = 61866, upload-time = "2026-07-28T06:06:12.9Z" }, ] + +[[package]] +name = "xlsxwriter" +version = "3.2.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940, upload-time = "2025-09-16T00:16:21.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315, upload-time = "2025-09-16T00:16:20.108Z" }, +] From 6568ed2288144eaa34da3d7fc9476850f4cbeac8 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 20:12:33 +0000 Subject: [PATCH 089/113] fix: chown both cache volumes and split the devcontainer create steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `hf-models` volume is created root-owned by Docker, so MinerU died at model download with "[Errno 13] Permission denied: '/home/vscode/.cache/huggingface/hub'" (measured) — `onCreateCommand` chowned only the uv cache. It now chowns both and does nothing else; fetching the Lean cache, syncing the venv and installing the hooks move to `postCreateCommand`, which is where they belong now that the converter is a locked dependency rather than a `uv tool` install. `containerEnv` pins the model origin. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .devcontainer/devcontainer.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c0f3563..4482db0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,8 +17,20 @@ }, "ghcr.io/thamaji/devcontainer-features/gitleaks:latest": {} }, - // --with six: mineru 3.4.5's pipeline imports six without declaring it (measured). - "onCreateCommand": "rm -rf .lake/ && lake exe cache get && uv sync && uv run lefthook install && uv tool install --with six \"mineru[pipeline,vlm]\"", + // Both cache volumes are created root-owned by Docker, so chown them before + // anything writes: without this MinerU dies at model download with + // "[Errno 13] Permission denied: '/home/vscode/.cache/huggingface/hub'". + "onCreateCommand": "sudo chown -R vscode:vscode /home/vscode/.cache/uv /home/vscode/.cache/huggingface && rm -rf .lake/", + "postCreateCommand": "lake exe cache get && uv sync && uv run lefthook install", + // Pin where MinerU fetches models from. Its default (`auto`) probes + // HuggingFace and silently falls back to ModelScope, so the download origin + // depends on the network. The env var outranks ~/mineru.json, which MinerU + // rewrites itself after every successful download. + "containerEnv": { + "UV_LINK_MODE": "copy", + "UV_CACHE_DIR": "/home/vscode/.cache/uv", + "MINERU_MODEL_SOURCE": "huggingface" + }, // Pass the host GPU through (Docker Desktop bundles the NVIDIA runtime). // If the container fails to start on a machine without a GPU, drop this line. "runArgs": [ From 4d8a21be048d7738754e23c45f3fd495f1e8b366 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Fri, 14 Aug 2026 20:12:43 +0000 Subject: [PATCH 090/113] feat: hand extraction notes to math-review and to object design A note produced by `/math-extract` is now read twice after it is written: `/math-review` resolves the note for the file under review, has the reviewer cite its `(D#)` / `(X#)` / degeneracy lines by id, converts note tiers into review tiers, and maintains the `Implemented as` back-link; AGENTS.md *Think before coding* points at `docs/math/README.md` before a new object is designed. note-format.md states what the adopted general form must contain so those readers have something to check against. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/agents/math-reviewer.md | 59 +++++++++++++-- .claude/skills/math-extract/SKILL.md | 52 ++++++-------- .../math-extract/references/note-format.md | 71 ++++++++++++++++--- .claude/skills/math-review/SKILL.md | 53 +++++++++++++- AGENTS.md | 6 ++ docs/math/README.md | 11 ++- 6 files changed, 202 insertions(+), 50 deletions(-) diff --git a/.claude/agents/math-reviewer.md b/.claude/agents/math-reviewer.md index d0458c8..d058384 100644 --- a/.claude/agents/math-reviewer.md +++ b/.claude/agents/math-reviewer.md @@ -86,6 +86,30 @@ cover all five yourself. of the target modules, and — for deferred-hypothesis tracking — the files where a field is (or could be) discharged. Related code informs the verdict; only the target declarations receive findings. +- **Read the extraction note, when one exists.** `docs/math/<slug>.md` records + what the literature says about the object *before* any Lean was written — + the variants each source states, the conventions that make them meaningful, + which hypotheses are provable and which are genuinely model-dependent, and + what happens at the degenerate models. Find it through the index table in + `docs/math/README.md`, or through a note's `implemented-as:` frontmatter + field, which names the declaration it was formalized as. Each perspective has + a section that answers its own question directly: + + | Perspective | Section of the note | + |---|---| + | 1 Statement fidelity | `## Results and dependencies` — the `(R#)` statements, written out in the note's adopted conventions | + | 2 Deferred hypotheses | `## Hypotheses` — the `(A#)` table, with `Class` ∈ provable / model-dependent / open and the named `Witness` | + | 3 Abstraction & literature conformance | `## Definition` — the `(D#)` variants and the adopted general form, plus the typed discriminators in `## Rejected formulations` | + | 4 Notation, naming & documentation | `## Notation and conventions` — the `(C#)` axes and what each source fixes them to | + | 5 Counterexample models & vacuity | `## Degeneracies and boundary cases` — the cases already probed, and the effect recorded for each | + + The note is evidence about the literature, not about the Lean: it can tell + you the standard form and the known counterexample, never whether *this* + declaration states it. Confirm the Lean side from the elaborated type as + always. Two cautions: a note carries `## Not investigated` and `## Open + questions` sections, and what sits there is *not* covered; and a note row is + only as good as its own tier, which the note labels per row — see the + conversion rule under the evidence-tier ground rule below. - **Trust only the elaborated type.** Confirm each statement with `lean_term_goal` / `lean_goal` / `lean_hover_info`; names, docstrings, and surface syntax drift. @@ -123,6 +147,23 @@ cover all five yourself. spellings and a different tool (`lean_leansearch` for prose, `lean_loogle` for a type shape, `lean_leanfinder` for a concept); if it is still not found, say "I could not find" — which is a (c), not a (b). + + **An extraction note's tier converts, it does not transfer.** A note grades + its rows (a) quoted / (b) read / (c) attested / (d) recalled — evidence about + *the literature*. The tiers above grade evidence about *the code*. For a + claim about the literature that a note grounds: + + | Note row | Your tier | Why | + |---|---|---| + | (a) quoted / (b) read | **(b) verified** — cite the note path, the row id, and the source key | someone opened the source at the passage, and a quoted row survived the note's mechanical `grep -F` check | + | (c) attested / (d) recalled | **(c) recalled** — unchanged | the note is honest that nobody opened the source | + + So a note's (a)/(b) row *can* ground a `blocker` under perspective 3 or 5, + where recollection alone cannot. **Why:** rule 1 exists because "the standard + form is Y" asserted from memory is the main false-positive source in + perspective 3, and a quoted, locator-carrying row is exactly the thing that + stops being memory. It never reaches (a): only the elaborated type does that, + and a note says nothing about the elaborated type. - **Measure the trusted base, do not estimate it.** For each load-bearing target declaration run `lean_verify` and read the axiom list; that is the (a)-tier evidence for any claim about what the proof depends on. @@ -245,7 +286,12 @@ Would the notation or the docs slow a reader down, or mislead them? is conjugate-linear, whether ℏ = 1 is in force, and what a `∑` ranges over (`Finset.univ` versus a measure). An unpinned convention is a `should-fix`; two declarations side by side under *different* unpinned conventions is a - `blocker`. + `blocker`. This list is the same axis list + `.claude/skills/math-extract/references/note-format.md` pins under + `## Notation and conventions`, which is authoritative when the two drift; when + a note exists for the object, its `(C#)` table says what each source actually + fixes each axis to, so an unpinned axis there is a documented gap rather than + your own guess. - Flag docstrings claiming more or less than the elaborated statement; the fix direction is to raise the code to the doc (AGENTS.md *Match the code to the docs*), never to weaken the doc. @@ -264,9 +310,14 @@ does it wrongly say something in the worlds where it should fail? - **Instantiate at the degenerate cases.** Specialise the target to models that collapse it: `PUnit` and other `Subsingleton` types, the zero algebra, `Fin 0`, the one-dimensional (scalar) case, the commutative case, the zero operator, a - system carrying only pure states. Use `lean_run_code` (a self-contained snippet - with its own imports) or `lean_multi_attempt` at a proof position, and look for - two failures: + system carrying only pure states. This list mirrors the checklist in + `.claude/skills/math-extract/references/note-format.md` under + `## Degeneracies and boundary cases`, which is authoritative when the two + drift; when a note exists, its table already records what the *mathematics* + does at each case, so a Lean statement that survives a case the note says it + should not is a finding you can state at (b) rather than a hunch. Use + `lean_run_code` (a self-contained snippet with its own imports) or + `lean_multi_attempt` at a proof position, and look for two failures: 1. **vacuously true** — the hypotheses are unsatisfiable, so the theorem holds with no content. Contradictory typeclass assumptions and a `Fintype` that fails to exclude the empty type (making every sum trivially the claim) are diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md index 641e24f..a8713e5 100644 --- a/.claude/skills/math-extract/SKILL.md +++ b/.claude/skills/math-extract/SKILL.md @@ -11,12 +11,8 @@ definitions, the evidence tiers, the locator rule, the rejection discipline — lives in `.claude/agents/math-extractor.md`; the note's format lives in `references/note-format.md`. Never duplicate either here. -**This skill stops at the mathematics.** The note contains no Lean types, no -`def`/`structure`/`class` sketches, no candidate declaration names, no docstring -drafts, no ` ```lean ` fences. Reporting that Mathlib already contains something -is a fact and belongs in the note; proposing how this project should define -anything does not. A premature Lean sketch is noise at the moment the Lean is -actually written, and step 6 fails the run if one reaches the note. +**This skill stops at the mathematics.** `references/note-format.md` states what +that bars from the note; step 6 fails the run if any of it reaches the note. For reviewing Lean that already exists, use `math-review` instead. @@ -74,9 +70,8 @@ short form: that matters rather than the whole book. 5. Not obtainable — record it and move on. -Everything lands in `references/<slug-of-source>/`, which is gitignored. **The -cache is navigation; the note is the product.** Nothing in the cache is a -deliverable and it may be deleted at any time. +Everything lands in `references/<slug-of-source>/`, which is gitignored and may +be deleted at any time. Keep two lists as you go: the **corpus** (source key → cache path → how it was obtained) and the **unfetchable list** (source key → what was tried). Both go to @@ -100,11 +95,15 @@ Count three numbers from step 2: - **D** — definitional variants sighted. - **R** — results that will appear in the note. +Read the table top to bottom and take the **first** row whose condition holds. +Largest first, because one number out of range is enough to make a run large: +a corpus of three that disagrees irreconcilably is not a medium run. + | Size | Condition | Lanes | |---|---|---| -| **small** | D ≤ 1 and S ≤ 2 and R ≤ 3 | **Do not fan out** — see below | -| **medium** | D = 2, or S ≤ 3, or R ≤ 8 | three agents: **1+2**, **3+4**, **5** | | **large** | D ≥ 3, or S ≥ 4, or R ≥ 9, or the sources disagree irreconcilably | all five, one agent each, plus step 4 | +| **small** | D ≤ 1 and S ≤ 2 and R ≤ 3 | **Do not fan out** — see below | +| **medium** | neither of the above | three agents: **1+2**, **3+4**, **5** | At **small**, launch a single `math-extractor` with no lane assigned — its agent file then has it cover all five lanes itself, in 5–15 tool calls. Continue with @@ -206,7 +205,9 @@ Three things are **yours**, not any lane's: On a re-extraction, carry `## Rejected formulations and refuted claims` and `## Sources` forward verbatim and append to them; replace every other section. -Add a `revisions:` entry. +Add a `revisions:` entry. Carry `implemented-as` forward unchanged too — it is +`math-review`'s field, not yours, and a re-extraction that resets it to `none` +silently deletes the back-link to a formalization that still exists. Do not soften or drop what the lanes returned. Rows from different lanes that touch the same object stay separate; only `## Out of lane` items get @@ -246,10 +247,16 @@ so read every hit rather than counting them. 3. **Locator check.** ```bash - grep -nE 'tier \((c|d)\)' docs/math/<slug>.md | + grep -nE 'tier \([cd]\)|\| *[cd] *\|' docs/math/<slug>.md | grep -E 'Theorem|Thm|Lemma|Prop|Cor|§|p\. ?[0-9]|eq\. ?\(' ``` + Both spellings of the tier are needed: the prose rows write `tier (c)`, while + the `## Hypotheses`, `## Rejected` and `## Sources` rows carry a bare `c` or + `d` in a column. The second alternative costs some false positives on any + one-letter cell, which is the right trade here — a missed (c) row with a + theorem number is the failure this check exists to catch. + Every hit is a violation: the row must carry the substitution sentence instead of the number. Then read the `[ext: …]` markers and the `## Sources` rows for anything on the unfetchable list. @@ -257,7 +264,7 @@ so read every hit rather than counting them. 4. **Discipline check.** ```bash - awk -F'|' '/model-dependent/ { w=$5; gsub(/^[ \t]+|[ \t]+$/,"",w) + awk -F'|' '/model-dependent/ { w=$6; gsub(/^[ \t]+|[ \t]+$/,"",w) if (w=="" || w=="—" || w=="-") print NR": no witness: "$2 }' docs/math/<slug>.md awk -F'|' '/\| rejected \|/ { if ($5 !~ /\(X[1-5]\)/) print NR": untyped: "$2 }' docs/math/<slug>.md grep -niE 'harder to formalize|awkward in a proof assistant|not standard|more lemmas' docs/math/<slug>.md @@ -336,20 +343,3 @@ tool are paired into one agent at medium size for exactly that reason. Conversion is deliberately outside all of this: it is serial, minutes long, and breaks under concurrency, so it happens once in step 2 and the lanes only read what it produced. - -## Sources ledger - -`sources.md`, next to this file, is keyed by **source**, while the notes are -keyed by **object**. It holds the three things a note structurally cannot: - -1. **Retrieval attempts** — that a book could not be obtained is true for every - object that cites it, and rediscovering it each time costs the same ten - minutes each time. -2. **Locator adjudications** — when someone finally opens a source and finds - that a widely-copied theorem number does not say what it is said to say, that - correction belongs to the source, not to whichever object was being extracted - that day. It gets recorded once and read forever. -3. **Edition and version drift** — preprint and published numbering, second - editions, arXiv versions. - -Step 1 reads it; step 6 writes it. Nothing else touches it. diff --git a/.claude/skills/math-extract/references/note-format.md b/.claude/skills/math-extract/references/note-format.md index 28360da..02cf958 100644 --- a/.claude/skills/math-extract/references/note-format.md +++ b/.claude/skills/math-extract/references/note-format.md @@ -63,9 +63,19 @@ revisions: ### Adopted general form -<Written by the orchestrator at merge time, not by a lane. States the form this - note takes forward and cites the discriminators that justify it — e.g. "(D1), - because (X3) shows (D2) drops the non-σ-finite case that [DL84] §1 covers".> +<Written by the orchestrator at merge time, not by a lane. Two parts, in this + order. + + First the statement itself, written out in this note's conventions: the + ambient objects and their standing assumptions, the quantifiers in order, and + the (A#) rows it carries. Complete enough to be compared against an elaborated + Lean type without opening a source. + + Then the justification, one sentence citing the (D#) followed and the (X#) + that discriminates — e.g. "This is (D1); (X3) shows (D2) drops the non-σ-finite + case that [DL84] §1 covers." If no discriminator justifies the choice, write + "provisional — no discriminator separates (D1) from (D2)" and stop; do not + manufacture a reason.> ## Notation and conventions @@ -144,7 +154,7 @@ revisions: ## Not investigated -<Never omitted.> +<Never omitted, and never empty.> ```` ## Section rules @@ -156,9 +166,16 @@ revisions: thing a reader sees, and it is an honesty indicator: a note whose conclusions ride on recollection says so at the top. - `implemented-as` is a **fact-only back-link**, `none` until the object is - implemented and a declaration name afterwards. Writing the name is this - skill's job; checking that the declaration still matches the note is - `math-review`'s job. + implemented and a fully-qualified declaration name afterwards. This skill + writes `none`, because it runs *before* the Lean exists and has nothing to + point at. `math-review` fills the name in — and resets it to `none` when the + declaration is gone — as part of checking that the declaration still matches + the note; those two fields (here and in the `docs/math/README.md` index row) + are the only thing it may write in this file. A re-extraction carries the + field forward unchanged rather than resetting it. + **Why:** a back-link nobody is obliged to maintain decays into a claim that + the object was formalized as something it no longer is, which is worse than + the honest `none` it started as. - `mathlib-rev` is the Mathlib revision from `lake-manifest.json` at extraction time. It is what expires the `## Prior art` rows. - `revisions` carries the history. **The body never does** — a note is the @@ -185,6 +202,18 @@ mean, and why the generality is the one under discussion. Not a survey. justification comes from lane 4's discriminators and lane 1 cannot see them while running in parallel. It may never be justified by formalization convenience. +- **The adopted form is written out, not merely named.** State the definition + as a complete sentence in this note's own conventions — the ambient objects + and their standing assumptions, the quantifiers in order, and the `(A#)` rows + it carries — and only then cite the `(D#)` it follows and the `(X#)` that + justifies it. "(D1), because (X3) shows (D2) drops the non-σ-finite case" is + the *justification*; it is not the definition, and a reader who stops there + has to reconstruct the mathematics from a verbatim quote in some source's own + notation. + **Why:** this paragraph is what the eventual formalization is written + against, and it is what `math-review` compares an elaborated type to. Both + need a statement whose quantifier order and hypotheses are unambiguous in + *one* place; a pointer to a quote in another notation is not that. - No proposed notation, no identifiers. ### Notation and conventions @@ -263,7 +292,11 @@ quantifier swap and per dropped hypothesis. This is coverage, not a quota. - A search miss is recorded as "could not find X, having searched …" — never "Mathlib has no X". - Every row carries the Mathlib revision it was measured against. The row is - void once `lake-manifest.json`'s Mathlib revision moves. + void once `lake-manifest.json`'s Mathlib revision moves. Nothing enforces this + automatically: expiry is decided by a reader comparing the row's revision to + the manifest, which is why the revision is written into the row rather than + left implicit in the note's date. A void row is not wrong — it is unmeasured, + and a claim resting on it drops to (c). ### Sources @@ -274,7 +307,9 @@ facts. The cross-object retrieval ledger and the locator adjudications live in ### Not investigated -**Never omitted, even when empty.** State: +**Never omitted, and never empty.** The last item below always has content, so +an empty section means it was not written rather than that nothing was left +unexamined. State: - the `[ext: …]` edges from `## Results` that lane 5 never reached; - the sources listed as not retrieved, and which rows depend on them; @@ -313,10 +348,24 @@ can actually falsify. ### The quote check -> Every blockquote in the note must survive `grep -F` against the corpus cache -> under `references/`. What fails is downgraded to (b) or deleted. +> Every blockquote in the note must survive `grep -F` against +> `source.flat.txt` of **the source that row cites** — not against the cache at +> large. What fails is downgraded to (b) or deleted. + +Matching some other file in the cache proves the sentence exists somewhere, +which is not the claim the row makes. `source.flat.txt` rather than `source.txt` +because a quotation crossing a line break matches only there; see +`ingestion.md`. **Why:** it makes tier (a) mechanically decidable instead of self-reported, at a cost of seconds. Converted PDFs are model output, not text, so a quote taken from converted Markdown is (b) with `mineru-unchecked` until compared against the page image; an arXiv LaTeX source is the original and needs no such check. + +**Known limitation.** The check is decidable only while the cache exists, and +the cache under `references/<slug>/` is untracked and disposable. Once it is +deleted, a tier (a) row is re-checkable only by re-ingesting the source — the +`## Sources` table records the path and enough bibliographic detail to do that, +which is why that table is append-only. A downstream reader who cannot re-ingest +treats an (a) row as an (a) row: the check was run when the row was written, and +the row's locator is what makes the claim falsifiable against a physical copy. diff --git a/.claude/skills/math-review/SKILL.md b/.claude/skills/math-review/SKILL.md index 83e4114..0f64d82 100644 --- a/.claude/skills/math-review/SKILL.md +++ b/.claude/skills/math-review/SKILL.md @@ -42,6 +42,21 @@ explicit file or directory target has no diff; its scope is the entire file. Announce the resolved target before dispatching, so a wrong default costs one word to correct. +**Then resolve the extraction notes.** `docs/math/<slug>.md` records what the +literature says about an object, written before its Lean by `/math-extract`; +`references/note-format.md` in that skill states that checking the declaration +still matches the note is *this* skill's job. Read `docs/math/README.md` and +match its index rows to the target: a row's `Implemented as` column names the +declaration, and each note's `implemented-as:` frontmatter field carries the +same back-link. When neither names a target declaration, match by object — +a note on the split inclusion covers `SplitInclusion.lean` whether or not the +back-link was ever written. Collect the absolute paths of the notes that match. + +No note is a normal state, not a violation: most objects here predate the +skill. Missing notes are recorded in `## Not reviewed` (step 4) and nothing +else follows from them — never file a finding for the absence of a note, and +never write one yourself. `/math-extract` owns that file. + ### 2. Spawn one sub-agent per perspective **Scale to the target first.** When the scope is small — roughly three target @@ -75,6 +90,13 @@ permission to prove that guess wrong. Each prompt must state: perspective's definition, the agent file owns it; - the target files, with the changed line ranges collected in step 1 — or *entire file* for an explicit target that has no diff; +- **the absolute paths of the extraction notes resolved in step 1**, or the + explicit statement that none matched. Do not summarise a note into the + prompt: the agent file tells each perspective which section answers its own + question, and a summary would decide that for it. Say only which object each + note covers. When no note matched, say so — silence reads as "nobody + looked", and a reviewer that assumes a note exists will hunt for it and + spend the sweep on filesystem searches; - a reminder to investigate related code beyond the diff, and to sweep the whole target rather than stopping at the first finding; - **the absolute path of the notes file** it must append confirmed findings to @@ -144,8 +166,31 @@ next run repeat this one's dead ends. ### 4. Aggregate -Wait for every perspective (and the refutation pass, if any) to complete, then -emit one markdown report to the chat, grouped by severity. Do not soften, +Wait for every perspective (and the refutation pass, if any) to complete. + +**First, reconcile each extraction note's back-link.** For every note resolved +in step 1, check the two facts that go stale on their own: whether +`implemented-as:` names a declaration that still exists (`lean_local_search`, +or `lean_declaration_file`), and whether the `docs/math/README.md` index row +agrees with it. Then: + +- **Back-link absent or stale, and a target declaration implements the note's + object** — write the fully-qualified declaration name into the note's + `implemented-as:` field and into the README index row. These two fields are + the *only* thing this skill may write in `docs/math/`; everything else there + belongs to `/math-extract`, and a review that edits a `## Hypotheses` row has + overwritten an extraction it did not perform. +- **Back-link names a declaration that no longer exists** — set it back to + `none` and say so in the report. A back-link pointing at a deleted + declaration is worse than none: it claims a formalization that is gone. +- **The declaration exists but does not state the note's adopted general + form** — do **not** touch the back-link. That is a perspective 3 finding, and + it is the finding this whole reconciliation exists to surface; silently + rewriting the link would record agreement where there is a divergence. + +Skip this entirely when step 1 found no notes. + +Then emit one markdown report to the chat, grouped by severity. Do not soften, merge, or drop findings; findings from different perspectives on the same line stay separate entries. The one exception: the reviewers' `## Out of perspective` sections (defects fitting no perspective — layout violations, @@ -172,6 +217,7 @@ Template: **Scope**: <N> files / <M> declarations <!-- from the agents' reviewed-declaration lists --> **Verdict**: <worst severity present, or ✅ no findings> +**Extraction notes**: <the notes consulted, with any back-link written or reset — or `none matched`> ## 🛑 Blocker ### 1. <one-line title> @@ -206,6 +252,9 @@ Template: ## Not reviewed <deleted files; files no agent could reach; perspectives that returned partial; + target declarations with no extraction note, and — for the notes that were + consulted — what their own `## Not investigated` and `## Open questions` + sections leave uncovered, since a reviewer leaning on a note inherits its gaps; and — always — the **unexamined dependencies the verdict rests on**: the declarations the reviewers relied upon without opening, taken from each reviewer's per-finding confidence split. The risk lives here, not in what was diff --git a/AGENTS.md b/AGENTS.md index ec1c7b3..f07bd8a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,6 +13,12 @@ **Think before coding.** - Read the target file and its importers before editing. +- Before designing a new object, check `docs/math/README.md` for an extraction + note on it and read the note if one exists — its adopted general form is the + statement the Lean is meant to realise, and its `## Hypotheses` table already + separates the provable from the genuinely model-dependent. A note is + mathematics, not a design: it never says how to define anything in Lean, and + no note is a normal state, not a blocker. - State your assumptions about the goal, the existing lemmas, and the proof skeleton before typing tactics. Capture the goal with `lean_goal` rather than guessing the shape from the file context. diff --git a/docs/math/README.md b/docs/math/README.md index 37e22b5..e24e6f9 100644 --- a/docs/math/README.md +++ b/docs/math/README.md @@ -11,6 +11,11 @@ skill. They contain mathematics only: no Lean types, no declaration names, no docstring drafts. How the object is eventually formalized is decided when it is formalized, and a note that guessed in advance would only add noise. +They are read twice afterwards: when the object is designed (AGENTS.md *Think +before coding*), and by `/math-review`, which compares the elaborated Lean back +against the note's adopted general form, hypothesis classification and +degeneracy table — and which maintains the `Implemented as` column below. + The format is specified in `.claude/skills/math-extract/references/note-format.md`. The retrieval history and locator adjudications for the sources these notes cite live in @@ -24,5 +29,7 @@ the product. |---|---|---| <!-- One row per note. "Implemented as" is a fact recorded after the object is - formalized — the module or declaration that ended up carrying it, or - "none" while it is still only a note. It is a back-link, not a plan. --> + formalized — the fully-qualified declaration that ended up carrying it, or + "none" while it is still only a note. It is a back-link, not a plan. + /math-review writes it, and resets it to "none" when the declaration is + gone; it must agree with the note's own `implemented-as:` frontmatter. --> From 4ec09ecc722fee3786e7fc65527e83eac7a86632 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 07:26:53 +0000 Subject: [PATCH 091/113] feat: render source macros in a note preamble instead of editing quotes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A verbatim quote carries its source's own LaTeX macros, which every KaTeX or MathJax renderer rejects. Transcribing the definitions into a per-note $$ block keeps the quoted bytes intact — they are what the quote check verifies, and a shared macro table would silently render one source's quote in another's notation. Also records the mineru hybrid-engine backend flags and their VRAM failure mode in the ingestion ladder; neither backend raises the evidence tier. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-extract/SKILL.md | 10 +++- .../math-extract/references/note-format.md | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md index a8713e5..dda4efb 100644 --- a/.claude/skills/math-extract/SKILL.md +++ b/.claude/skills/math-extract/SKILL.md @@ -67,7 +67,11 @@ short form: 3. Any other URL. 4. A PDF through the converter — **slow, serial, and not verbatim**. Opt-in per call with `--allow-mineru`, and `--pages START-END` to convert the chapter - that matters rather than the whole book. + that matters rather than the whole book. The default backend is the CPU/GPU + pipeline; `--backend hybrid-engine --effort high` opts into the + higher-accuracy VLM path, which can exhaust this machine's VRAM — on + `CUDA out of memory`, drop both flags and rerun. Neither choice raises the + tier: converted text is (b) either way. 5. Not obtainable — record it and move on. Everything lands in `references/<slug-of-source>/`, which is gitignored and may @@ -189,6 +193,10 @@ general form has been attacked on all three fronts. Write `docs/math/<slug>.md` to the format in `references/note-format.md`. +If any quote you merge carries a macro its source defines — `\lok`, `\A`, `\bC` — +the note opens with the macro preamble that format specifies. Never edit a quote +to make it render. + Three things are **yours**, not any lane's: 1. **The adopted general form.** Lane 1 supplies the variants and lane 4 the diff --git a/.claude/skills/math-extract/references/note-format.md b/.claude/skills/math-extract/references/note-format.md index 02cf958..b895bc8 100644 --- a/.claude/skills/math-extract/references/note-format.md +++ b/.claude/skills/math-extract/references/note-format.md @@ -36,6 +36,16 @@ revisions: - 2026-08-14 · <short commit> · initial extraction · sources: DL84, BU74 --- +<!-- +Macros the quotes below need, copied from each source's own preamble: + \lok DL84, references/<slug-of-source>/raw/<file>.tex:144 +Omit this block and the comment when no quote carries a source macro. +--> + +$$ +\newcommand{\lok}[1]{{\mathcal #1}} +$$ + # <Object, as a mathematician names it> ## What this object is for @@ -159,6 +169,41 @@ revisions: ## Section rules +### Macro preamble + +Verbatim quotes carry the source's own LaTeX, and sources define their own +macros — `\lok`, `\A`, `\bC`. Any renderer that parses `$…$` (KaTeX in VS Code's +Markdown preview, MathJax elsewhere) raises a parse error on every one of them, +and **the fix is never to edit the quote**: those bytes are the evidence the +quote check verifies. Transcribe the definitions instead, into a `$$` block +between the frontmatter and the H1 — it must precede the first quote that uses +them — with an HTML comment naming the file and line each was copied from. + +- **Copy the definition; do not paraphrase it.** `\newcommand{\lok}[1]{{\mathcal + #1}}` lifted from the paper's preamble can be audited against that preamble. + An equivalent written from scratch cannot, and a wrong transcription + mis-renders a quote that the quote check will still pass — it checks the + source bytes, not what they display as. +- **Only the macros the note actually uses.** +- **`\renewcommand` where the renderer already defines the name.** `\H` is the + Hungarian-umlaut accent in KaTeX's own macro table, so `\newcommand{\H}` is an + error; sources redefining it hit the same wall and write `\renewcommand`, so + copying them is both correct and faithful. +- **The definitions are per-note, and that is the point.** Renderers reset the + macro table per document, so two notes may transcribe one name differently — + which is what the sources do. Defining the macros once in an editor or + workspace setting instead would put every note into a single namespace, and + the first collision would render one source's quote in another source's + notation **without raising an error**. A silently mis-rendered verbatim quote + is worse than a visible parse error, which is why this block belongs in the + note and not in a configuration file. +- A renderer that does not share macro state across a document simply ignores + the block, and the quotes show as source LaTeX — which is what they are. + Nothing downstream depends on it, and no editor configuration is required. + +The block is presentation, not mathematics: it carries no claim, so it needs no +tier and no locator beyond the file:line provenance in the comment. + ### Frontmatter - `worst-tier` is the **minimum tier over load-bearing rows** — the rows the @@ -357,6 +402,10 @@ which is not the claim the row makes. `source.flat.txt` rather than `source.txt` because a quotation crossing a line break matches only there; see `ingestion.md`. +A quote that will not *render* is still a quote. Fix it with the macro preamble +above, never by touching the bytes: normalising a formula so a previewer stops +complaining destroys the only thing that makes the row checkable. + **Why:** it makes tier (a) mechanically decidable instead of self-reported, at a cost of seconds. Converted PDFs are model output, not text, so a quote taken from converted Markdown is (b) with `mineru-unchecked` until compared against From c52db8962546117587099b9d5e81a1d814876307 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 18:16:37 +0000 Subject: [PATCH 092/113] docs: update GPU verification notes for uv sync and cu128 pin Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --- .devcontainer/gpu-verification.md | 168 ++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 29 deletions(-) diff --git a/.devcontainer/gpu-verification.md b/.devcontainer/gpu-verification.md index c339791..5a125e8 100644 --- a/.devcontainer/gpu-verification.md +++ b/.devcontainer/gpu-verification.md @@ -13,11 +13,14 @@ Windows 側に NVIDIA ドライバが入っていればよく、**WSL やコン VS Code のコマンドパレット → **Dev Containers: Rebuild Container**。 -`onCreateCommand` が `lake exe cache get` と -`uv tool install --with six "mineru[pipeline,vlm]"` を再実行する -(`--with six` は mineru 3.4.5 の未宣言依存の回避で、外すと変換が -`No module named 'six'` で全滅する。実測済み)。mineru の wheel(torch 含む ~4GB)は `uv-cache` volume に、モデルは -`hf-models` volume にキャッシュされているので、2 回目以降の再ビルドは大幅に速い。 +`onCreateCommand` が 2 つのキャッシュ volume(`uv-cache` と `hf-models`)を +`vscode` 所有に直し、続く `postCreateCommand` が `lake exe cache get` と `uv sync` +を再実行する(`uv sync` は `pyproject.toml` の `default-groups` に従い dev と mineru の +両方を入れる。`six` も `mineru` グループに入っている ── mineru 3.4.5 の未宣言依存で、 +無いと変換が `No module named 'six'` で全滅する。実測済み。torch は同じ +`pyproject.toml` で cu128 wheel に固定してある ── 理由は §3)。mineru の wheel +(torch 含む ~4GB)は `uv-cache` volume に、モデルは `hf-models` volume に +キャッシュされているので、2 回目以降の再ビルドは大幅に速い。 ## 2. GPU がコンテナに見えているか @@ -26,39 +29,64 @@ nvidia-smi ``` **期待**: GPU 名と `8192MiB` 前後のメモリ表を表示。 -`command not found` や `Failed to initialize NVML` の場合は §6 へ。 +`command not found` や `Failed to initialize NVML` の場合は §7 へ。 ## 3. torch が CUDA を認識しているか -torch は mineru の tool 環境に入っている(プロジェクト venv ではない)ので: +torch は `mineru` グループの一部としてプロジェクト venv に入っている: ```bash -~/.local/share/uv/tools/mineru/bin/python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else '-')" +.venv/bin/python -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else '-')" ``` -**期待**: `True <GPU 名>`。 -`False` の場合: `nvidia-smi` が通っているなら torch のビルド違いを疑う -(`...bin/python -c "import torch; print(torch.version.cuda)"` が `None` なら -CPU 版 wheel が入っている。`uv tool install --reinstall "mineru[pipeline,vlm]"` で -入れ直す。Linux の既定 wheel は CUDA 同梱なので通常はここに落ちない)。 +**期待**: `2.11.0+cu128 12.8 True <GPU 名>`。 + +`False` の場合、`nvidia-smi` が通っているなら torch のビルドを 2 段で疑う +(`.venv/bin/python -c "import torch; print(torch.version.cuda)"`): + +1. `None` なら CPU 版 wheel。`uv sync --group mineru --reinstall` で入れ直す。 +2. 値があるのに `False` なら、**wheel の CUDA 世代がホストドライバより新しい**。 + 警告に `The NVIDIA driver on your system is too old (found version 12080)` の + ような行が出る(12080 = CUDA 12.8 = ホストの現在値)。`nvidia-smi` 右上の + `CUDA Version` が wheel の `torch.version.cuda` より小さければこれ。実測: PyPI + 既定の `2.13.0+cu130` は driver 580 系以降を要求し、このホスト(573.22 / + CUDA 12.8)では初期化に失敗して CPU に落ちていた。 + +2 を避けるため、`pyproject.toml` は torch/torchvision を **cu128 index に固定**して +いる(`[[tool.uv.index]] pytorch-cu128` と `[tool.uv.sources]`、torch は `<2.12` +── cu128 wheel は torch 2.11 で打ち止め)。ホストのドライバを 580 系以降に更新した +なら、この固定を外して既定 wheel に戻してよい。 ## 4. 実 PDF の変換が GPU で速くなっているか -CPU での実測基準(このコンテナ、20 コア、5 ページの PDF): **モデルロード後の -変換だけで数分**。GPU なら同じ PDF が **数十秒以内**に落ちるはず。 +**arXiv の pdf URL を渡しても MinerU は通らない**: ingest.py は URL から arXiv id を +復元して rung 1(LaTeX)に落とす(仕様。そちらが厳密に良い)。GPU を測るには PDF を +ローカルに落として**パスで**渡す: ```bash -time uv run .claude/skills/math-extract/scripts/ingest.py <PDFのパスかURL> \ - --allow-mineru --cache-dir /tmp/gpu-check +curl -L -o /tmp/paper.pdf https://arxiv.org/pdf/1702.04924 +time uv run .claude/skills/math-extract/scripts/ingest.py /tmp/paper.pdf \ + --allow-mineru --pages 1-5 --cache-dir /tmp/gpu-check ``` **期待**: - JSON に `"stage": "mineru-pipeline"`、`"ok": true`。 -- mineru のログ(stderr)にデバイスとして `cuda` が現れる。 -- 所要時間が CPU 時より明確に短い。 - -初回はモデルのダウンロード(~1.5GB)が走る。`hf-models` volume に入るので 2 回目 -以降は走らない。事前に落としておきたい場合は `mineru-models-download`。 +- 所要時間が CPU 時より短い。実測(RTX 4060 Laptop、arXiv:1702.04924 の 5 ページ、 + `--pages 1-5`、モデルはキャッシュ済み): **GPU 22 秒 / CPU 60 秒** + (`MINERU_DEVICE_MODE=cpu` で同じ PDF を再実行。CPU 側は 20 コアを使い切って + user 7 分 9 秒)。モデル取得を含む初回は 1 分 17 秒。 + **倍率は 3 倍弱で、「CPU は数分」ではない** ── 従来の CPU 基準は別の文献で + 測ったものらしく、この文献では再現しなかった。GPU 判定は倍率ではなく、 + 次のメモリ確認で行うのが確実。 +- デバイスの直接確認は `nvidia-smi` を並走させる。ingest.py は mineru の stderr を + 捕まえて成功時には出さないので、ログで `cuda` を探すことはできない。変換中に + `nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv,noheader` を + 数秒おきに叩き、メモリが上がることを見る(実測: 待機 1.5GB → 変換中 3.8GB)。 + WSL2 では `--query-compute-apps` はプロセスを出さないので、空でも異常ではない。 + +初回はモデルのダウンロード(pipeline で ~0.6GB、hybrid-engine はさらに VLM 分)が +走る。`hf-models` volume に入るので 2 回目以降は走らない。事前に落としておきたい +場合は `mineru-models-download`。 ## 5.(任意)hybrid-engine を試す @@ -72,22 +100,104 @@ uv run .claude/skills/math-extract/scripts/ingest.py <PDF> \ - **成功したら**: 数式が濃い文献ではこちらを使う価値がある。VRAM に余裕を作るには 実行前に Windows 側の GPU 消費(ブラウザのハードウェアアクセラレーション等)を - 減らす。 + 減らす。実測(同じ 5 ページ、Windows が 1.5GB を使っている状態): **OOM せず + 2 分 42 秒**で完了 ── pipeline の 22 秒に対し約 7 倍で、常用ではなく数式が濃い + 文献に限って選ぶ、という前提は変わらない。 - **`CUDA out of memory` で落ちたら**: `--backend` を外して pipeline に戻す(既定)。 ingest.py の既定が pipeline なのはこのためで、設定変更は不要。 -## 6. 失敗時の切り分け +## 6. math-extract → math-review の実地確認(パイロット) + +§2–4 は GPU が動くかの確認。ここは **GPU を使う唯一の実利用者である +`math-extract` が、成果物の下流(Lean 形式化と `/math-review`)まで実際に +噛み合うか**の確認で、再ビルド後に一度だけ通せばよい。 + +背景: `docs/math/` のノートは現在 **0 件**で、フォーマットは一度も実運用されて +いない。ノートを読む側(`math-review`、AGENTS.md *Think before coding*)の配線は +入れたが、本番ノートに対しては未検証。題材に split inclusion を選ぶのは、 +`note-format.md` の雛形がこの対象で書かれており、対応する Lean +(`QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean`, +`QuantumSystem/Algebra/LocalNet/SplitProperty.lean`)が既にあるため。 +主要文献 Doplicher–Longo (Invent. Math. 75, 1984) と Buchholz (CMP 36, 1974) は +arXiv にないので **PDF → MinerU 経路(§4 の rung 4)を通る**。GPU がここで効く。 + +### 6-1. 抽出 + +```bash +/math-extract split inclusion of von Neumann algebras +``` + +PDF が 4 本以上ならスキルは見積りを出して止まる(想定どおり)。少数なら続行。 + +**成果物として確認すること**(`docs/math/split-inclusion.md`): + +| 見るもの | 合格条件 | +|---|---| +| step 6 の 4 検査 | Firewall / Quote / Locator / Discipline が全通過、スキルの報告に件数が出る | +| `### Adopted general form` | **判別子の引用だけで終わっていないこと。** 環境対象・標準仮定・量化子の順序・依拠する `(A#)` を含む完結した言明が書かれているか。ここが「(D1), because (X3)…」だけなら仕様(`note-format.md`)どおりに書かれていない | +| `## Hypotheses` | `model-dependent` の各行に **名前のある witness**。無ければ `open` に落ちているか | +| `## Degeneracies` | チェックリスト全項目に行がある(効果なしの行も含む)。特に `SplitProperty.lean` の module doc が既に述べている「退化表現では自明に成り立つ」「格子領域では空領域が全てに直交する」に対応する行があるか | +| `## Not investigated` | 非空 | +| frontmatter | `implemented-as: none`(この時点では Lean を指さない)、`worst-tier` が load-bearing 行の**最小**値 | + +**既存 module doc との突き合わせ**が本命の検証。`SplitInclusion.lean` / +`SplitProperty.lean` の module doc は既に文献・採用理由・model-dependent 性・ +退化ケースを抱えている(ただし locator なし)。ノートがそれを **再現できるか、 +locator を付けられるか、食い違うか** を見る。食い違ったらどちらが正しいかを +判断すること — ノートが勝つとは限らない。 + +### 6-2. レビュー + +```bash +/math-review QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean +``` + +**配線が効いていることの確認点**: + +1. レポート冒頭に `**Extraction notes**:` 行が出て、`docs/math/split-inclusion.md` + を指している(`none matched` ならノートの解決に失敗している)。 +2. perspective 3(Abstraction & literature conformance)と 5(vacuity)の + findings または cleared 報告が、ノートの `(D#)` / `(X#)` / `## Degeneracies` + の行を**行 id で引用**している。引用がなければ、ノートを渡しただけで読まれて + いない。 +3. ノートの tier (a)/(b) 行に依拠した主張が **(b) verified** として出ている + ((c) 止まりなら tier 変換規則が効いていない)。 +4. `docs/math/split-inclusion.md` の `implemented-as:` に宣言名が書き込まれ、 + `docs/math/README.md` の Index に行が入っている。宣言がノートの採用形と + ずれている場合は **back-link は書かれず、perspective 3 の finding が出る** + のが正しい挙動。 +5. `## Not reviewed` に、ノートの `## Not investigated` が残した穴が引き継がれて + いる。 + +### 6-3. 判定 + +- 6-1 の表と 6-2 の 5 点が全部通れば、成果物フォーマットは下流で使える状態。 +- 6-2 の 1 が通らない → `math-review/SKILL.md` step 1 のノート解決。 +- 6-2 の 2–3 が通らない → `.claude/agents/math-reviewer.md` のノート参照節と + tier 変換表。 +- 6-2 の 4 が通らない → `math-review/SKILL.md` step 4 の reconcile 段。 +- 6-1 の `Adopted general form` が言明になっていない → + `.claude/skills/math-extract/references/note-format.md` の同節。 + +パイロットで書かれるのは `docs/math/split-inclusion.md` と +`docs/math/README.md` の 1 行だけで、Lean には触れないので `lake build` は不要。 + +## 7. 失敗時の切り分け | 症状 | 原因と対処 | |---|---| | 再ビルドでコンテナ自体が起動しない(`could not select device driver "" with capabilities: [[gpu]]`) | Docker Desktop → Settings → General で WSL 2 based engine を確認。Windows 側 NVIDIA ドライバが古い場合は更新。**応急処置**: `devcontainer.json` の `runArgs` 2 行を削って再ビルドすれば従来どおり CPU で動く | | コンテナは起動するが `nvidia-smi` が無い / NVML エラー | Docker Desktop を再起動 → WSL を `wsl --shutdown` してから Docker Desktop を起動し直す。それでも駄目なら Windows 側ドライバを更新 | -| `torch.cuda.is_available()` が `False`(`nvidia-smi` は通る) | §3 の CPU wheel チェック。torch が CUDA 版なら Docker Desktop の GPU support 設定と再起動 | -| mineru がモデルダウンロードで止まる | ネットワーク。`MINERU_MODEL_SOURCE=modelscope` を試す(既定 auto は HuggingFace 優先) | -| 変換が CPU 時と同じくらい遅い | mineru のログに `cpu` と出ていないか確認。§3 が `True` でこれが起きるなら issue 級なので報告を | +| `torch.cuda.is_available()` が `False`(`nvidia-smi` は通る) | §3 の 2 段チェック。(1) `torch.version.cuda` が `None` なら CPU wheel、(2) 値があり `driver ... is too old (found version 12080)` の警告が出るなら wheel の CUDA 世代がホストドライバより新しい ── cu128 固定(現状の解)かホストドライバを 580 系へ。どちらでもないなら Docker Desktop の GPU support 設定と再起動 | +| mineru が `[Errno 13] Permission denied: '/home/vscode/.cache/huggingface/hub'` で落ちる | `hf-models` volume が root 所有のまま。`onCreateCommand` が 2 つのキャッシュを chown する(§1)が、volume を新規作成した直後に手で直すなら `sudo chown -R vscode:vscode /home/vscode/.cache/huggingface` | +| mineru がモデルダウンロードで止まる | ネットワーク。取得元は `devcontainer.json` の `containerEnv` で `huggingface` に固定してある。HuggingFace に届かない環境なら、固定を外さずそのコマンドだけ `MINERU_MODEL_SOURCE=modelscope mineru …` で上書きする | +| 変換が CPU 時と同じくらい遅い | 成功時の mineru ログは出ないので、§4 のメモリ確認で GPU を使っているかを見る。比較したいときは `MINERU_DEVICE_MODE=cpu` を付けた同じコマンドと並べる。§3 が `True` で、変換中に GPU メモリが上がらないなら issue 級なので報告を | + +## 8. 確認が全部通ったら -## 7. 確認が全部通ったら +§1–5 と §7 は以後も再ビルドのたびに使えるので消さなくてよい。§6 のパイロットは +一度通れば役目を終えるが、`math-extract` と `math-review` のノート受け渡しを +書き換えたときの回帰確認としてそのまま使える。 -このファイルの手順は以後も再ビルドのたびに使えるので消さなくてよい。 `math-extract` スキル側の GPU 関連の記述は `.claude/skills/math-extract/references/ingestion.md` の Rung 4 にある。 From eb7caa6227f4f0bafc95c264b07152ae61e15b2e Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 18:18:01 +0000 Subject: [PATCH 093/113] docs: remove GPU verification notes Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --- .devcontainer/gpu-verification.md | 203 ------------------------------ 1 file changed, 203 deletions(-) delete mode 100644 .devcontainer/gpu-verification.md diff --git a/.devcontainer/gpu-verification.md b/.devcontainer/gpu-verification.md deleted file mode 100644 index 5a125e8..0000000 --- a/.devcontainer/gpu-verification.md +++ /dev/null @@ -1,203 +0,0 @@ -# GPU 有効化後の確認手順 - -devcontainer に GPU を渡す設定(`devcontainer.json` の `"runArgs": ["--gpus", "all"]`) -は**コンテナの再ビルドで初めて効く**。再ビルドすると実行中のセッションは消えるため、 -この確認手順をワークスペース内に残している。**このファイルだけ読めば、GPU が正しく -使えているかを判定できる**ように書いてある。 - -前提: ホストは Windows + Docker Desktop(NVIDIA ランタイム同梱)、GPU は VRAM 8GB。 -Windows 側に NVIDIA ドライバが入っていればよく、**WSL やコンテナの中に Linux 用 -ドライバを入れてはいけない**(壊れる)。 - -## 1. 再ビルド - -VS Code のコマンドパレット → **Dev Containers: Rebuild Container**。 - -`onCreateCommand` が 2 つのキャッシュ volume(`uv-cache` と `hf-models`)を -`vscode` 所有に直し、続く `postCreateCommand` が `lake exe cache get` と `uv sync` -を再実行する(`uv sync` は `pyproject.toml` の `default-groups` に従い dev と mineru の -両方を入れる。`six` も `mineru` グループに入っている ── mineru 3.4.5 の未宣言依存で、 -無いと変換が `No module named 'six'` で全滅する。実測済み。torch は同じ -`pyproject.toml` で cu128 wheel に固定してある ── 理由は §3)。mineru の wheel -(torch 含む ~4GB)は `uv-cache` volume に、モデルは `hf-models` volume に -キャッシュされているので、2 回目以降の再ビルドは大幅に速い。 - -## 2. GPU がコンテナに見えているか - -```bash -nvidia-smi -``` - -**期待**: GPU 名と `8192MiB` 前後のメモリ表を表示。 -`command not found` や `Failed to initialize NVML` の場合は §7 へ。 - -## 3. torch が CUDA を認識しているか - -torch は `mineru` グループの一部としてプロジェクト venv に入っている: - -```bash -.venv/bin/python -c "import torch; print(torch.__version__, torch.version.cuda, torch.cuda.is_available(), torch.cuda.get_device_name(0) if torch.cuda.is_available() else '-')" -``` - -**期待**: `2.11.0+cu128 12.8 True <GPU 名>`。 - -`False` の場合、`nvidia-smi` が通っているなら torch のビルドを 2 段で疑う -(`.venv/bin/python -c "import torch; print(torch.version.cuda)"`): - -1. `None` なら CPU 版 wheel。`uv sync --group mineru --reinstall` で入れ直す。 -2. 値があるのに `False` なら、**wheel の CUDA 世代がホストドライバより新しい**。 - 警告に `The NVIDIA driver on your system is too old (found version 12080)` の - ような行が出る(12080 = CUDA 12.8 = ホストの現在値)。`nvidia-smi` 右上の - `CUDA Version` が wheel の `torch.version.cuda` より小さければこれ。実測: PyPI - 既定の `2.13.0+cu130` は driver 580 系以降を要求し、このホスト(573.22 / - CUDA 12.8)では初期化に失敗して CPU に落ちていた。 - -2 を避けるため、`pyproject.toml` は torch/torchvision を **cu128 index に固定**して -いる(`[[tool.uv.index]] pytorch-cu128` と `[tool.uv.sources]`、torch は `<2.12` -── cu128 wheel は torch 2.11 で打ち止め)。ホストのドライバを 580 系以降に更新した -なら、この固定を外して既定 wheel に戻してよい。 - -## 4. 実 PDF の変換が GPU で速くなっているか - -**arXiv の pdf URL を渡しても MinerU は通らない**: ingest.py は URL から arXiv id を -復元して rung 1(LaTeX)に落とす(仕様。そちらが厳密に良い)。GPU を測るには PDF を -ローカルに落として**パスで**渡す: - -```bash -curl -L -o /tmp/paper.pdf https://arxiv.org/pdf/1702.04924 -time uv run .claude/skills/math-extract/scripts/ingest.py /tmp/paper.pdf \ - --allow-mineru --pages 1-5 --cache-dir /tmp/gpu-check -``` - -**期待**: -- JSON に `"stage": "mineru-pipeline"`、`"ok": true`。 -- 所要時間が CPU 時より短い。実測(RTX 4060 Laptop、arXiv:1702.04924 の 5 ページ、 - `--pages 1-5`、モデルはキャッシュ済み): **GPU 22 秒 / CPU 60 秒** - (`MINERU_DEVICE_MODE=cpu` で同じ PDF を再実行。CPU 側は 20 コアを使い切って - user 7 分 9 秒)。モデル取得を含む初回は 1 分 17 秒。 - **倍率は 3 倍弱で、「CPU は数分」ではない** ── 従来の CPU 基準は別の文献で - 測ったものらしく、この文献では再現しなかった。GPU 判定は倍率ではなく、 - 次のメモリ確認で行うのが確実。 -- デバイスの直接確認は `nvidia-smi` を並走させる。ingest.py は mineru の stderr を - 捕まえて成功時には出さないので、ログで `cuda` を探すことはできない。変換中に - `nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv,noheader` を - 数秒おきに叩き、メモリが上がることを見る(実測: 待機 1.5GB → 変換中 3.8GB)。 - WSL2 では `--query-compute-apps` はプロセスを出さないので、空でも異常ではない。 - -初回はモデルのダウンロード(pipeline で ~0.6GB、hybrid-engine はさらに VLM 分)が -走る。`hf-models` volume に入るので 2 回目以降は走らない。事前に落としておきたい -場合は `mineru-models-download`。 - -## 5.(任意)hybrid-engine を試す - -精度 95%(pipeline は 86%)だが、**VRAM 8GB はこのバックエンドの最低ラインで、 -しかも Windows デスクトップと共有**のため OOM しうる。試すなら: - -```bash -uv run .claude/skills/math-extract/scripts/ingest.py <PDF> \ - --allow-mineru --backend hybrid-engine --effort high --cache-dir /tmp/gpu-check -``` - -- **成功したら**: 数式が濃い文献ではこちらを使う価値がある。VRAM に余裕を作るには - 実行前に Windows 側の GPU 消費(ブラウザのハードウェアアクセラレーション等)を - 減らす。実測(同じ 5 ページ、Windows が 1.5GB を使っている状態): **OOM せず - 2 分 42 秒**で完了 ── pipeline の 22 秒に対し約 7 倍で、常用ではなく数式が濃い - 文献に限って選ぶ、という前提は変わらない。 -- **`CUDA out of memory` で落ちたら**: `--backend` を外して pipeline に戻す(既定)。 - ingest.py の既定が pipeline なのはこのためで、設定変更は不要。 - -## 6. math-extract → math-review の実地確認(パイロット) - -§2–4 は GPU が動くかの確認。ここは **GPU を使う唯一の実利用者である -`math-extract` が、成果物の下流(Lean 形式化と `/math-review`)まで実際に -噛み合うか**の確認で、再ビルド後に一度だけ通せばよい。 - -背景: `docs/math/` のノートは現在 **0 件**で、フォーマットは一度も実運用されて -いない。ノートを読む側(`math-review`、AGENTS.md *Think before coding*)の配線は -入れたが、本番ノートに対しては未検証。題材に split inclusion を選ぶのは、 -`note-format.md` の雛形がこの対象で書かれており、対応する Lean -(`QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean`, -`QuantumSystem/Algebra/LocalNet/SplitProperty.lean`)が既にあるため。 -主要文献 Doplicher–Longo (Invent. Math. 75, 1984) と Buchholz (CMP 36, 1974) は -arXiv にないので **PDF → MinerU 経路(§4 の rung 4)を通る**。GPU がここで効く。 - -### 6-1. 抽出 - -```bash -/math-extract split inclusion of von Neumann algebras -``` - -PDF が 4 本以上ならスキルは見積りを出して止まる(想定どおり)。少数なら続行。 - -**成果物として確認すること**(`docs/math/split-inclusion.md`): - -| 見るもの | 合格条件 | -|---|---| -| step 6 の 4 検査 | Firewall / Quote / Locator / Discipline が全通過、スキルの報告に件数が出る | -| `### Adopted general form` | **判別子の引用だけで終わっていないこと。** 環境対象・標準仮定・量化子の順序・依拠する `(A#)` を含む完結した言明が書かれているか。ここが「(D1), because (X3)…」だけなら仕様(`note-format.md`)どおりに書かれていない | -| `## Hypotheses` | `model-dependent` の各行に **名前のある witness**。無ければ `open` に落ちているか | -| `## Degeneracies` | チェックリスト全項目に行がある(効果なしの行も含む)。特に `SplitProperty.lean` の module doc が既に述べている「退化表現では自明に成り立つ」「格子領域では空領域が全てに直交する」に対応する行があるか | -| `## Not investigated` | 非空 | -| frontmatter | `implemented-as: none`(この時点では Lean を指さない)、`worst-tier` が load-bearing 行の**最小**値 | - -**既存 module doc との突き合わせ**が本命の検証。`SplitInclusion.lean` / -`SplitProperty.lean` の module doc は既に文献・採用理由・model-dependent 性・ -退化ケースを抱えている(ただし locator なし)。ノートがそれを **再現できるか、 -locator を付けられるか、食い違うか** を見る。食い違ったらどちらが正しいかを -判断すること — ノートが勝つとは限らない。 - -### 6-2. レビュー - -```bash -/math-review QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean -``` - -**配線が効いていることの確認点**: - -1. レポート冒頭に `**Extraction notes**:` 行が出て、`docs/math/split-inclusion.md` - を指している(`none matched` ならノートの解決に失敗している)。 -2. perspective 3(Abstraction & literature conformance)と 5(vacuity)の - findings または cleared 報告が、ノートの `(D#)` / `(X#)` / `## Degeneracies` - の行を**行 id で引用**している。引用がなければ、ノートを渡しただけで読まれて - いない。 -3. ノートの tier (a)/(b) 行に依拠した主張が **(b) verified** として出ている - ((c) 止まりなら tier 変換規則が効いていない)。 -4. `docs/math/split-inclusion.md` の `implemented-as:` に宣言名が書き込まれ、 - `docs/math/README.md` の Index に行が入っている。宣言がノートの採用形と - ずれている場合は **back-link は書かれず、perspective 3 の finding が出る** - のが正しい挙動。 -5. `## Not reviewed` に、ノートの `## Not investigated` が残した穴が引き継がれて - いる。 - -### 6-3. 判定 - -- 6-1 の表と 6-2 の 5 点が全部通れば、成果物フォーマットは下流で使える状態。 -- 6-2 の 1 が通らない → `math-review/SKILL.md` step 1 のノート解決。 -- 6-2 の 2–3 が通らない → `.claude/agents/math-reviewer.md` のノート参照節と - tier 変換表。 -- 6-2 の 4 が通らない → `math-review/SKILL.md` step 4 の reconcile 段。 -- 6-1 の `Adopted general form` が言明になっていない → - `.claude/skills/math-extract/references/note-format.md` の同節。 - -パイロットで書かれるのは `docs/math/split-inclusion.md` と -`docs/math/README.md` の 1 行だけで、Lean には触れないので `lake build` は不要。 - -## 7. 失敗時の切り分け - -| 症状 | 原因と対処 | -|---|---| -| 再ビルドでコンテナ自体が起動しない(`could not select device driver "" with capabilities: [[gpu]]`) | Docker Desktop → Settings → General で WSL 2 based engine を確認。Windows 側 NVIDIA ドライバが古い場合は更新。**応急処置**: `devcontainer.json` の `runArgs` 2 行を削って再ビルドすれば従来どおり CPU で動く | -| コンテナは起動するが `nvidia-smi` が無い / NVML エラー | Docker Desktop を再起動 → WSL を `wsl --shutdown` してから Docker Desktop を起動し直す。それでも駄目なら Windows 側ドライバを更新 | -| `torch.cuda.is_available()` が `False`(`nvidia-smi` は通る) | §3 の 2 段チェック。(1) `torch.version.cuda` が `None` なら CPU wheel、(2) 値があり `driver ... is too old (found version 12080)` の警告が出るなら wheel の CUDA 世代がホストドライバより新しい ── cu128 固定(現状の解)かホストドライバを 580 系へ。どちらでもないなら Docker Desktop の GPU support 設定と再起動 | -| mineru が `[Errno 13] Permission denied: '/home/vscode/.cache/huggingface/hub'` で落ちる | `hf-models` volume が root 所有のまま。`onCreateCommand` が 2 つのキャッシュを chown する(§1)が、volume を新規作成した直後に手で直すなら `sudo chown -R vscode:vscode /home/vscode/.cache/huggingface` | -| mineru がモデルダウンロードで止まる | ネットワーク。取得元は `devcontainer.json` の `containerEnv` で `huggingface` に固定してある。HuggingFace に届かない環境なら、固定を外さずそのコマンドだけ `MINERU_MODEL_SOURCE=modelscope mineru …` で上書きする | -| 変換が CPU 時と同じくらい遅い | 成功時の mineru ログは出ないので、§4 のメモリ確認で GPU を使っているかを見る。比較したいときは `MINERU_DEVICE_MODE=cpu` を付けた同じコマンドと並べる。§3 が `True` で、変換中に GPU メモリが上がらないなら issue 級なので報告を | - -## 8. 確認が全部通ったら - -§1–5 と §7 は以後も再ビルドのたびに使えるので消さなくてよい。§6 のパイロットは -一度通れば役目を終えるが、`math-extract` と `math-review` のノート受け渡しを -書き換えたときの回帰確認としてそのまま使える。 - -`math-extract` スキル側の GPU 関連の記述は -`.claude/skills/math-extract/references/ingestion.md` の Rung 4 にある。 From 351f5ddf0f48ac6049b6e36b9d8ee7a2aca0c80e Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 18:20:19 +0000 Subject: [PATCH 094/113] docs: add proof route and nonvacuity check to math-extract Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --- .claude/agents/math-extractor.md | 22 +++++--- .claude/skills/math-extract/SKILL.md | 13 ++++- .../math-extract/references/note-format.md | 52 ++++++++++++++++++- 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/.claude/agents/math-extractor.md b/.claude/agents/math-extractor.md index 9144758..7f04ccb 100644 --- a/.claude/agents/math-extractor.md +++ b/.claude/agents/math-extractor.md @@ -214,6 +214,13 @@ sources stating genuinely different results under the same name is two rows, plus a note for lane 1. Keep each source's own numbering as the locator; never renumber and never merge two numbered statements because they look alike. +For a row whose proof status is `proved in source` and that you actually read +through, add a `Proof route:` line — one reason per step, each step naming the +(R#)/(A#)/[ext] edge it consumes. Route and `Depends on:` must agree: an edge a +step consumes belongs in `Depends on:`, and a listed edge no step consumes is +either an error in the list or a step you skipped. A proof you only skimmed +gets no route and no `proved in source` — that reading is `sketched`. + Do not classify hypotheses and do not judge degenerate cases. If you notice either, put it in `## Handoffs` and let the orchestrator route it. @@ -258,12 +265,15 @@ and splitting the lane would have two agents build it twice. Run the degeneracy checklist against the adopted general form and record a disposition for **every** item, including the ones where nothing happens — "no -effect" is a result: the zero object (zero algebra, the scalars, an empty -region); the finite-dimensional case; the commutative case; the non-separable or -non-σ-finite case; the type III case; the non-unital or degenerate-representation -case; and a degenerate index set in which everything is orthogonal to everything. -Then one probe per quantifier — swap it with its neighbour and say whether the -meaning changes — and one per hypothesis — drop it and say what survives. +effect" is a result: **nonvacuity of the intended case** (a corpus-named +instance where the form holds non-trivially, or "none found — <what was +searched>" — the positive mirror of lane 3's witness rule); the zero object +(zero algebra, the scalars, an empty region); the finite-dimensional case; the +commutative case; the non-separable or non-σ-finite case; the type III case; +the non-unital or degenerate-representation case; and a degenerate index set in +which everything is orthogonal to everything. Then one probe per quantifier — +swap it with its neighbour and say whether the meaning changes — and one per +hypothesis — drop it and say what survives. This is a coverage requirement, not a quota. Knuth's thirty-one attempts are worth having because they were systematic, not because they were thirty-one; a diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md index dda4efb..58476bf 100644 --- a/.claude/skills/math-extract/SKILL.md +++ b/.claude/skills/math-extract/SKILL.md @@ -210,6 +210,10 @@ Three things are **yours**, not any lane's: silently claims coverage it does not have. 3. **`worst-tier`** — the minimum tier over the rows the adopted form and the main results rest on. Not the average, and not the best. +4. **The variant comparison grid.** Lane 1's (D#) rows are its only input, but + choosing the axes — the columns along which the variants genuinely differ — + needs all the rows at once, which no lane has. The grid is a derived index + and carries no tier; when it disagrees with a (D#) block, the grid is wrong. On a re-extraction, carry `## Rejected formulations and refuted claims` and `## Sources` forward verbatim and append to them; replace every other section. @@ -281,8 +285,13 @@ so read every hit rather than counting them. A `model-dependent` row with no witness becomes `open`. A `rejected` row with no typed discriminator, or resting on a banned ground, becomes `preference-only`. Then check by eye that every degeneracy checklist item has - a row, including the ones with no effect, and that `## Not investigated` is - present **and** non-empty. + a row — including the ones with no effect, and including the + `intended case is nonvacuous` row (a named instance or an explicit + "none found — <what was searched>") — and that `## Not investigated` is + present **and** non-empty. Finally, for each `(R#)` carrying a + `Proof route:`, cross-check route against `Depends on:` both ways: an edge a + step consumes but the list omits is the exact omission the field exists to + catch; a listed edge no step consumes is an error in one of the two. Then update `sources.md`: one row per source attempted this run, and a `Notes` entry for any locator you adjudicated. **This is the only step that writes to diff --git a/.claude/skills/math-extract/references/note-format.md b/.claude/skills/math-extract/references/note-format.md index b895bc8..0f8636e 100644 --- a/.claude/skills/math-extract/references/note-format.md +++ b/.claude/skills/math-extract/references/note-format.md @@ -57,6 +57,11 @@ $$ ### Variants as the sources write them +| (D#) | Source | <axis> | <axis> | <axis> | Tier | +|---|---|---|---|---|---| +| (D1) | [DL84] | pair of algebras | second algebra arbitrary | no vector | a | +| (D2) | [BU74] | net-level | second algebra a commutant | vector required | b | + **(D1) [DL84] §1** — tier (a) > <verbatim quote, in the source's language, unmodified, formulas in the @@ -85,7 +90,11 @@ $$ that discriminates — e.g. "This is (D1); (X3) shows (D2) drops the non-σ-finite case that [DL84] §1 covers." If no discriminator justifies the choice, write "provisional — no discriminator separates (D1) from (D2)" and stop; do not - manufacture a reason.> + manufacture a reason. + + When the literature has a canonical display for the object — an inclusion + chain, a commuting diagram — it may follow the written-out statement as + display math; it supplements the statement and never replaces it.> ## Notation and conventions @@ -102,6 +111,8 @@ $$ - Source: [DL84] Thm 3.2 · tier (a) · **proved in source** - Depends on: (R2), (A1), [ext: …] - Conventions: (C1) +- Proof route: <proved-in-source rows only, optional — one reason per step; + each step names its justification and the (R#)/(A#)/[ext] edge it consumes> - Verbatim: > <quote — tier (a) only; must survive the quote check> @@ -119,6 +130,7 @@ $$ | Case | Effect on the adopted form | Tier | |---|---|---| +| intended case is nonvacuous | <named instance, or "none found — <what was searched>"> | — | | zero object / scalars | … | — | | finite-dimensional | … | — | | commutative | … | — | @@ -236,6 +248,17 @@ mean, and why the generality is the one under discussion. Not a survey. - Every variant carries a source, a tier, and a locator where the tier allows one. **A variant with no source is not a variant** — it belongs under `## Rejected formulations` as a candidate. +- **The comparison grid is a derived index, not a claim.** The orchestrator + writes it at merge from the (D#) blocks below it, choosing as columns the + axes along which the corpus actually splits (quantification level, what the + second object is, extra data such as a distinguished vector — whatever the + variants genuinely differ on). Like the macro preamble it carries no tier and + no locator, and when grid and (D#) block disagree, the grid is wrong. The + verbatim blocks and `differs from:` lines are unchanged by its presence. + **Why:** filling one column per axis is what makes a variant axis visible at + merge time — the adopted general form's generality decisions are made along + exactly these axes, and an axis nobody wrote down is an axis silently + dropped. - Never merge two sources' formulations into one row because they look alike, and never renumber a source's own labels. - `differs from:` states the difference in one sentence. "Slightly different" is @@ -259,6 +282,12 @@ mean, and why the generality is the one under discussion. Not a survey. against, and it is what `math-review` compares an elaborated type to. Both need a statement whose quantifier order and hypotheses are unambiguous in *one* place; a pointer to a quote in another notation is not that. +- **A canonical display supplements the statement; it never replaces it.** + When the literature writes the object as a standard display — an inclusion + chain, a commuting diagram — transcribing it after the written-out statement + is welcome, but the written-out sentence remains mandatory: a display-only + adopted form is the pointer-only failure the previous rule forbids, in + prettier clothes. - No proposed notation, no identifiers. ### Notation and conventions @@ -276,6 +305,17 @@ the inference came from. That inference is tier (b) at best. - `proof status` ∈ proved in source / sketched / cited elsewhere / asserted. Cheap to record and it tells the implementer where the real work is. +- **`Proof route:` — one reason per step.** Optional, and only on rows whose + proof status is `proved in source`. Each step names its justification — a + definition unfolded, a dependency invoked, a substitution, an approximation — + and the (R#)/(A#)/[ext] edge it consumes. **Every edge named in the route + must appear in `Depends on:`, and every `Depends on:` edge of a routed row + must be consumed by some step** — that cross-check is the field's point. + **Why:** a hypothesis the proof uses but the row never lists is the most + expensive omission a formalization inherits, and per-step naming is the + cheapest audit of the dependency list. It also keeps proof status honest: a + route cannot be written for a proof that was only skimmed, so a row that + claims `proved in source` and cannot state its route was read as a sketch. - Every dependency a source does not prove in the corpus is marked `[ext: …]`. At tier (c)/(d) it carries no locator and instead carries a one-line statement of what the external result says — see the substitution rule below. @@ -306,6 +346,16 @@ Every checklist item gets a row, including the ones where nothing happens: "no effect" is a result, and an unlisted case is an unchecked one. One row per quantifier swap and per dropped hypothesis. This is coverage, not a quota. +The `intended case is nonvacuous` row is never omitted: it names an instance — +from the corpus, at that attestation's tier — where the adopted form holds +non-trivially, or records "none found — <what was searched>". A corpus with no +non-trivial instance is a finding about the adopted form, in the same +discipline as `## Prior art`'s "could not find X, having searched …". +**Why:** the failure witnesses in `## Hypotheses` guard one direction — a +statement that proves too much — and this row guards the other: a definition +nothing satisfies formalizes cleanly and says nothing, and vacuity is cheapest +to catch before the Lean exists. + ### Rejected formulations and refuted claims - **Append-only. Rows are never deleted.** A changed disposition is edited in From 4d59f7f96d0ea702b322c60bc86c778a30d6d811 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:43:06 +0000 Subject: [PATCH 095/113] feat(ForMathlib): add supporting lemmas for Hilbert space, rank-one operators, commutants Small additions upstream candidates needed by the von Neumann algebra type I structure theorem and tensor factorization work: helpers on CStarAlgebra Hilbert space, rank-one operators, and von Neumann algebra commutants. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../Analysis/CStarAlgebra/HilbertSpace.lean | 5 +++ .../Analysis/InnerProductSpace/RankOne.lean | 6 ++++ .../Analysis/VonNeumannAlgebra/Commutant.lean | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean index a467d56..de84600 100644 --- a/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean +++ b/QuantumSystem/ForMathlib/Analysis/CStarAlgebra/HilbertSpace.lean @@ -35,6 +35,11 @@ noncomputable instance instPreComplexHilbertSpace [ComplexHilbertSpace H] : Comp end ComplexHilbertSpace +/-- `ℂ` is a complex Hilbert space over itself — the one-dimensional one. It is the smallest +nondegenerate space on which the bundled `ComplexHilbertSpace` interfaces can be exercised, and +the class has no instance for it otherwise, since its three parents are found separately. -/ +noncomputable instance : ComplexHilbertSpace ℂ where + section UnitaryMap variable {H K : Type*} [ComplexHilbertSpace H] [ComplexHilbertSpace K] diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean index 560379e..5580ecb 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean @@ -12,6 +12,12 @@ A continuous linear operator on an inner product space that commutes with every von Neumann algebras `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)`. We also record that a rank-one operator has finite- (in fact one-) dimensional range, used to see that a rank-one minimal projection of `B(H)` has one-dimensional multiplicity space. + +## Notation + +`⊗̄` in the prose above is documentation shorthand for the von Neumann (spatial) tensor product of +algebras; that convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, +downstream of this file, where the algebras it names are defined. -/ @[expose] public section diff --git a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean index 33e16d0..1dfa2af 100644 --- a/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean +++ b/QuantumSystem/ForMathlib/Analysis/VonNeumannAlgebra/Commutant.lean @@ -37,6 +37,10 @@ scope; activate it with `open scoped VonNeumannAlgebra`. |---|---|---| | `M′` | `VonNeumannAlgebra.commutant M` | `open scoped VonNeumannAlgebra` | | `s″` | `VonNeumannAlgebra.generated s`, i.e. `(s ∪ s⋆)''` | `open scoped VonNeumannAlgebra` | + +`⊗̄` is documentation shorthand for the von Neumann (spatial) tensor product of algebras; that +convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, downstream +of this file, where the algebras it names are defined. -/ @[expose] public section @@ -59,6 +63,22 @@ lemma Set.image_centralizer {M₁ M₂ F : Type*} [Mul M₁] [Mul M₂] apply EquivLike.injective φ rw [map_mul, map_mul, h] +/-- **The range of a `star`-preserving map is star-closed.** The hypothesis is stated for a bare +map together with its `star`-compatibility rather than for a bundled `*`-homomorphism, so that it +applies to composites assembled on the spot — the generating sets `π(𝔄(O))` of the local von +Neumann algebras of a net are of exactly that shape — and it is what discharges the star-closedness +hypothesis of `VonNeumannAlgebra.coe_commutantSet_of_star_eq` and +`VonNeumannAlgebra.coe_generated_of_star_eq` below. -/ +theorem Set.star_range {A B : Type*} [InvolutiveStar A] [InvolutiveStar B] {f : A → B} + (hf : ∀ a, f (star a) = star (f a)) : star (Set.range f) = Set.range f := by + ext x + simp only [Set.mem_star, Set.mem_range] + constructor + · rintro ⟨a, ha⟩ + exact ⟨star a, by rw [hf, ha, star_star]⟩ + · rintro ⟨a, ha⟩ + exact ⟨star a, by rw [hf, ha]⟩ + namespace VonNeumannAlgebra variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] @@ -87,11 +107,23 @@ lemma mem_commutantSet_iff {s : Set (H →L[ℂ] H)} {z : H →L[ℂ] H} : z ∈ commutantSet s ↔ ∀ g ∈ s, g * z = z * g ∧ star g * z = z * star g := StarSubalgebra.mem_centralizer_iff ℂ +/-- On a **star-closed** set the symmetrization built into `commutantSet` is vacuous: it is then +literally the commutant `s′` of the operator-algebra literature. -/ +lemma coe_commutantSet_of_star_eq {s : Set (H →L[ℂ] H)} (hs : star s = s) : + (commutantSet s : Set (H →L[ℂ] H)) = s.centralizer := by + rw [coe_commutantSet, hs, Set.union_self] + /-- The von Neumann algebra `s''` generated by a set `s` of bounded operators, defined as the commutant of its commutant. -/ noncomputable def generated (s : Set (H →L[ℂ] H)) : VonNeumannAlgebra H := (commutantSet s).commutant +/-- For a **star-closed** generating set `generated s` is literally the double commutant `s″` of +the operator-algebra literature, with no symmetrization step. -/ +lemma coe_generated_of_star_eq {s : Set (H →L[ℂ] H)} (hs : star s = s) : + (generated s : Set (H →L[ℂ] H)) = s.centralizer.centralizer := by + rw [generated, VonNeumannAlgebra.coe_commutant, coe_commutantSet_of_star_eq hs] + /-- The carrier of a von Neumann algebra is norm-closed: it is a double centralizer, and centralizers are closed. (Von Neumann algebras are even weakly closed, but the norm-closedness is what the subalgebra-membership lemmas of the continuous functional calculus consume.) -/ From f66a2ffd775725d8450c8133aa03f61444ac4c4d Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:43:16 +0000 Subject: [PATCH 096/113] feat: prove the type I factor structure theorem and spatial tensor factorization Extends VonNeumannAlgebra.Basic with supporting lemmas, adds the spatial tensor decomposition and tensor-factor commutant theorems, and uses them to prove the type I structure theorem (every type I factor is spatially isomorphic to the bounded operators on some Hilbert space) together with abelian/minimal-projection comparison results. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../Algebra/VonNeumannAlgebra/Basic.lean | 71 ++++++++-- .../SpatialDecomposition.lean | 35 +++-- .../VonNeumannAlgebra/StructureTheorem.lean | 42 ++++-- .../VonNeumannAlgebra/TensorFactor.lean | 5 +- .../Algebra/VonNeumannAlgebra/TypeI.lean | 126 ++++++++++-------- 5 files changed, 196 insertions(+), 83 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean index 7e36afd..f7ba3ca 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/Basic.lean @@ -61,6 +61,10 @@ The file is organised in three parts: scalar corner `(q a e)⋆(q a e) = c • e`, `c > 0`, yields `e ≼[N] q`. * `VonNeumannAlgebra.IsMinimalProjection.mvNSub_of_isFactor` — the comparison theorem for minimal projections: in a factor, a minimal projection is subordinate to every nonzero projection. +* `VonNeumannAlgebra.eq_boundedLinearOperators_complex` — on the one-dimensional Hilbert space + `𝓑(ℂ)` is the *only* von Neumann algebra, every bounded operator on `ℂ` being a scalar + (`VonNeumannAlgebra.apply_eq_mul_apply_one`, `VonNeumannAlgebra.mul_comm_complex`). This is what + makes one-dimensional models of downstream properties both easy and uninformative. The full comparison theorem (any two projections in a factor are comparable) requires central supports and polar decomposition for general projections and is not developed here; the @@ -109,6 +113,7 @@ algebra* of all operators), and the expected type disambiguates. The two levels canonical `⋆`-isomorphism `boundedLinearOperators.starAlgEquiv`. -/ scoped notation:max "𝓑(" H ")" => VonNeumannAlgebra.boundedLinearOperators H +/-- The carrier of `𝓑(H)` is all of `H →L[ℂ] H`. -/ @[simp] lemma coe_boundedLinearOperators : ((𝓑(H) : VonNeumannAlgebra H) : Set (H →L[ℂ] H)) = Set.univ := rfl @@ -137,13 +142,47 @@ noncomputable def boundedLinearOperators.starAlgEquiv : (H →L[ℂ] H) →⋆ₐ[ℂ] (𝓑(H) : VonNeumannAlgebra H).toStarSubalgebra) (fun _ => rfl) (fun _ => rfl) -/-! ### Factors, minimal projections and Murray–von Neumann equivalence -/ - /-- A von Neumann algebra is closed under scalar multiplication. -/ lemma smul_mem {N : VonNeumannAlgebra H} (c : ℂ) {x : H →L[ℂ] H} (hx : x ∈ N) : c • x ∈ N := by rw [Algebra.smul_def] exact mul_mem (algebraMap_mem N.toStarSubalgebra c) hx +/-! ### The one-dimensional case + +On `ℂ` every bounded operator is a scalar, so there is exactly one von Neumann algebra. This is +what makes one-dimensional witnesses of net- and inclusion-level properties go through without +computing any generated algebra — and, read the other way, what makes them evidence of +inhabitation only: on `ℂ` no algebra, no net and no representation is distinguished from any +other. +-/ + +/-- A bounded operator on `ℂ` is multiplication by its value at `1`. -/ +lemma apply_eq_mul_apply_one (x : ℂ →L[ℂ] ℂ) (w : ℂ) : x w = w * x 1 := by + rw [← smul_eq_mul, ← map_smul, smul_eq_mul, mul_one] + +/-- **Bounded operators on `ℂ` commute.** Each is multiplication by a scalar +(`apply_eq_mul_apply_one`), and scalars commute. -/ +lemma mul_comm_complex (x y : ℂ →L[ℂ] ℂ) : x * y = y * x := by + refine ContinuousLinearMap.ext fun z => ?_ + rw [ContinuousLinearMap.mul_apply, ContinuousLinearMap.mul_apply, + apply_eq_mul_apply_one x (y z), apply_eq_mul_apply_one y (x z), + apply_eq_mul_apply_one y z, apply_eq_mul_apply_one x z] + ring + +/-- **On `ℂ` there is only one von Neumann algebra.** Every von Neumann algebra on the +one-dimensional Hilbert space is `𝓑(ℂ)`: it contains `1` and is closed under scalars, while +every bounded operator on `ℂ` is a scalar multiple of `1` (`apply_eq_mul_apply_one`). -/ +lemma eq_boundedLinearOperators_complex (N : VonNeumannAlgebra ℂ) : N = 𝓑(ℂ) := by + refine SetLike.ext fun x => ⟨fun _ => mem_boundedLinearOperators x, fun _ => ?_⟩ + have hx : x = (x 1) • (1 : ℂ →L[ℂ] ℂ) := by + refine ContinuousLinearMap.ext fun z => ?_ + rw [ContinuousLinearMap.smul_apply, ContinuousLinearMap.one_apply, smul_eq_mul, + apply_eq_mul_apply_one x z, mul_comm] + rw [hx] + exact smul_mem _ (one_mem N) + +/-! ### Factors, minimal projections and Murray–von Neumann equivalence -/ + /-- A von Neumann algebra `N` is a **factor** when its centre is trivial: every operator lying in both `N` and its commutant is a scalar multiple of the identity. -/ def IsFactor (N : VonNeumannAlgebra H) : Prop := @@ -157,12 +196,22 @@ supports comparison theory without invoking Borel functional calculus. -/ def IsMinimalProjection (N : VonNeumannAlgebra H) (e : H →L[ℂ] H) : Prop := IsStarProjection e ∧ e ∈ N ∧ e ≠ 0 ∧ ∀ a ∈ N, ∃ c : ℂ, e * a * e = c • e +omit [CompleteSpace H] in +/-- **A nonzero operator witnesses a nonzero space.** On a subsingleton `H` every operator is `0`, +so exhibiting any `x ≠ 0` already gives `Nontrivial H`. This is why almost none of the results +below need `[Nontrivial H]` as a hypothesis: they carry a nonzero projection, which supplies it. +The exceptions are the statements that quantify over projections without asserting one exists +(`IsFactor.isTypeI_iff_exists_isMinimalProjection`, `isTypeIFactor_iff_isFactor_and_isTypeI`) and +the ones producing a minimal projection of `𝓑(H)` out of nothing. -/ +lemma nontrivial_of_ne_zero {x : H →L[ℂ] H} (hx : x ≠ 0) : Nontrivial H := + let ⟨y, hy⟩ := ContinuousLinearMap.exists_ne_zero hx + ⟨⟨x y, 0, hy⟩⟩ + /-- A von Neumann algebra with a minimal projection acts on a nonzero space: the minimal projection is nonzero, so it sends some vector to a nonzero vector, witnessing `Nontrivial H`. -/ lemma IsMinimalProjection.nontrivial {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : Nontrivial H := - let ⟨x, hx⟩ := ContinuousLinearMap.exists_ne_zero he.2.2.1 - ⟨⟨e x, 0, hx⟩⟩ + nontrivial_of_ne_zero he.2.2.1 /-- A minimal projection has no proper nonzero subprojection in `N`: if a projection `f ∈ N` satisfies `f ≤ e` (the Loewner order on projections, equivalently the range inclusion @@ -267,10 +316,14 @@ lemma isCentralProjection_one (N : VonNeumannAlgebra H) : IsCentralProjection N ⟨IsStarProjection.one _, one_mem _, one_mem _⟩ /-- In a factor, every central projection is trivial: it is `0` or `1`. This is the -projection-level form of the triviality of the centre. -/ -theorem IsFactor.central_projection_eq [Nontrivial H] {N : VonNeumannAlgebra H} +projection-level form of the triviality of the centre. On a subsingleton `H` the conclusion is +vacuous (every operator is `0 = 1`), which is why no nontriviality hypothesis is needed. -/ +theorem IsFactor.central_projection_eq {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsCentralProjection N e) : e = 0 ∨ e = 1 := by + rcases subsingleton_or_nontrivial H with hH | hH + · haveI := hH + exact Or.inl (Subsingleton.elim _ _) obtain ⟨c, hc⟩ := hN e he.2.1 he.2.2 have hidem : e * e = e := he.1.isIdempotentElem rw [hc] at hidem @@ -298,8 +351,9 @@ orthogonal projection `P` onto the closed `N`-invariant subspace generated by `e both `N` and `N'`, so it is central, hence `0` or `1`; since `P` acts as the identity on `e H` (so `P ≠ 0`, as `e ≠ 0`), `P = 1`, so the generated subspace is the whole space and `q` cannot annihilate it. This is the geometric input of the comparison theorem. -/ -theorem IsFactor.exists_mul_ne [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) +theorem IsFactor.exists_mul_ne {N : VonNeumannAlgebra H} (hN : IsFactor N) {e q : H →L[ℂ] H} (heN : e ∈ N) (he0 : e ≠ 0) (hq0 : q ≠ 0) : ∃ a ∈ N, q * a * e ≠ 0 := by + haveI : Nontrivial H := nontrivial_of_ne_zero he0 by_contra hcon have hcon' : ∀ a ∈ N, q * a * e = 0 := fun a haN => by by_contra h; exact hcon ⟨a, haN, h⟩ @@ -534,10 +588,11 @@ scaling lemma (via `mvNSub_of_ne`) with the central-support input (`IsFactor.exists_mul_ne`, which supplies an `a ∈ N` with `q a e ≠ 0`). It is the form of comparison needed to show a maximal orthogonal family of minimal projections exhausts the identity. -/ -theorem IsMinimalProjection.mvNSub_of_isFactor [Nontrivial H] {N : VonNeumannAlgebra H} +theorem IsMinimalProjection.mvNSub_of_isFactor {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) {q : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (hq0 : q ≠ 0) : e ≼[N] q := by + haveI : Nontrivial H := he.nontrivial obtain ⟨a, haN, hane⟩ := hN.exists_mul_ne he.2.1 he.2.2.1 hq0 exact he.mvNSub_of_ne hq hqN haN hane diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean index 0d07378..e7495d9 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SpatialDecomposition.lean @@ -62,11 +62,17 @@ span of the union of the ranges is the whole space; this is the operator-friendl `∃ c, v_p⋆ a v_q = c • e` for `a ∈ N`. * `IsPartialIsometry.sourceRangeEquiv` — the isometric equivalence `range (v⋆v) ≃ₗᵢ range (vv⋆)` induced by a partial isometry `v`. -* `VonNeumannAlgebra.IsFactor.exists_tensor_decomposition` — the `ℓ²`-sum form `H ≅ ℓ²(F; eH)` of +* `VonNeumannAlgebra.IsFactor.exists_lp_decomposition` — the `ℓ²`-sum form `H ≅ ℓ²(F; eH)` of the spatial decomposition of a type I factor. * `VonNeumannAlgebra.IsFactor.exists_tmul_decomposition` — the literal tensor form `H ≅ ℓ²(F) ⊗̂ (eH)`, obtained by composing with the tensor bridge `HilbertTensor.lpTensorEquiv`. + +## Notation + +`⊗̄` in the prose above is documentation shorthand for the von Neumann (spatial) tensor product of +algebras; that convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, +where the algebras it names (`HilbertTensor.vnTensorLeft` / `vnTensorRight`) are defined. -/ @[expose] public section @@ -177,10 +183,11 @@ The proof takes a *maximal* such family `F` (Zorn) and lets `p` be the orthogona the closed span `M` of the ranges; `p ∈ N`. If `M ≠ ⊤` then `r = 1 - p` is a nonzero projection in `N`, so by the comparison theorem some nonzero `q' ≼ r` is equivalent to `e`; `q'` is orthogonal to every `f ∈ F`, contradicting maximality. -/ -theorem IsFactor.exists_orthEquivFam_top [Nontrivial H] {N : VonNeumannAlgebra H} +theorem IsFactor.exists_orthEquivFam_top {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ := by + haveI : Nontrivial H := he.nontrivial obtain ⟨F, hF, hFmax⟩ := exists_maximal_orthEquivFam N e refine ⟨F, hF, ?_⟩ set S : Set H := {y | ∃ f ∈ F, ∃ x, f x = y} with hS @@ -256,17 +263,21 @@ oriented with source projection `v_p⋆ v_p = e` (`pisom_source`) and range proj noncomputable def OrthEquivFam.pisom (hF : OrthEquivFam N e F) (p : F) : H →L[ℂ] H := (hF.1 p.1 p.2).2.2.2.choose +/-- The chosen equivalence partial isometry `v_p` lies in `N`. -/ lemma OrthEquivFam.pisom_mem (hF : OrthEquivFam N e F) (p : F) : hF.pisom p ∈ N := (hF.1 p.1 p.2).2.2.2.choose_spec.1 +/-- The chosen `v_p` is a partial isometry. -/ lemma OrthEquivFam.pisom_isPI (hF : OrthEquivFam N e F) (p : F) : IsPartialIsometry (hF.pisom p) := (hF.1 p.1 p.2).2.2.2.choose_spec.2.1 +/-- The source projection of `v_p` is `e`: `v_p⋆ v_p = e`. -/ lemma OrthEquivFam.pisom_source (hF : OrthEquivFam N e F) (p : F) : star (hF.pisom p) * hF.pisom p = e := (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.1 +/-- The range projection of `v_p` is `p`: `v_p v_p⋆ = p`. -/ lemma OrthEquivFam.pisom_range (hF : OrthEquivFam N e F) (p : F) : hF.pisom p * star (hF.pisom p) = (p : H →L[ℂ] H) := (hF.1 p.1 p.2).2.2.2.choose_spec.2.2.2 @@ -554,12 +565,14 @@ noncomputable def OrthEquivFam.hilbertSumEquiv {N : VonNeumannAlgebra H} {e : H H ≃ₗᵢ[ℂ] lp (fun i : F => LinearMap.range ((i : H →L[ℂ] H) : H →ₗ[ℂ] H)) 2 := (hF.isHilbertSum htop).linearIsometryEquiv -/-- **Tensor-product decomposition of the Hilbert space.** A covering orthogonal family of +/-- **Multiplicity decomposition of the Hilbert space.** A covering orthogonal family of projections each Murray–von Neumann equivalent to `e` identifies `H` isometrically with `ℓ²(F; eH)` — the `ℓ²` sum, indexed by `F`, of copies of the fibre `range e` (which is the -*multiplicity space* when `e` is minimal, as in `exists_tensor_decomposition`; minimality is not -assumed in this lemma). This is the spatial content of the type I factor structure theorem: -`H ≅ ℓ²(F) ⊗̂ (eH)`. The equivalence +*multiplicity space* when `e` is minimal, as in `exists_lp_decomposition`; minimality is not +assumed in this lemma). The codomain is that `ℓ²` sum and nothing else: no tensor product occurs +here. Composing with the tensor bridge turns it into the literal `H ≅ ℓ²(F) ⊗̂ (eH)` of the type I +factor structure theorem — that is `OrthEquivFam.spatialEquiv`, and the existence statement is +`exists_tmul_decomposition`. The equivalence is built from the Hilbert-sum decomposition `H ≅ ⊕ᵢ range eᵢ` and the partial-isometry-induced isometries `range eᵢ ≅ range e`. -/ noncomputable def OrthEquivFam.multiplicityEquiv {N : VonNeumannAlgebra H} {e : H →L[ℂ] H} @@ -620,9 +633,9 @@ lemma OrthEquivFam.coe_hilbertSumEquiv_apply {N : VonNeumannAlgebra H} {e : H minimal projection `e` acts on a Hilbert space isometric to the `ℓ²` sum `ℓ²(F; eH)` of copies of `eH = range e`, indexed by a covering orthogonal family `F` (`OrthEquivFam`, with densely spanning ranges) of minimal projections equivalent to `e`. Composing with the tensor bridge turns -this `ℓ²` sum into the literal tensor product `H ≅ ℓ²(F) ⊗̂ eH`; see -`exists_tmul_decomposition`. -/ -theorem IsFactor.exists_tensor_decomposition [Nontrivial H] {N : VonNeumannAlgebra H} +this `ℓ²` sum into the literal tensor product `H ≅ ℓ²(F) ⊗̂ eH`; that is the statement of +`exists_tmul_decomposition`, and it — not this one — is the tensor-product form. -/ +theorem IsFactor.exists_lp_decomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ ∧ @@ -637,8 +650,8 @@ projection `e` acts on a Hilbert space isometric to the completed Hilbert tensor `ℓ²(F) ⊗̂ (eH)`, where `F` is a covering orthogonal family (`OrthEquivFam`, with densely spanning ranges) of minimal projections equivalent to `e` and `eH = range e` is the multiplicity space. This is the literal `H ≅ ℓ²(F) ⊗̂ eH` form of the type I structure theorem, obtained from -`exists_tensor_decomposition` by composing with the tensor bridge `HilbertTensor.lpTensorEquiv`. -/ -theorem IsFactor.exists_tmul_decomposition [Nontrivial H] {N : VonNeumannAlgebra H} +`exists_lp_decomposition` by composing with the tensor bridge `HilbertTensor.lpTensorEquiv`. -/ +theorem IsFactor.exists_tmul_decomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : ∃ F : Set (H →L[ℂ] H), OrthEquivFam N e F ∧ (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤ ∧ diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean index a662db6..ef140f6 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean @@ -54,12 +54,28 @@ carries the matrix unit `e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨ * `VonNeumannAlgebra.OrthEquivFam.conjStarAlgEquiv_matrixUnit` — `U e_{pq} U⋆ = |δ_p⟩⟨δ_q| ⊗̂ 1`. * `VonNeumannAlgebra.OrthEquivFam.conj_spatialEquiv_eq_vnTensorLeft` — the identification `U N U⋆ = B(ℓ²(F)) ⊗̄ 1`, with commutant companion `conj_spatialEquiv_commutant_eq_vnTensorRight`. -* `VonNeumannAlgebra.IsFactor.exists_spatial_tensorDecomposition` — the existence headline. -* `VonNeumannAlgebra.IsFactor.exists_split_tensorDecomposition` — the split tensor decomposition: +* `VonNeumannAlgebra.IsFactor.exists_spatial_tensor_decomposition` — the existence headline. +* `VonNeumannAlgebra.IsFactor.exists_split_tensor_decomposition` — the split tensor decomposition: for an inclusion `A ≤ B` of von Neumann algebras with intermediate type I factor `A ≤ N ≤ B` — a *split inclusion* in the sense of Doplicher–Longo (see `VonNeumannAlgebra.IsSplitInclusion`) — the same `U` sends `A` into `B(ℓ²(F)) ⊗̄ 1` and the commutant `B′` into `1 ⊗̄ B(eH)`. + +## References + +* [Yngvason] J. Yngvason, *Localization and Entanglement in Relativistic Quantum Physics*, in + *The Message of Quantum Science*, Lecture Notes in Physics 899, Springer 2015, pp. 325–348; + arXiv:1401.2652. Its §5.1 ("Causal Independence and Split Property") displays the two equations + cited below as `(38)`, `𝒜₁ ⊂ 𝒩 ⊂ 𝒜₂′`, and `(39)`, `𝒜₁ ⊂ ℬ(ℋ₁) ⊗ 𝟏` and `𝒜₂ ⊂ 𝟏 ⊗ ℬ(ℋ₂)`. +* [DL84] S. Doplicher, R. Longo, *Standard and split inclusions of von Neumann algebras*, + Invent. Math. 75 (1984) 493–536. +* [dB74] D. Buchholz, *Product states for local algebras*, Comm. Math. Phys. 36 (1974) 287–304. + +## Notation + +`⊗̄` in the prose above is documentation shorthand for the von Neumann (spatial) tensor product of +algebras; that convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, +where the algebras it names (`HilbertTensor.vnTensorLeft` / `vnTensorRight`) are defined. -/ @[expose] public section @@ -247,6 +263,7 @@ hypotheses throughout this file.) -/ local notation "δ" => lpDelta omit [CompleteSpace H] in +/-- `δ_i` unfolds to the `ℓ²` standard basis vector `lp.single 2 i 1`. -/ lemma lpDelta_apply [DecidableEq F] (i : F) : lpDelta i = lp.single (E := fun _ : F => ℂ) 2 i (1 : ℂ) := rfl @@ -531,11 +548,12 @@ lemma OrthEquivFam.nonempty_of_top [Nontrivial H] {F : Set (H →L[ℂ] H)} projection `e` (acting on a nonzero Hilbert space) is, up to a spatial isomorphism `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)`, exactly the tensor factor `B(ℓ²(F)) ⊗̄ 1`, with commutant `1 ⊗̄ B(eH)`: conjugation by `U` carries `N` onto `vnTensorLeft` and `N'` onto `vnTensorRight`. This is -Yngvason §5.1 (38)→(39) in its model-independent von-Neumann-algebraic form. -/ -theorem IsFactor.exists_spatial_tensorDecomposition {N : VonNeumannAlgebra H} +[Yngvason] §5.1 (38)→(39) in its model-independent von-Neumann-algebraic form (see the module +doc's reference list). -/ +theorem IsFactor.exists_spatial_tensor_decomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) : - ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] - HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), + ∃ (F : Set (H →L[ℂ] H)) + (U : H ≃ₗᵢ[ℂ] lp (fun _ : F => ℂ) 2 ⊗̂ LinearMap.range (e : H →ₗ[ℂ] H)), VonNeumannAlgebra.conj U N = vnTensorLeft ∧ VonNeumannAlgebra.conj U N′ = vnTensorRight := by haveI := he.nontrivial @@ -546,7 +564,8 @@ theorem IsFactor.exists_spatial_tensorDecomposition {N : VonNeumannAlgebra H} exact ⟨F, hF.spatialEquiv htop, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop⟩ -/-- **Split tensor decomposition (Yngvason §5.1 (38)→(39)).** Suppose an inclusion `A ≤ B` of von +/-- **Split tensor decomposition ([Yngvason] §5.1 (38)→(39); see the module doc's reference +list).** Suppose an inclusion `A ≤ B` of von Neumann algebras admits an intermediate factor `N ⊆ B(H)` with minimal projection `e` — that is, `A ≤ N ≤ B` with `N` type I. The existence of such an `N` is precisely what makes `A ≤ B` a *split inclusion* in the sense of Doplicher–Longo (*Standard and split inclusions of von Neumann @@ -560,11 +579,12 @@ tensor-splitting the inclusion — `A` lands in the left factor `B(ℓ²(F)) ⊗ `B′` lands in the right factor `1 ⊗̄ B(eH)`, with `N` and its commutant identified exactly. The commuting-pair form of this statement — `A₁ ≤ N ≤ A₂′` for a pair `(A₁, A₂)` — is recovered by instantiating `B := A₂′`. -/ -theorem IsFactor.exists_split_tensorDecomposition {N : VonNeumannAlgebra H} +theorem IsFactor.exists_split_tensor_decomposition {N : VonNeumannAlgebra H} (hN : IsFactor N) {e : H →L[ℂ] H} (he : IsMinimalProjection N e) {A B : VonNeumannAlgebra H} (h₁ : A ≤ N) (h₂ : N ≤ B) : - ∃ (F : Set (H →L[ℂ] H)) (U : H ≃ₗᵢ[ℂ] - HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), + ∃ (F : Set (H →L[ℂ] H)) + (U : H ≃ₗᵢ[ℂ] lp (fun _ : F => ℂ) 2 ⊗̂ LinearMap.range (e : H →ₗ[ℂ] H)), + Nonempty F ∧ VonNeumannAlgebra.conj U N = vnTensorLeft ∧ VonNeumannAlgebra.conj U N′ = vnTensorRight ∧ VonNeumannAlgebra.conj U A ≤ vnTensorLeft ∧ @@ -574,7 +594,7 @@ theorem IsFactor.exists_split_tensorDecomposition {N : VonNeumannAlgebra H} haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range haveI : DecidableEq F := Classical.decEq _ haveI : Nonempty F := OrthEquivFam.nonempty_of_top htop - exact ⟨F, hF.spatialEquiv htop, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, + exact ⟨F, hF.spatialEquiv htop, ‹Nonempty F›, hF.conj_spatialEquiv_eq_vnTensorLeft he htop, hF.conj_spatialEquiv_commutant_eq_vnTensorRight he htop, hF.conj_spatialEquiv_le_vnTensorLeft he htop h₁, hF.conj_spatialEquiv_le_vnTensorRight he htop h₂⟩ diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean index 3c53adb..b070c00 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TensorFactor.lean @@ -24,7 +24,9 @@ definitions above. The tensor notations that *are* declared live in `TensorProdu `⊗̂` for the completed Hilbert tensor product and `⊗ₕ` for elementary tensors. These are the objects in the split-property tensor decomposition `A₁ ⊆ B(H₁)⊗̄1`, -`A₂ ⊆ 1⊗̄B(H₂)` (paper eq. (39)). The file culminates in the **tensor commutation theorem** +`A₂ ⊆ 1⊗̄B(H₂)` — equation (39) of J. Yngvason, *Localization and Entanglement in Relativistic +Quantum Physics*, in *The Message of Quantum Science*, Lecture Notes in Physics 899, Springer 2015, +pp. 325–348 (arXiv:1401.2652), §5.1. The file culminates in the **tensor commutation theorem** `vnTensorLeft.commutant = vnTensorRight` (von Neumann's commutation theorem for a full factor on the first leg): the commutant of `B(H₁)⊗̄1` is exactly `1⊗̄B(H₂)`. @@ -102,6 +104,7 @@ noncomputable def tmulRightL (f : H₁) : H₂ →L[ℂ] HilbertTensor H₁ H₂ (LinearMap.mkContinuous (TensorProduct.mk ℂ H₁ H₂ f) ‖f‖ fun z => by rw [TensorProduct.mk_apply, TensorProduct.norm_tmul]) +/-- The inclusion `tmulRightL f` sends `z` to the elementary tensor `f ⊗ z`. -/ @[simp] lemma tmulRightL_apply (f : H₁) (z : H₂) : tmulRightL f z = tmul f z := rfl /-- The left and right amplifications commute: `(A ⊗̂ 1)(1 ⊗̂ B) = A ⊗̂ B = (1 ⊗̂ B)(A ⊗̂ 1)`. -/ diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean index 6e0b9b9..248b02b 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/TypeI.lean @@ -67,12 +67,25 @@ infinite-dimensional this exhibits `B(H)` as a **type I_∞ factor**. * `VonNeumannAlgebra.exists_isMinimalProjection_boundedLinearOperators` — `B(H)` has a minimal projection (rank-one). * `VonNeumannAlgebra.isTypeIFactor_boundedLinearOperators` — `B(H)` is a type I factor. -* `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(K)` for some - Hilbert space `K`. +* `VonNeumannAlgebra.exists_starAlgEquiv_boundedLinearOperators` — `B(H) ≃⋆ₐ B(ℓ²(ι))` with the + implementing isometry `H ≃ₗᵢ ℓ²(ι)`, for `ι` the index set of a Hilbert basis of `H`. * `VonNeumannAlgebra.isTypeIInfinite_boundedLinearOperators` — for infinite-dimensional `H`, `B(H)` is a type I_∞ factor, packaged as the intrinsic predicate `IsTypeIInfinite 𝓑(H)`. * `VonNeumannAlgebra.exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators` — for - infinite-dimensional `H`, `B(H) ≃⋆ₐ B(K)` with `K` itself infinite-dimensional. + infinite-dimensional `H`, the same with `ι` infinite, hence `ℓ²(ι)` infinite-dimensional. + +## Notation + +In the prose above `B(H)` names the mathematical object — the algebra of all bounded operators — +while `𝓑(H)` is the Lean notation for it. The two are used deliberately, not interchangeably: +`𝓑(H)` resolves to `VonNeumannAlgebra.boundedLinearOperators H` (bundled von Neumann algebra) or +to `H →L[ℂ] H` (operator type) according to the expected type, an overload tabled in +`QuantumSystem.Algebra.VonNeumannAlgebra.Basic` and bridged by +`boundedLinearOperators.starAlgEquiv`. + +`⊗̄` is documentation shorthand for the von Neumann (spatial) tensor product of algebras; that +convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, where the +algebras it names (`HilbertTensor.vnTensorLeft` / `vnTensorRight`) are defined. -/ @[expose] public section @@ -98,9 +111,10 @@ def IsTypeIFactor (N : VonNeumannAlgebra H) : Prop := /-- A factor with a minimal projection is type I: the only nonzero central projection of a factor is `1` (`central_projection_eq`), and it dominates the minimal projection, which is abelian and nonzero. -/ -lemma IsFactor.isTypeI_of_exists_isMinimalProjection [Nontrivial H] {N : VonNeumannAlgebra H} +lemma IsFactor.isTypeI_of_exists_isMinimalProjection {N : VonNeumannAlgebra H} (hN : IsFactor N) (h : ∃ e : H →L[ℂ] H, IsMinimalProjection N e) : IsTypeI N := by obtain ⟨e, he⟩ := h + haveI : Nontrivial H := he.nontrivial intro z hz hz0 rcases hN.central_projection_eq hz with h0 | h1 · exact absurd h0 hz0 @@ -114,12 +128,13 @@ The proof avoids corner-commutant theory and polar decomposition: if `0 ≠ q `IsFactor.exists_mul_ne` produces `a ∈ N` with `z := r a q ≠ 0`. Both `z` and `z⋆` are corner elements of `p`, so they commute by abelianness; but `q z = 0` and `q z⋆ = z⋆` force `z⋆ z = q (z z⋆) = (q z) z⋆ = 0`, and the C⋆-identity gives `z = 0` — a contradiction. -/ -theorem IsFactor.subprojection_eq_of_isAbelianProjection [Nontrivial H] {N : VonNeumannAlgebra H} +theorem IsFactor.subprojection_eq_of_isAbelianProjection {N : VonNeumannAlgebra H} (hN : IsFactor N) {p : H →L[ℂ] H} (hp : IsAbelianProjection N p) {q : H →L[ℂ] H} (hq : IsStarProjection q) (hqN : q ∈ N) (hsub : p * q = q) : q = 0 ∨ q = p := by by_cases hq0 : q = 0 · exact Or.inl hq0 + haveI : Nontrivial H := nontrivial_of_ne_zero hq0 by_cases hqp : q = p · exact Or.inr hqp exfalso @@ -574,7 +589,7 @@ theorem isMinimalProjection_of_forall_subprojection {N : VonNeumannAlgebra H} /-- **In a factor, a nonzero abelian projection is minimal**: it is order-minimal (`subprojection_eq_of_isAbelianProjection`), and order-minimality forces the trivial corner (`isMinimalProjection_of_forall_subprojection`). -/ -theorem IsFactor.isMinimalProjection_of_isAbelianProjection [Nontrivial H] +theorem IsFactor.isMinimalProjection_of_isAbelianProjection {N : VonNeumannAlgebra H} (hN : IsFactor N) {p : H →L[ℂ] H} (hp : IsAbelianProjection N p) (hp0 : p ≠ 0) : IsMinimalProjection N p := isMinimalProjection_of_forall_subprojection hp.1 hp.2.1 hp0 fun _ hq hqN hsub => @@ -582,8 +597,10 @@ theorem IsFactor.isMinimalProjection_of_isAbelianProjection [Nontrivial H] /-- **The abelian-projection characterisation of type I coincides with the minimal-projection one on factors**: a factor is type I iff it has a minimal projection. Nontriviality of `H` is -essential in both directions (on a subsingleton `H` the type I condition is vacuous while no -nonzero projection exists). -/ +essential for the forward direction only: on a subsingleton `H` the type I condition is vacuously +satisfied while no nonzero projection exists, so `IsTypeI N` cannot produce one. The converse +carries no such hypothesis (`isTypeI_of_exists_isMinimalProjection`) — the minimal projection it +is handed is nonzero and so supplies the nontriviality itself. -/ theorem IsFactor.isTypeI_iff_exists_isMinimalProjection [Nontrivial H] {N : VonNeumannAlgebra H} (hN : IsFactor N) : IsTypeI N ↔ ∃ e : H →L[ℂ] H, IsMinimalProjection N e := by constructor @@ -599,7 +616,9 @@ theorem IsFactor.isTypeI_iff_exists_isMinimalProjection [Nontrivial H] {N : VonN · exact hN.isTypeI_of_exists_isMinimalProjection /-- The factor-specialised definition `IsTypeIFactor` agrees with the conjunction of the general -abelian-projection type I property and factor-ness. -/ +abelian-projection type I property and factor-ness. `[Nontrivial H]` is load-bearing here, not +decoration: on a subsingleton `H` *every* von Neumann algebra satisfies `IsFactor N ∧ IsTypeI N` +while *none* satisfies `IsTypeIFactor N`, since a minimal projection must be nonzero. -/ theorem isTypeIFactor_iff_isFactor_and_isTypeI [Nontrivial H] {N : VonNeumannAlgebra H} : IsTypeIFactor N ↔ IsFactor N ∧ IsTypeI N := by constructor @@ -652,7 +671,7 @@ lemma IsTypeIInfinite.isTypeIFactor {N : VonNeumannAlgebra H} (hN : IsTypeIInfin A type I factor is `⋆`-isomorphic to `B(K)` for some Hilbert space `K`. The spatial content — the implementing unitary and the multiplicity model `K = ℓ²(F)` — is -`IsFactor.exists_spatial_tensorDecomposition` in `Algebra.VonNeumannAlgebra.StructureTheorem`; +`IsFactor.exists_spatial_tensor_decomposition` in `Algebra.VonNeumannAlgebra.StructureTheorem`; here it is packaged as an abstract `⋆`-isomorphism. -/ universe u @@ -663,7 +682,7 @@ bounded operators on *some* complex Hilbert space `K`. This is the model-indepen classification of type I factors: `B(K)` for `K = ℓ²(F)` is exactly the type `I_{|F|}` factor, and `K = H` recovers the full algebra `B(H)` as the type `I` factor `𝓑(H)`. The spatial content — that the isomorphism is implemented by a unitary and that `K` is the multiplicity space of the minimal -projection — is `IsFactor.exists_spatial_tensorDecomposition`; here it is packaged as an abstract +projection — is `IsFactor.exists_spatial_tensor_decomposition`; here it is packaged as an abstract `⋆`-isomorphism, hiding the specific model `K = ℓ²(F)` behind an existential. -/ theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] {N : VonNeumannAlgebra H} @@ -671,7 +690,7 @@ theorem IsTypeIFactor.exists_starAlgEquiv {H : Type u} [NormedAddCommGroup H] ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), Nonempty (N ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by obtain ⟨hFactor, e, he⟩ := hN - obtain ⟨F, U, hU, -⟩ := hFactor.exists_spatial_tensorDecomposition he + obtain ⟨F, U, hU, -⟩ := hFactor.exists_spatial_tensor_decomposition he haveI : CompleteSpace (LinearMap.range (e : H →ₗ[ℂ] H)) := he.1.completeSpace_range haveI : Nontrivial (LinearMap.range (e : H →ₗ[ℂ] H)) := by rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] @@ -727,50 +746,53 @@ theorem isTypeIFactor_boundedLinearOperators [Nontrivial H] : IsTypeIFactor 𝓑(H) := ⟨isFactor_boundedLinearOperators, exists_isMinimalProjection_boundedLinearOperators⟩ -/-- **`B(H)` is `⋆`-isomorphic to `B(K)`** for some complex Hilbert space `K`. This applies the -abstract type I factor structure theorem `IsTypeIFactor.exists_starAlgEquiv` to the full algebra; -`K` is `ℓ²` of an orthonormal basis of `H`. -/ +/-- **`B(H) ≃⋆ₐ B(ℓ²(ι))` with `H ≃ₗᵢ ℓ²(ι)`.** The full algebra is `⋆`-isomorphic to the bounded +operators on `ℓ²(ι)` for an index set `ι` — the index set of a Hilbert basis of `H` — and the +isomorphism is implemented by the corresponding isometry `H ≃ₗᵢ ℓ²(ι)`, which is returned +alongside it. + +The `ℓ²` model is stated rather than hidden behind an unconstrained `∃ K`. With `K` unconstrained +the statement would be discharged by `K := H` and `boundedLinearOperators.starAlgEquiv`, +carrying none of the classification content: the content is exactly that `K` may be taken of the +form `ℓ²(ι)`, which is what `IsTypeIFactor.exists_starAlgEquiv` hides behind its existential and +what the type `I_{|ι|}` reading of `B(H)` needs. Nonzeroness of `H` is not required: for `H = 0` +the Hilbert basis is empty and both sides are trivial. -/ theorem exists_starAlgEquiv_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] - [InnerProductSpace ℂ H] [CompleteSpace H] [Nontrivial H] : - ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), - Nonempty (𝓑(H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := - isTypeIFactor_boundedLinearOperators.exists_starAlgEquiv - -/-- **`B(H) ≃⋆ₐ B(K)` with `K` infinite-dimensional, when `H` is infinite-dimensional.** The full -algebra is `⋆`-isomorphic to `B(K)` for a complex Hilbert space `K` that is itself -infinite-dimensional. Here `K = ℓ²(F)` for `F` an orthonormal basis of `H`; a finite `F` would, -through the spatial decomposition `H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` with one-dimensional multiplicity `eH` (the -range of the rank-one minimal projection), force `H` finite-dimensional. Expressing type I_∞ as -`¬FiniteDimensional ℂ K` is the standard reading: a type I_n factor is `B(K)` with `dim K = n`, so -I_∞ is exactly the infinite-dimensional `K`. -/ + [InnerProductSpace ℂ H] [CompleteSpace H] : + ∃ ι : Type u, Nonempty (H ≃ₗᵢ[ℂ] lp (fun _ : ι => ℂ) 2) ∧ + Nonempty ((𝓑(H) : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] + (lp (fun _ : ι => ℂ) 2 →L[ℂ] lp (fun _ : ι => ℂ) 2)) := by + obtain ⟨w, b, -⟩ := exists_hilbertBasis ℂ H + exact ⟨w, ⟨b.repr⟩, ⟨boundedLinearOperators.starAlgEquiv.trans b.repr.conjStarAlgEquiv⟩⟩ + +/-- **`B(H) ≃⋆ₐ B(ℓ²(ι))` with `ι` infinite, when `H` is infinite-dimensional.** The full algebra +is `⋆`-isomorphic to the bounded operators on `ℓ²(ι)` for an *infinite* index set `ι`, with the +implementing isometry `H ≃ₗᵢ ℓ²(ι)` returned alongside; in particular `ℓ²(ι)` is itself +infinite-dimensional. Expressing type I_∞ this way is the standard reading: a type I_n factor is +`B(K)` with `dim K = n`, so I_∞ is exactly the infinite index set. + +As in `exists_starAlgEquiv_boundedLinearOperators`, the `ℓ²` model is part of the statement: an +unconstrained `∃ K` with `¬FiniteDimensional ℂ K` would be discharged by `K := H`. -/ theorem exists_starAlgEquiv_infiniteDimensional_boundedLinearOperators {H : Type u} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] (hinf : ¬FiniteDimensional ℂ H) : - ∃ (K : Type u) (_ : NormedAddCommGroup K) (_ : InnerProductSpace ℂ K) (_ : CompleteSpace K), - ¬FiniteDimensional ℂ K ∧ - Nonempty (𝓑(H) ≃⋆ₐ[ℂ] (K →L[ℂ] K)) := by - haveI : Nontrivial H := by - rcases subsingleton_or_nontrivial H with h | h - · haveI := h - exact absurd (inferInstance : FiniteDimensional ℂ H) hinf - · exact h - obtain ⟨u, hu⟩ := exists_unit_vector (H := H) - have he : IsMinimalProjection 𝓑(H) (rankOne ℂ u u) := - isMinimalProjection_rankOne_boundedLinearOperators hu - obtain ⟨F, U, hU, -⟩ := isFactor_boundedLinearOperators.exists_spatial_tensorDecomposition he - haveI : CompleteSpace (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := - he.1.completeSpace_range - haveI hfd : FiniteDimensional ℂ (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := - finiteDimensional_range_rankOne u - haveI : Nontrivial (LinearMap.range ((rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H)) := by - rw [Submodule.nontrivial_iff_ne_bot, ne_eq, LinearMap.range_eq_bot] - exact fun h => he.2.2.1 (ContinuousLinearMap.coe_injective - (h.trans ContinuousLinearMap.coe_zero.symm)) - refine ⟨lp (fun _ : F => ℂ) 2, inferInstance, inferInstance, inferInstance, ?_, - ⟨(conjEquiv U 𝓑(H)).trans ((equivOfEq hU).trans HilbertTensor.amplifyLeftStarAlgEquiv.symm)⟩⟩ - intro hK - haveI := hK - exact hinf U.symm.toLinearEquiv.finiteDimensional + ∃ ι : Type u, Infinite ι ∧ ¬FiniteDimensional ℂ (lp (fun _ : ι => ℂ) 2) ∧ + Nonempty (H ≃ₗᵢ[ℂ] lp (fun _ : ι => ℂ) 2) ∧ + Nonempty ((𝓑(H) : VonNeumannAlgebra H) ≃⋆ₐ[ℂ] + (lp (fun _ : ι => ℂ) 2 →L[ℂ] lp (fun _ : ι => ℂ) 2)) := by + obtain ⟨w, b, -⟩ := exists_hilbertBasis ℂ H + have hwinf : Infinite w := by + rw [← not_finite_iff_infinite] + intro hfin + haveI : Finite w := hfin + haveI : Fintype w := Fintype.ofFinite w + exact hinf b.toOrthonormalBasis.toBasis.finiteDimensional_of_finite + have hnfd : ¬FiniteDimensional ℂ (lp (fun _ : w => ℂ) 2) := by + intro hK + haveI := hK + exact hinf b.repr.symm.toLinearEquiv.finiteDimensional + exact ⟨w, hwinf, hnfd, ⟨b.repr⟩, + ⟨boundedLinearOperators.starAlgEquiv.trans b.repr.conjStarAlgEquiv⟩⟩ /-- **`B(H)` is a type I_∞ factor when `H` is infinite-dimensional.** Packaged as the intrinsic predicate `IsTypeIInfinite`: `𝓑(H) = B(H)` is a type I factor (`isTypeIFactor_boundedLinearOperators`) From 74da9e1029acde5d42b44aec877c9607dca8ea8b Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:43:23 +0000 Subject: [PATCH 097/113] feat: add split inclusion of von Neumann algebras MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IsSplitInclusion (an interpolating type I factor), monotonicity/sandwich/self constructors, and the spatial tensor decomposition of a split inclusion and its commutant (exists_tensor_decomposition). Also adds a minimal negative witness, the diagonal algebra on EuclideanSpace ℂ (Fin 2), whose identity inclusion is not split. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../VonNeumannAlgebra/SplitInclusion.lean | 152 ++++++++++++++++-- 1 file changed, 138 insertions(+), 14 deletions(-) diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean index 11f819c..61bca10 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean @@ -1,6 +1,8 @@ module public import QuantumSystem.Algebra.VonNeumannAlgebra.TypeI +public import Mathlib.Analysis.InnerProductSpace.Adjoint +public import Mathlib.Analysis.InnerProductSpace.PiL2 /-! # Split inclusions of von Neumann algebras @@ -15,8 +17,8 @@ across a commuting pair. The AQFT *split property* — this predicate applied to level in `QuantumSystem.Algebra.LocalNet.SplitProperty`. The structural content of a split inclusion is the tensor decomposition -`IsSplitInclusion.exists_tensorDecomposition`: a spatial isomorphism `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` -carrying `A` into the tensor factor `B(ℓ²(F)) ⊗̄ 1` and the commutant `B′` into `1 ⊗̄ B(eH)`. It +`IsSplitInclusion.exists_tensor_decomposition`: a spatial isomorphism `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` +carrying `A` into the tensor factor `𝓑(ℓ²(F)) ⊗̄ 1` and the commutant `B′` into `1 ⊗̄ 𝓑(eH)`. It is inherited from the type I structure theorem (`QuantumSystem.Algebra.VonNeumannAlgebra.StructureTheorem`). @@ -25,8 +27,23 @@ is inherited from the type I structure theorem * `VonNeumannAlgebra.IsSplitInclusion A B` — some type I factor `M` satisfies `A ≤ M ≤ B`. * `VonNeumannAlgebra.IsSplitInclusion.le` / `mono` — a split inclusion is an inclusion, and splitness survives shrinking `A` and enlarging `B`. -* `VonNeumannAlgebra.IsSplitInclusion.exists_tensorDecomposition` — the split tensor +* `VonNeumannAlgebra.IsTypeIFactor.isSplitInclusion_of_le_of_le` — any inclusion sandwiching a + type I factor is split. +* `VonNeumannAlgebra.isSplitInclusion_self_iff` — the identity inclusion `M ≤ M` is split exactly + when `M` is a type I factor; the two directions are + `IsTypeIFactor.isSplitInclusion_self` and `IsSplitInclusion.isTypeIFactor_of_self`. +* `VonNeumannAlgebra.IsSplitInclusion.exists_tensor_decomposition` — the split tensor decomposition of the inclusion. +* `VonNeumannAlgebra.diagonalAlgebra` and `VonNeumannAlgebra.not_isSplitInclusion_diagonalAlgebra` + — the negative control: the diagonal algebra `ℂ ⊕ ℂ` on `ℂ²` is not a factor + (`not_isFactor_diagonalAlgebra`), so its identity inclusion is *not* split. This is what keeps + the predicate distinguishable from plain inclusion. + +## Notation + +`⊗̄` in the prose above is documentation shorthand for the von Neumann (spatial) tensor product of +algebras; that convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, +where the algebras it names (`HilbertTensor.vnTensorLeft` / `vnTensorRight`) are defined. -/ @[expose] public section @@ -59,31 +76,138 @@ lemma IsTypeIFactor.isSplitInclusion_of_le_of_le {M A B : VonNeumannAlgebra H} (hM : IsTypeIFactor M) (h₁ : A ≤ M) (h₂ : M ≤ B) : IsSplitInclusion A B := ⟨M, hM, h₁, h₂⟩ -/-- A type I factor splits in itself: `IsSplitInclusion M M`. Consequently the reflexive -instances of the AQFT split property (`O₁ = O₂`) require the local algebras themselves to be -type I factors. -/ +/-- A type I factor splits in itself: `IsSplitInclusion M M`. -/ lemma IsTypeIFactor.isSplitInclusion_self {M : VonNeumannAlgebra H} (hM : IsTypeIFactor M) : IsSplitInclusion M M := hM.isSplitInclusion_of_le_of_le le_rfl le_rfl +/-- **The identity inclusion splits only for type I factors.** An interpolating factor squeezed +between `M` and itself *is* `M`, by antisymmetry. This is why a reflexive proper-containment +relation would make the AQFT split property demand type I local algebras — the reason +`ProperContainment` is axiomatised to be irreflexive. -/ +lemma IsSplitInclusion.isTypeIFactor_of_self {M : VonNeumannAlgebra H} + (h : IsSplitInclusion M M) : IsTypeIFactor M := + let ⟨_, hN, h₁, h₂⟩ := h + le_antisymm h₂ h₁ ▸ hN + +/-- The identity inclusion `M ≤ M` is split exactly when `M` is a type I factor. -/ +lemma isSplitInclusion_self_iff {M : VonNeumannAlgebra H} : + IsSplitInclusion M M ↔ IsTypeIFactor M := + ⟨IsSplitInclusion.isTypeIFactor_of_self, IsTypeIFactor.isSplitInclusion_self⟩ + /-- **Split tensor decomposition.** A split inclusion `A ≤ M ≤ B` is spatially tensor-split: there is a linear isometric equivalence `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` (with `e` a minimal projection of the interpolating type I factor `M`) under which `M` becomes exactly the tensor factor -`B(ℓ²(F)) ⊗̄ 1` and `M′` the factor `1 ⊗̄ B(eH)`, so that `A` lands in the left factor and the +`𝓑(ℓ²(F)) ⊗̄ 1` and `M′` the factor `1 ⊗̄ 𝓑(eH)`, so that `A` lands in the left factor and the commutant `B′` in the right factor. This is the inclusion-form structural consequence of the split property (Doplicher–Longo; Buchholz), inherited from -`IsFactor.exists_split_tensorDecomposition`. -/ -theorem IsSplitInclusion.exists_tensorDecomposition {A B : VonNeumannAlgebra H} +`IsFactor.exists_split_tensor_decomposition`. + +The interpolating factor is returned with its full type I factoriality and its minimal projection, +and the index set `F` with its nonemptiness, so that a consumer needs no reconstruction. -/ +theorem IsSplitInclusion.exists_tensor_decomposition {A B : VonNeumannAlgebra H} (h : IsSplitInclusion A B) : ∃ (M : VonNeumannAlgebra H) (e : H →L[ℂ] H) (F : Set (H →L[ℂ] H)) - (U : H ≃ₗᵢ[ℂ] HilbertTensor (lp (fun _ : F => ℂ) 2) (LinearMap.range (e : H →ₗ[ℂ] H))), - IsMinimalProjection M e ∧ A ≤ M ∧ M ≤ B ∧ + (U : H ≃ₗᵢ[ℂ] lp (fun _ : F => ℂ) 2 ⊗̂ LinearMap.range (e : H →ₗ[ℂ] H)), + IsTypeIFactor M ∧ IsMinimalProjection M e ∧ Nonempty F ∧ A ≤ M ∧ M ≤ B ∧ VonNeumannAlgebra.conj U M = vnTensorLeft ∧ VonNeumannAlgebra.conj U M′ = vnTensorRight ∧ VonNeumannAlgebra.conj U A ≤ vnTensorLeft ∧ VonNeumannAlgebra.conj U B′ ≤ vnTensorRight := by - obtain ⟨M, ⟨hMf, e, he⟩, h₁, h₂⟩ := h - obtain ⟨F, U, hM, hM', hA, hB⟩ := hMf.exists_split_tensorDecomposition he h₁ h₂ - exact ⟨M, e, F, U, he, h₁, h₂, hM, hM', hA, hB⟩ + obtain ⟨M, hMt, h₁, h₂⟩ := h + obtain ⟨hMf, e, he⟩ := hMt + obtain ⟨F, U, hF, hM, hM', hA, hB⟩ := hMf.exists_split_tensor_decomposition he h₁ h₂ + exact ⟨M, e, F, U, ⟨hMf, e, he⟩, he, hF, h₁, h₂, hM, hM', hA, hB⟩ + +/-! ### A non-split inclusion: the diagonal algebra on `ℂ²` + +The negative control for `IsSplitInclusion`. Everything above inhabits the *positive* side of the +predicate; this section keeps the negations of `IsFactor`, `IsTypeIFactor` and `IsSplitInclusion` +inhabited, realizing the minimal non-split witness `ℂ⊕ℂ ⊆ ℂ⊕ℂ` of the extraction note +`docs/math/split-inclusion.md` (degeneracy table: a commutative algebra is split in itself only +when it is `ℂ·1`). Without it nothing built in this repository would distinguish `IsSplitInclusion` +from plain inclusion, nor `IsFactor` from `True`. + +It lives here, next to the predicate it refutes, rather than among the local-net witnesses: it +mentions no net, no index set and no representation. +-/ + +section Diagonal + +open InnerProductSpace + +/-- The rank-one projection `|e₀⟩⟨e₀|` onto the first coordinate of `ℂ²`: self-adjoint +(`star_diagonalProjection`) and not a scalar (`diagonalProjection_ne_smul_one`), it generates +the diagonal algebra below and witnesses its nontrivial centre. -/ +noncomputable def diagonalProjection : + EuclideanSpace ℂ (Fin 2) →L[ℂ] EuclideanSpace ℂ (Fin 2) := + rankOne ℂ (EuclideanSpace.single 0 1) (EuclideanSpace.single 0 1) + +/-- The **diagonal algebra** `ℂ ⊕ ℂ` on `ℂ²`: the commutant of the rank-one projection onto the +first coordinate — concretely, the operators diagonal in the standard basis. The smallest +von Neumann algebra in the repository that is a counterexample rather than a witness. -/ +noncomputable def diagonalAlgebra : VonNeumannAlgebra (EuclideanSpace ℂ (Fin 2)) := + commutantSet {diagonalProjection} + +/-- The rank-one projection onto a coordinate is self-adjoint. -/ +lemma star_diagonalProjection : star diagonalProjection = diagonalProjection := by + rw [diagonalProjection, ContinuousLinearMap.star_eq_adjoint, adjoint_rankOne] + +/-- The generating projection acts as `v ↦ v₀ • e₀`. -/ +lemma diagonalProjection_apply (v : EuclideanSpace ℂ (Fin 2)) : + diagonalProjection v = v 0 • EuclideanSpace.single 0 1 := by + rw [diagonalProjection, rankOne_apply, EuclideanSpace.inner_single_left, map_one, one_mul] + +/-- The generating projection lies in the diagonal algebra: it commutes with itself and, being +self-adjoint, with its own adjoint. -/ +lemma diagonalProjection_mem : diagonalProjection ∈ diagonalAlgebra := by + rw [diagonalAlgebra, mem_commutantSet_iff] + rintro g rfl + exact ⟨rfl, by rw [star_diagonalProjection]⟩ + +/-- The generating projection lies in the commutant of the diagonal algebra: every member of the +commutant of `{diagonalProjection}` commutes with it by definition. -/ +lemma diagonalProjection_mem_commutant : diagonalProjection ∈ diagonalAlgebra.commutant := by + rw [mem_commutant_iff] + intro g hg + rw [diagonalAlgebra, mem_commutantSet_iff] at hg + exact (hg diagonalProjection rfl).1.symm + +/-- The generating projection is not a scalar: it fixes `e₀` and kills `e₁`, so `c • 1` would +force `c = 1` and `c = 0` at once. This is the nontrivial centre of the diagonal algebra. -/ +lemma diagonalProjection_ne_smul_one (c : ℂ) : diagonalProjection ≠ c • 1 := by + intro h + have h0 : diagonalProjection (EuclideanSpace.single 0 1) 0 = c := by + rw [h] + simp + have h1 : diagonalProjection (EuclideanSpace.single 1 1) 1 = c := by + rw [h] + simp + rw [diagonalProjection_apply] at h0 h1 + simp at h0 h1 + exact one_ne_zero (h0.trans h1.symm) + +/-- **The diagonal algebra is not a factor**: its generating projection lies in its centre and is +not a scalar. The first refuted `IsFactor` in the repository — without it nothing built here +distinguishes `IsFactor` from `True`. -/ +theorem not_isFactor_diagonalAlgebra : ¬ IsFactor diagonalAlgebra := fun h => + let ⟨c, hc⟩ := h diagonalProjection diagonalProjection_mem diagonalProjection_mem_commutant + diagonalProjection_ne_smul_one c hc + +/-- The diagonal algebra is not a type I factor, not being a factor at all. -/ +theorem not_isTypeIFactor_diagonalAlgebra : ¬ IsTypeIFactor diagonalAlgebra := fun h => + not_isFactor_diagonalAlgebra h.1 + +/-- **A non-split inclusion** — the extraction note's minimal witness `ℂ⊕ℂ ⊆ ℂ⊕ℂ`: the identity +inclusion of the diagonal algebra on `ℂ²` is not split. An interpolating type I factor squeezed +between `diagonalAlgebra` and itself would *be* `diagonalAlgebra` +(`IsSplitInclusion.isTypeIFactor_of_self`), which is not a factor. This keeps the negation of +`IsSplitInclusion` inhabited: without it nothing built in the repository distinguishes the +predicate from plain inclusion. -/ +theorem not_isSplitInclusion_diagonalAlgebra : + ¬ IsSplitInclusion diagonalAlgebra diagonalAlgebra := fun h => + not_isTypeIFactor_diagonalAlgebra h.isTypeIFactor_of_self + +end Diagonal end VonNeumannAlgebra From bb05693e59b99ed3418235a1948ee81e916a9f59 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:43:33 +0000 Subject: [PATCH 098/113] feat: add causal index sets for local nets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CausalOrthogonality/OrthogonalHat/CausalIndexSet formalize the abstract causal-disjointness axioms (symmetry, heredity, every region has a ⊥-partner) without assuming directedness. LocalNet and its Faithful/ Covariance classes, and the quasi-local C*-algebra construction, are restated over an arbitrary CausalIndexSet instead of a fixed geometric model. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../Algebra/LocalNet/Covariance.lean | 137 +++++++-- QuantumSystem/Algebra/LocalNet/Net.lean | 267 ++++++++++++++++-- .../Algebra/LocalNet/QuasiLocalAlgebra.lean | 250 +++++++++------- 3 files changed, 525 insertions(+), 129 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/Covariance.lean b/QuantumSystem/Algebra/LocalNet/Covariance.lean index 41f3e45..485504a 100644 --- a/QuantumSystem/Algebra/LocalNet/Covariance.lean +++ b/QuantumSystem/Algebra/LocalNet/Covariance.lean @@ -1,6 +1,7 @@ module public import QuantumSystem.Algebra.LocalNet.Net +public import Mathlib.Data.Finset.Grade /-! # Covariance data for a local net @@ -9,19 +10,28 @@ A **covariance** of a local net over a causal index set `K` is an order automorp of the regions preserving causal orthogonality, together with, for every region `O`, a `*`-isomorphism `β_O : 𝔄(O) ≃⋆ₐ[ℂ] 𝔄(σO)` of local algebras that is natural with respect to the isotony embeddings. The naturality field `β_incl` is the AQFT covariance axiom -`β(𝔄(O)) = 𝔄(σO)` compatibly with inclusions (Naaijkens 2012 §3.2, Verch 2025 §1.2). These +`β(𝔄(O)) = 𝔄(σO)` compatibly with inclusions (Naaijkens, *Anyons in Infinite Quantum Systems*, +2012, §3.2; Verch, *Lecture Notes on Operator Algebras and Quantum Field Theory*, +arXiv:2507.00900, 2025, §1.2). These covariances form a `Group` under composition (`Covariance.id`, `Covariance.comp`, `Covariance.inv`). For lattice nets (`K = Finset sites`) a covariance is induced by a site -permutation via `Covariance.ofSitePerm` — and every covariance of a lattice net arises this way, -since an order automorphism of `Finset sites` is determined by its action on singletons. +permutation via `Covariance.ofSitePerm`, and conversely every covariance of a lattice net arises +this way (`Covariance.exists_eq_ofSitePerm`), since an order automorphism of `Finset sites` maps +atoms to atoms and the atoms are the singletons. This file isolates the abstract covariance *data* and its group structure. Its *action* on the quasi-local algebra — assembling the per-region `*`-isomorphisms into a `*`-automorphism -`quasiLocalCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local +`localObservableCovariance` and (for a `Faithful` net) its continuous extension to the quasi-local C⋆-algebra — is built in `LocalNet.QuasiLocalAlgebra`. A symmetry group `G` acts on the net by supplying a group homomorphism `G →* N.Covariance` (whose `σ`-component is the geometric action -`G → K ≃o K`); composing it with `quasiLocalCovarianceHom` — or, for a `Faithful` net, +`G → K ≃o K`); composing it with `localObservableCovarianceHom` — or, for a `Faithful` net, `quasiLocalCStarCovarianceHom` — yields the automorphic action of `G` on the (quasi-local) algebra. + +## Notation + +`𝔄(O)` and `𝓡(O)` in the prose above are documentation shorthand for the local C⋆-algebra +`N.algebra O` and the local von Neumann algebra `N.localVonNeumannAlgebra R O`; the convention — +and why neither is a Lean notation — is stated in full in `QuantumSystem.Algebra.LocalNet.Net`. -/ @[expose] public section @@ -30,7 +40,7 @@ namespace LocalNet open scoped CausalOrthogonality -variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] (N : LocalNet K) +variable {K : Type*} [Preorder K] [CausalOrthogonality K] (N : LocalNet K) /-! ### Covariances of the net @@ -62,14 +72,11 @@ namespace Covariance variable {N} (a : N.Covariance) -/-- The image `σO` of a region under the covariance. -/ -def region (O : K) : K := a.σ O - /-- **Extensionality** for covariances: two covariances with the same region automorphism and the same local `*`-isomorphisms (compared along the induced region equality) are equal. The remaining fields are propositions, hence irrelevant. -/ @[ext (iff := false)] lemma ext {s t : N.Covariance} (hσ : s.σ = t.σ) - (hβ : ∀ (O : K) (x : N.algebra O) (e : s.region O = t.region O), + (hβ : ∀ (O : K) (x : N.algebra O) (e : s.σ O = t.σ O), N.algebraCongr e (s.β O x) = t.β O x) : s = t := by revert hσ hβ obtain ⟨sσ, -, sβ, -⟩ := s @@ -127,46 +134,57 @@ def inv (a : N.Covariance) : N.Covariance where simp only [StarAlgEquiv.trans_apply] rw [N.incl_algebraCongr _ _ h (a.σ.monotone (a.σ.symm.monotone h)), a.β_symm_incl] +/-- The identity covariance acts as the identity on every local algebra. -/ @[simp] lemma id_β_apply (O : K) (x : N.algebra O) : (Covariance.id N).β O x = x := rfl +/-- The composite covariance acts by composing the local `*`-isomorphisms along the region maps. -/ @[simp] lemma comp_β_apply (a b : N.Covariance) (O : K) (x : N.algebra O) : (a.comp b).β O x = a.β (b.σ O) (b.β O x) := rfl +/-- The inverse covariance acts by the inverse local `*`-isomorphism, after transporting the + argument along the region equality `σ(σ⁻¹O) = O`. -/ @[simp] lemma inv_β_apply (a : N.Covariance) (O : K) (x : N.algebra O) : (Covariance.inv a).β O x = (a.β (a.σ.symm O)).symm (N.algebraCongr (a.σ.apply_symm_apply O).symm x) := rfl -@[simp] lemma region_id (O : K) : (Covariance.id N).region O = O := +/-- The identity covariance fixes every region. -/ +@[simp] lemma id_σ_apply (O : K) : (Covariance.id N).σ O = O := rfl -@[simp] lemma region_comp (a b : N.Covariance) (O : K) : - (a.comp b).region O = a.region (b.region O) := +/-- Composing covariances composes their region maps. -/ +@[simp] lemma comp_σ_apply (a b : N.Covariance) (O : K) : + (a.comp b).σ O = a.σ (b.σ O) := rfl +/-- The identity covariance is a left unit for composition. -/ lemma id_comp (a : N.Covariance) : (Covariance.id N).comp a = a := by refine Covariance.ext ?_ fun O x e => ?_ · exact OrderIso.ext rfl · exact N.algebraCongr_self e _ +/-- The identity covariance is a right unit for composition. -/ lemma comp_id (a : N.Covariance) : a.comp (Covariance.id N) = a := by refine Covariance.ext ?_ fun O x e => ?_ · exact OrderIso.ext rfl · exact N.algebraCongr_self e _ +/-- Composition of covariances is associative. -/ lemma comp_assoc (a b c : N.Covariance) : (a.comp b).comp c = a.comp (b.comp c) := by refine Covariance.ext ?_ fun O x e => ?_ · exact OrderIso.ext rfl · exact N.algebraCongr_self e _ +/-- The inverse covariance is a left inverse for composition; together with the three laws above + this is what makes the covariances a group. -/ lemma inv_comp (a : N.Covariance) : (Covariance.inv a).comp a = Covariance.id N := by refine Covariance.ext ?_ fun O x e => ?_ · exact OrderIso.ext (funext fun O => a.σ.symm_apply_apply O) · rw [algebraCongr_eq_iff] simp only [comp_β_apply, inv_β_apply, id_β_apply] - erw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply] + rw [← a.β_algebraCongr, StarAlgEquiv.symm_apply_apply] rfl /-- The covariances of a local net form a **group** under composition, with `Covariance.id` the @@ -193,9 +211,11 @@ lemma inv_def (a : N.Covariance) : a⁻¹ = a.inv := rfl /-- Build a covariance of a lattice net (`K = Finset sites`) from a **site permutation**: the induced region automorphism is `Λ ↦ Λ.map σ`, which preserves disjointness. This recovers the - site-permutation covariances of spin-system nets (Naaijkens 2012 §3.2); conversely, every - covariance of a lattice net arises this way, since an order automorphism of `Finset sites` - preserves atoms (singletons) and is therefore induced by a permutation of the sites. -/ + site-permutation covariances of spin-system nets (Naaijkens, *Anyons in Infinite Quantum + Systems*, 2012, §3.2). Conversely every + covariance of a lattice net arises this way — that is `exists_eq_ofSitePerm`, proved below via + the fact that an order automorphism of `Finset sites` preserves atoms (singletons) and is + therefore induced by a permutation of the sites. -/ def ofSitePerm {sites : Type*} {N : LocalNet (Finset sites)} (σ : sites ≃ sites) (β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding)) (β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), @@ -206,6 +226,89 @@ def ofSitePerm {sites : Type*} {N : LocalNet (Finset sites)} (σ : sites ≃ sit β := β β_incl h x := β_incl h x +/-! #### Every lattice covariance comes from a site permutation + +An order automorphism of `Finset sites` maps atoms to atoms, and the atoms of `Finset sites` are +exactly the singletons; so it is determined by a permutation of the sites, and the covariance it +belongs to is `ofSitePerm` of that permutation. +-/ + +/-- The image of a singleton region under an order automorphism is again a singleton: order + isomorphisms preserve atoms (`OrderIso.isAtom_iff`), and the atoms of `Finset sites` are the + singletons (`Finset.isAtom_iff`). -/ +lemma exists_singleton_image {sites : Type*} (e : Finset sites ≃o Finset sites) (x : sites) : + ∃ y, e {x} = {y} := + Finset.isAtom_iff.1 ((e.isAtom_iff _).2 (Finset.isAtom_singleton x)) + +open Classical in +/-- The site that an order automorphism of lattice regions sends `x` to. -/ +noncomputable def sitePermFun {sites : Type*} (e : Finset sites ≃o Finset sites) (x : sites) : + sites := + (exists_singleton_image e x).choose + +/-- Defining property of `sitePermFun`: `e {x} = {sitePermFun e x}`. -/ +lemma sitePermFun_spec {sites : Type*} (e : Finset sites ≃o Finset sites) (x : sites) : + e {x} = {sitePermFun e x} := (exists_singleton_image e x).choose_spec + +/-- **The site permutation underlying an order automorphism of lattice regions.** Its inverse is + the site map of the inverse automorphism, the two being mutually inverse because `e.symm` undoes + `e` on singletons. -/ +noncomputable def sitePerm {sites : Type*} (e : Finset sites ≃o Finset sites) : sites ≃ sites where + toFun := sitePermFun e + invFun := sitePermFun e.symm + left_inv x := by + have h2 := sitePermFun_spec e.symm (sitePermFun e x) + rw [← sitePermFun_spec e x, e.symm_apply_apply] at h2 + exact (Finset.singleton_inj.1 h2).symm + right_inv y := by + have h2 := sitePermFun_spec e (sitePermFun e.symm y) + rw [← sitePermFun_spec e.symm y, e.apply_symm_apply] at h2 + exact (Finset.singleton_inj.1 h2).symm + +/-- **An order automorphism of lattice regions is the image map of its site permutation.** + Membership in `e Λ` is tested one site at a time: `y ∈ e Λ` iff `{y} ≤ e Λ` iff + `e.symm {y} ≤ Λ` iff `sitePerm e ⁻¹ y ∈ Λ`. -/ +lemma map_sitePerm {sites : Type*} (e : Finset sites ≃o Finset sites) (Λ : Finset sites) : + e Λ = Λ.map (sitePerm e).toEmbedding := by + ext y + rw [Finset.mem_map] + have key : y ∈ e Λ ↔ sitePermFun e.symm y ∈ Λ := by + rw [← Finset.singleton_subset_iff, ← Finset.singleton_subset_iff, + ← sitePermFun_spec e.symm y] + exact (e.symm_apply_le).symm + rw [key] + constructor + · intro h + exact ⟨sitePermFun e.symm y, h, (sitePerm e).right_inv y⟩ + · rintro ⟨x, hx, rfl⟩ + rwa [show sitePermFun e.symm ((sitePerm e).toEmbedding x) = x from (sitePerm e).left_inv x] + +variable {sites : Type*} {N : LocalNet (Finset sites)} + +/-- **The region automorphism of a lattice covariance is induced by a site permutation.** -/ +theorem exists_sitePerm (a : N.Covariance) : + ∃ σ : sites ≃ sites, ∀ Λ : Finset sites, a.σ Λ = Λ.map σ.toEmbedding := + ⟨sitePerm a.σ, map_sitePerm a.σ⟩ + +/-- **Every covariance of a lattice net arises from a site permutation** — the converse of + `ofSitePerm`, and the statement its docstring advertises. The region automorphism is the image + map of a site permutation `σ` (`exists_sitePerm`); transporting the local `*`-isomorphisms + along that identification of regions produces the `β` data, whose naturality is `a`'s own + naturality composed with `incl_algebraCongr`. -/ +theorem exists_eq_ofSitePerm (a : N.Covariance) : + ∃ (σ : sites ≃ sites) + (β : ∀ Λ : Finset sites, N.algebra Λ ≃⋆ₐ[ℂ] N.algebra (Λ.map σ.toEmbedding)) + (β_incl : ∀ {Λ Λ' : Finset sites} (h : Λ ⊆ Λ') (x : N.algebra Λ), + β Λ' (N.incl h x) = N.incl (Finset.map_subset_map.mpr h) (β Λ x)), + a = Covariance.ofSitePerm σ β β_incl := by + obtain ⟨σ, hσ⟩ := a.exists_sitePerm + refine ⟨σ, fun Λ => (a.β Λ).trans (N.algebraCongr (hσ Λ)), ?_, ?_⟩ + · intro Λ Λ' h x + simp only [StarAlgEquiv.trans_apply] + rw [a.β_incl h] + exact N.incl_algebraCongr (hσ Λ) (hσ Λ') (a.σ.monotone h) (Finset.map_subset_map.mpr h) _ + · exact Covariance.ext (OrderIso.ext (funext hσ)) fun Λ x e => rfl + end Covariance end LocalNet diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index b6b3ad1..29f6b70 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -7,12 +7,38 @@ public import Mathlib.Order.DirectedInverseSystem # Local nets of C⋆-algebras This file contains the abstract **local net** data in Haag–Kastler form: the regions form an -abstract *causal index set* — a partially ordered set `K` (in the literature, the open bounded +abstract *causal index set* — an ordered set `K` of regions (in the literature, the open bounded regions of spacetime ordered by inclusion) equipped with a causal orthogonality relation `O₁ ⟂ O₂` (`CausalOrthogonality`, abstracting spacelike separation) — and each region is assigned a local C⋆-algebra, with functorial isotony embeddings and locality. Lattice (quantum spin system) -nets are the instance `K = Finset sites` with `⟂ = Disjoint`; nothing in this file assumes -directedness, so non-directed index sets (wedges, spacelike cones) are also in scope. +nets are the instance `K = Finset sites` with `⟂ = Disjoint`. The literature's third axiom on the +index set — every region admits a causally disjoint one — is the mixin `CausalIndexSet`, kept +separate because not every index family of the corpus satisfies it. + +The order is carried as a `Preorder` throughout, not a `PartialOrder`: the literature's index sets +are ordered by inclusion and so are partial orders, but antisymmetry is used nowhere in this +development — not by the net axioms, not by the quasi-local algebra, not by the split property — so +demanding it would restrict the interface without buying anything. A concrete index set that is a +partial order is of course still an instance. + +**Directedness, and what locality means without it.** No definition in this file assumes the index +set directed, so a non-directed `K` — the proper intervals of the circle, wedges — carries the data +of a `LocalNet` perfectly well. The *locality axiom*, however, is weaker there than its name +suggests: commutation of `𝔄(O₁)` with `𝔄(O₂)` has to be stated inside an algebra containing both, +so the axiom binds a common upper bound of the two regions and therefore constrains only the +causally orthogonal pairs that have one. That is Guido–Longo–Roberts–Verch's derived relation `⊥̂` +(`CausalOrthogonality.OrthogonalHat`), which collapses onto `⟂` whenever `K` is directed +(`CausalOrthogonality.orthogonalHat_iff`). The converse fails for a *fixed* orthogonality +relation — an empty `⟂` collapses on every preorder — and becomes true once the relation is +quantified over: directedness of `K` is equivalent to `⊥̂ = ⟂` holding for *every* +`CausalOrthogonality K` (`CausalOrthogonality.isDirectedOrder_iff_forall_orthogonalHat_iff`). +The dichotomy is spelled out at +`LocalNet.exists_locality_of_orthogonalHat` and `LocalNet.exists_locality_of_orthogonal`, and the +regions carrying the interesting statements are precisely the ones it bites on: a region and its +causal complement typically have no common upper bound in the index set — on the circle their +union misses only two points and so is neither connected nor non-dense, hence not a region. A net +over such an index set needing locality for `⟂` itself must be taken as a `VonNeumannNet` +(`QuantumSystem.Algebra.LocalNet.SplitProperty`), where the ambient `𝓑(H)` removes the obstruction. The file deliberately stops at the net-level axioms; in particular, additivity/generation axioms (e.g. `𝔄(O₁ ⊔ O₂)` being generated by the images of `𝔄(O₁)` and `𝔄(O₂)`, as in tensor-product @@ -21,6 +47,15 @@ spin-system nets) are intentionally out of scope here and belong to concrete ins The quasi-local algebra built from a net lives in `LocalNet.QuasiLocalAlgebra` (and requires the index set to be directed); covariance data and its action live in `LocalNet.Covariance` / `LocalNet.QuasiLocalAlgebra`. + +## Notation + +`𝔄(O)` in the prose above is documentation shorthand, following the AQFT literature, for the local +C⋆-algebra `N.algebra O` of a region; where a representation is in play, `𝓡(O)` abbreviates the +local von Neumann algebra `N.localVonNeumannAlgebra R O`. Neither is a Lean notation, and +deliberately so: both objects carry the net `N` — and `𝓡(O)` also the representation `R` — as +parameters that a bare `𝔄(O)` could not capture, so a faithful notation would have to spell them +out anyway. The symbols stay in the prose; the code writes the projections. -/ @[expose] public section @@ -31,10 +66,27 @@ index set to be directed); covariance data and its action live in `LocalNet.Cova (spacelike) disjointness of regions, the relation under which the Haag–Kastler locality axiom applies. It is symmetric and hereditary under shrinking regions. - Of the causal-index-set axiomatizations in the literature (Roberts; Guido–Longo–Roberts–Verch) - this class keeps only symmetry and heredity — the minimal core needed for locality, the - quasi-local algebra, and the split property. The existence of causal complements - (`∀ O₁, ∃ O₂, O₁ ⟂ O₂`), needed for DHR sector theory, is intentionally not required. + The literature's axiomatization (Guido–Longo–Roberts–Verch §3.1, the only abstract one in the + sources behind `docs/math/causal-index-set.md`) asks for three conditions: symmetry, heredity, + and the existence of causal complements (`∀ O₁, ∃ O₂, O₁ ⟂ O₂`). This class carries the first + two, which are properties of the relation itself; the third is a property of the *index set* + and is carried separately, as the mixin `CausalIndexSet` below. Splitting it off keeps this + class available where the third condition is absent or in doubt: the corpus secures it in + three different ways — through a membership condition (Guido–Longo–Roberts–Verch's regular + diamonds and Köster's proper intervals demand a non-void causal complement to *be* a region), + by admitting the empty region (lattice regions, where `∅` is disjoint from everything), or not + at all (Halvorson–Müger's double cones state no such clause) — and on a time-slab around a + compact Cauchy surface it fails under the reading of Brunetti–Fredenhagen–Verch that their own + category of spacetimes forces, though read literally their index set contains `∅` and the + condition then holds vacuously. A class demanding the condition could not carry such an index + set at all. + + What the third condition buys — on a *directed* index set, through heredity — is that causal + orthogonality refines the *other* derived relation of Guido–Longo–Roberts–Verch (`⊥̃`, a common + orthogonal partner rather than a common upper bound), and through it the duality theory of the + dual net and the DHR selection criterion; without directedness it has no order-theoretic + consequence at all, since adjoining a bottom element related to everything satisfies all three + conditions on any poset. None of that is used here. The relation is *not* required to be irreflexive: `O ⟂ O` legitimately holds for degenerate regions (e.g. the empty lattice region) and forces `𝔄(O)` to be commutative. For Minkowski @@ -77,27 +129,162 @@ theorem Orthogonal.mono {O₁' O₁ O₂' O₂ : K} (h₁ : O₁' ≤ O₁) (h O₁' ⟂ O₂' := (h.mono_left h₁).mono_right h₂ +/-! ### The derived relation `⊥̂` + +Guido–Longo–Roberts–Verch derive from `⟂` a relation written `⊥̂`, obtained by supplementing +`O₁ ⟂ O₂` with the demand that `O₁` and `O₂` have a **common upper bound** in the index set. It is +purely order- and `⟂`-theoretic — no topology, no closures — so it is available over +`CausalOrthogonality` exactly as that class stands. On a directed index set it collapses back onto +`⟂` (`orthogonalHat_iff`); off one it *can* be strictly weaker, though whether it is depends on the +relation — the collapse characterises directedness only after quantifying over all causal +orthogonality relations on the index set (`isDirectedOrder_iff_forall_orthogonalHat_iff`). The whole +`⟂` / `⊥̂` distinction is the price of dropping directedness. + +It is carried here because it, and not `⟂`, is what the locality axiom of `LocalNet` below +actually constrains: see `LocalNet.locality` and `LocalNet.exists_locality_of_orthogonalHat`. + +No notation is introduced for it: the literature's `⊥̂` needs a combining accent, and the relation +appears rarely enough that the spelled-out name reads better than a near-collision with `⟂`. +-/ + +/-- The **derived orthogonality relation `⊥̂`** of Guido–Longo–Roberts–Verch: `O₁` and `O₂` are + causally orthogonal *and* admit a common upper bound in the index set. + + This is the relation on which the locality axiom of a `LocalNet` bites, since commutation of + `𝔄(O₁)` with `𝔄(O₂)` can only be *stated* inside an algebra containing both. On a directed + index set it is `⟂` itself (`orthogonalHat_iff`). -/ +def OrthogonalHat (O₁ O₂ : K) : Prop := + O₁ ⟂ O₂ ∧ ∃ O₃, O₁ ≤ O₃ ∧ O₂ ≤ O₃ + +/-- The derived relation refines causal orthogonality. -/ +theorem OrthogonalHat.orthogonal {O₁ O₂ : K} (h : OrthogonalHat O₁ O₂) : O₁ ⟂ O₂ := + h.1 + +/-- A common upper bound of a pair related by the derived relation. -/ +theorem OrthogonalHat.exists_upperBound {O₁ O₂ : K} (h : OrthogonalHat O₁ O₂) : + ∃ O₃, O₁ ≤ O₃ ∧ O₂ ≤ O₃ := + h.2 + +/-- The derived relation is symmetric. Symmetry of `⟂` is what is used on the first component; + a common upper bound is symmetric on the nose. -/ +theorem OrthogonalHat.symm {O₁ O₂ : K} (h : OrthogonalHat O₁ O₂) : OrthogonalHat O₂ O₁ := + ⟨h.1.symm, h.2.imp fun _ hO => ⟨hO.2, hO.1⟩⟩ + +/-- The derived relation is hereditary under shrinking the left region: heredity of `⟂` handles + the first component and transitivity of `≤` the upper bound. -/ +theorem OrthogonalHat.mono_left {O₀ O₁ O₂ : K} (h₀ : O₀ ≤ O₁) (h : OrthogonalHat O₁ O₂) : + OrthogonalHat O₀ O₂ := + ⟨h.1.mono_left h₀, h.2.imp fun _ hO => ⟨h₀.trans hO.1, hO.2⟩⟩ + +/-- The derived relation is hereditary under shrinking the right region. -/ +theorem OrthogonalHat.mono_right {O₁ O₂ O₃ : K} (h₀ : O₃ ≤ O₂) (h : OrthogonalHat O₁ O₂) : + OrthogonalHat O₁ O₃ := + (h.symm.mono_left h₀).symm + +/-- The derived relation is hereditary under shrinking both regions. -/ +theorem OrthogonalHat.mono {O₁' O₁ O₂' O₂ : K} (h₁ : O₁' ≤ O₁) (h₂ : O₂' ≤ O₂) + (h : OrthogonalHat O₁ O₂) : OrthogonalHat O₁' O₂' := + (h.mono_left h₁).mono_right h₂ + +/-- **Passing to the derived relation is idempotent**: supplementing `⊥̂` with the demand for a + common upper bound asks for nothing new, since `⊥̂` already carries one. No axiom of + `CausalOrthogonality` is used. -/ +theorem orthogonalHat_and_exists_upperBound_iff {O₁ O₂ : K} : + (OrthogonalHat O₁ O₂ ∧ ∃ O₃, O₁ ≤ O₃ ∧ O₂ ≤ O₃) ↔ OrthogonalHat O₁ O₂ := + ⟨And.left, fun h => ⟨h, h.2⟩⟩ + +/-- **On a directed index set the derived relation is causal orthogonality itself.** Directedness + supplies the common upper bound, and no axiom of `CausalOrthogonality` is needed. + + Only this implication holds for a *fixed* orthogonality relation: off a directed index set the + two need not differ, since an empty `⟂` collapses onto `⊥̂` on any preorder. The sharp converse + quantifies over the relation (`isDirectedOrder_iff_forall_orthogonalHat_iff`). Where they do + differ it is `⊥̂` that the locality axiom of a `LocalNet` constrains: on the two-element + antichain `{O₁, O₂}` with `O₁ ⟂ O₂` there is no common upper bound at all, so `⊥̂` is empty + there while `⟂` is not. -/ +theorem orthogonalHat_iff [IsDirectedOrder K] {O₁ O₂ : K} : + OrthogonalHat O₁ O₂ ↔ O₁ ⟂ O₂ := + ⟨OrthogonalHat.orthogonal, fun h => ⟨h, directed_of (· ≤ ·) O₁ O₂⟩⟩ + +/-- **Directedness is exactly the coincidence of `⊥̂` with `⟂`, quantified over the relation.** + For one fixed `CausalOrthogonality K` the coincidence is strictly weaker than directedness — + the empty relation collapses on every preorder — so the literature's "`⊥̂ = ⟂` precisely on + directed index sets" is a statement about the index set, not about a single net's causal + structure. Read that way it is true: the forward direction is `orthogonalHat_iff`, and the + converse tests directedness against the *total* relation, in which every pair is causally + orthogonal and `⊥̂` therefore records nothing but the existence of a common upper bound. -/ +theorem isDirectedOrder_iff_forall_orthogonalHat_iff (K : Type*) [Preorder K] : + IsDirectedOrder K ↔ + ∀ [CausalOrthogonality K] (O₁ O₂ : K), OrthogonalHat O₁ O₂ ↔ O₁ ⟂ O₂ := by + constructor + · intro _ _ _ _ + exact orthogonalHat_iff + · intro h + refine ⟨fun O₁ O₂ => ?_⟩ + letI : CausalOrthogonality K := + { Orthogonal := fun _ _ => True + orthogonal_symm := fun _ _ _ => trivial + orthogonal_mono_left := fun _ _ _ _ _ => trivial } + exact ((h O₁ O₂).2 trivial).2 + end CausalOrthogonality open scoped CausalOrthogonality +/-- A **causal index set** in the full sense of Guido–Longo–Roberts–Verch §3.1: on top of the + symmetry and heredity carried by `CausalOrthogonality`, the third condition of the + axiomatization — the **existence of causal complements**, every region admitting a causally + disjoint one. An ordered `K` with `[CausalOrthogonality K]` and this mixin is exactly the + adopted general form of the extraction note `docs/math/causal-index-set.md`. + + Carried as a mixin rather than folded into `CausalOrthogonality`, because unlike symmetry and + heredity this condition is a property of the index set rather than of the relation, and the + corpus's index families do not all satisfy it (see the docstring of `CausalOrthogonality`). + It is genuinely model-dependent input: what this development draws from it is + `CausalIndexSet.exists_orthogonalHat` — on a directed index set the locality axiom of a + `LocalNet` bites at every region — while the duality theory it really feeds (the dual net, the + DHR selection criterion) is not formalized here; the literature's causal index set is not + expressible without it. -/ +class CausalIndexSet (K : Type*) [Preorder K] [CausalOrthogonality K] : Prop where + /-- Every region admits a causally disjoint region — axiom c) of the + Guido–Longo–Roberts–Verch axiomatization. -/ + exists_orthogonal : ∀ O₁ : K, ∃ O₂, O₁ ⟂ O₂ + +/-- **On a directed causal index set every region has a `⊥̂`-orthogonal partner**: directedness + upgrades the causal complement supplied by `exists_orthogonal` to the derived relation `⊥̂` + (`CausalOrthogonality.orthogonalHat_iff`), which is the relation the locality axiom of a + `LocalNet` actually constrains. So the locality axiom is nowhere vacuous on such an index set: + `LocalNet.exists_locality_of_orthogonalHat` applies at every region. -/ +theorem CausalIndexSet.exists_orthogonalHat {K : Type*} [Preorder K] [CausalOrthogonality K] + [IsDirectedOrder K] [CausalIndexSet K] (O : K) : + ∃ O', CausalOrthogonality.OrthogonalHat O O' := + let ⟨O', h⟩ := CausalIndexSet.exists_orthogonal O + ⟨O', CausalOrthogonality.orthogonalHat_iff.2 h⟩ + /-- On the finite regions of a lattice of sites, causal orthogonality is plain set disjointness: a lattice net is kinematical (equal-time), so "spacelike separated" degenerates to "disjoint in - space" (Naaijkens 2012 §3.4). -/ + space" (Naaijkens, *Anyons in Infinite Quantum Systems*, 2012, §3.4). -/ instance {α : Type*} : CausalOrthogonality (Finset α) where Orthogonal := Disjoint orthogonal_symm _ _ h := h.symm orthogonal_mono_left _ _ _ h₀ h := h.mono_left h₀ -/-- A **local net of C⋆-algebras** over a causal index set `K` — a partially ordered set of +/-- The lattice regions form a causal index set in the full sense: the **empty region** is + disjoint from every region, so causal complements exist for free. This is how the literature's + lattice index set secures the condition — through `∅ ∈ 𝒦` rather than through a membership + clause — at the price of `⟂` being reflexive at `∅`. -/ +instance {α : Type*} : CausalIndexSet (Finset α) := + ⟨fun Λ => ⟨∅, Finset.disjoint_empty_right Λ⟩⟩ + +/-- A **local net of C⋆-algebras** over a causal index set `K` — an ordered set of regions with a causal orthogonality relation `⟂` (`CausalOrthogonality`): the assignment `O ↦ 𝔄(O)` together with isotony embeddings `incl : 𝔄(O) →⋆ₐ[ℂ] 𝔄(O')` for `O ≤ O'`, functorial (`incl_refl`/`incl_trans`) and local (`locality`). This is the Haag–Kastler net structure over an abstract index set, *without* the injectivity requirement on the isotony - embeddings; the literature's net (Naaijkens 2012 §3.4) is `LocalNet` together with the - `Faithful` class, which carries that requirement. Lattice nets are the instance + embeddings; the literature's net (Naaijkens, *Anyons in Infinite Quantum Systems*, 2012, §3.4) + is `LocalNet` together with the `Faithful` class, which carries that requirement. Lattice nets are the instance `K = Finset sites` with `⟂ = Disjoint`. -/ -structure LocalNet (K : Type*) [PartialOrder K] [CausalOrthogonality K] where +structure LocalNet (K : Type*) [Preorder K] [CausalOrthogonality K] where /-- The local C⋆-algebra `𝔄(O)` assigned to a region. For any self-orthogonal region `O ⟂ O` (e.g. the empty lattice region) the axioms force `𝔄(O)` to be commutative (instantiate `locality` at `O₁ = O₂ = O`) but do *not* force it to be trivial: the literature's @@ -113,7 +300,22 @@ structure LocalNet (K : Type*) [PartialOrder K] [CausalOrthogonality K] where incl_trans : ∀ {O₁ O₂ O₃ : K} (h₁₂ : O₁ ≤ O₂) (h₂₃ : O₂ ≤ O₃) (x : algebra O₁), incl h₂₃ (incl h₁₂ x) = incl (h₁₂.trans h₂₃) x /-- **Locality** (microcausality, Einstein causality): observables localised in causally - orthogonal regions commute inside any common larger region. -/ + orthogonal regions commute inside any common larger region. + + The common region `O` is bound *before* the orthogonality hypothesis, and that is not an + accident of phrasing: `Commute x y` for `x : 𝔄(O₁)` and `y : 𝔄(O₂)` is not even typeable + without an algebra containing both, and over a non-directed index set there need be no such + region — nor any quasi-local algebra to fall back on. So the pairs this field constrains are + exactly those causally orthogonal pairs that admit a common upper bound, which is the derived + relation `CausalOrthogonality.OrthogonalHat` (`⊥̂`) rather than `⟂` itself. The two coincide + on directed index sets (`CausalOrthogonality.orthogonalHat_iff`) — and, once the orthogonality + relation is quantified over, only there + (`CausalOrthogonality.isDirectedOrder_iff_forall_orthogonalHat_iff`) — which is where every + consumer of this field lives. + + A net over a genuinely non-directed index set that needs locality for `⟂` itself must be + taken as a `VonNeumannNet` (`QuantumSystem.Algebra.LocalNet.SplitProperty`), whose ambient + `𝓑(H)` lets `algebra_le_commutant_of_orthogonal` state locality with no upper bound. -/ locality : ∀ {O₁ O₂ O : K} (h₁ : O₁ ≤ O) (h₂ : O₂ ≤ O), O₁ ⟂ O₂ → ∀ (x : algebra O₁) (y : algebra O₂), Commute (incl h₁ x) (incl h₂ y) @@ -149,7 +351,7 @@ def mk' (algebra : K → Type*) [algebraCStar : ∀ O, CStarAlgebra (algebra O)] end SemilatticeSup -variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] (N : LocalNet K) +variable {K : Type*} [Preorder K] [CausalOrthogonality K] (N : LocalNet K) /-- The net forms a directed system of `*`-algebras: the isotony embeddings compose and the identity inclusion is the identity. -/ @@ -158,6 +360,36 @@ instance directedSystem : map_self _ x := N.incl_refl x map_map _ _ _ hij hjk x := N.incl_trans hij hjk x +/-! ### What locality constrains + +The `locality` field quantifies over a common upper bound of the two regions, so the pairs it +constrains are exactly those related by the derived relation `⊥̂` of +`CausalOrthogonality.OrthogonalHat`. The two lemmas below say this in both directions of the +directedness dichotomy: `⊥̂`-related pairs always get commutation somewhere, and on a directed +index set that is every causally orthogonal pair. +-/ + +/-- **Locality is locality for the derived relation `⊥̂`**: a causally orthogonal pair admitting a + common upper bound commutes inside one. This is the whole content of the `locality` field — + for a causally orthogonal pair with *no* common upper bound the field says nothing, and cannot, + since the commutation has nowhere to be stated. -/ +theorem exists_locality_of_orthogonalHat {O₁ O₂ : K} + (h : CausalOrthogonality.OrthogonalHat O₁ O₂) : + ∃ (O : K) (h₁ : O₁ ≤ O) (h₂ : O₂ ≤ O), + ∀ (x : N.algebra O₁) (y : N.algebra O₂), Commute (N.incl h₁ x) (N.incl h₂ y) := + let ⟨O, h₁, h₂⟩ := h.exists_upperBound + ⟨O, h₁, h₂, N.locality h₁ h₂ h.orthogonal⟩ + +/-- **On a directed index set locality is locality for `⟂` itself**: directedness supplies the + common upper bound, so every causally orthogonal pair commutes inside some region. This is the + setting of every consumer of the `locality` field — in particular of + `LocalNet.ιLocal_commute_of_orthogonal`, where the quasi-local algebra provides the ambient + algebra in which the commutation is finally stated for all pairs at once. -/ +theorem exists_locality_of_orthogonal [IsDirectedOrder K] {O₁ O₂ : K} (h : O₁ ⟂ O₂) : + ∃ (O : K) (h₁ : O₁ ≤ O) (h₂ : O₂ ≤ O), + ∀ (x : N.algebra O₁) (y : N.algebra O₂), Commute (N.incl h₁ x) (N.incl h₂ y) := + N.exists_locality_of_orthogonalHat (CausalOrthogonality.orthogonalHat_iff.2 h) + /-! ### Faithful nets A net is *faithful* when its isotony embeddings are injective (the standard AQFT @@ -166,11 +398,12 @@ non-degeneracy condition). The quasi-local C⋆-norm built from this hypothesis -/ /-- A local net is **faithful** when all its isotony embeddings are injective. In the standard - AQFT definition the isotony embeddings are *injective* unital `*`-homomorphisms (Naaijkens 2012 - §3.4), so a faithful local net — `LocalNet` together with `Faithful` — is the literature's net. + AQFT definition the isotony embeddings are *injective* unital `*`-homomorphisms (Naaijkens, + *Anyons in Infinite Quantum Systems*, 2012, §3.4), so a faithful local net — `LocalNet` + together with `Faithful` — is the literature's net. Carried as a typeclass rather than a structure field so algebraic constructions can state the non-degeneracy hypothesis only where they need it. -/ -class Faithful {K : Type*} [PartialOrder K] [CausalOrthogonality K] (N : LocalNet K) : Prop where +class Faithful {K : Type*} [Preorder K] [CausalOrthogonality K] (N : LocalNet K) : Prop where /-- Every isotony embedding of the net is injective. -/ incl_injective : ∀ {O O' : K} (h : O ≤ O'), Function.Injective (N.incl h) diff --git a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean index 834a9ce..3ecc812 100644 --- a/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean +++ b/QuantumSystem/Algebra/LocalNet/QuasiLocalAlgebra.lean @@ -14,20 +14,28 @@ The **algebra of local observables** and the **quasi-local C⋆-algebra** of an union of the local algebras an algebra. Lattice nets (`K = Finset sites`) are directed by unions with the empty region as base point. -* `LocalNet.quasiLocalAlgebra` is the algebraic inductive limit `‾⋃_O 𝔄(O)` of the local algebras +* `LocalNet.localObservables` is the algebraic inductive limit `‾⋃_O 𝔄(O)` of the local algebras along the isotony embeddings, with cocone `ιLocal`, exhaustion (`exists_ιLocal`) and locality (`ιLocal_commute_of_orthogonal`). * For a `Faithful` net the connecting maps are isometric, so the algebra of local observables carries a C⋆-norm whose completion `LocalNet.quasiLocalCStarAlgebra` is the AQFT quasi-local - algebra `𝔄 = ‾⋃_O 𝔄(O)` (Naaijkens 2012 §1.3, Bratteli–Robinson Vol.2 §6.2), with dense local - embeddings `ιLocalCStar`. + algebra `𝔄 = ‾⋃_O 𝔄(O)` (Naaijkens, *Anyons in Infinite Quantum Systems*, 2012, §1.3; + Bratteli–Robinson Vol.2 §6.2), with isometric local embeddings `ιLocalCStar` — unital + `*`-homomorphisms `𝔄(O) →⋆ₐ[ℂ] 𝔄`, injective and with *closed* range, whose ranges are dense + in `𝔄` only taken together (`denseRange_iUnion_ιLocalCStar`). A `LocalNet.Covariance` (defined in `LocalNet.Covariance`) acts on these algebras: its per-region -`*`-isomorphisms assemble into a ring endomorphism `quasiLocalCovariance` of the algebra of local +`*`-isomorphisms assemble into a ring endomorphism `localObservableCovariance` of the algebra of local observables, which is functorial and is shown `ℂ`-linear and `*`-preserving — hence bundled as a -`*`-automorphism `quasiLocalCovarianceEquiv`, assembled into a group homomorphism -`quasiLocalCovarianceHom`. For a `Faithful` net it is isometric and extends to a `*`-automorphism +`*`-automorphism `localObservableCovarianceEquiv`, assembled into a group homomorphism +`localObservableCovarianceHom`. For a `Faithful` net it is isometric and extends to a `*`-automorphism `quasiLocalCStarCovarianceEquiv` of the quasi-local C⋆-algebra. + +## Notation + +`𝔄(O)` and `𝓡(O)` in the prose above are documentation shorthand for the local C⋆-algebra +`N.algebra O` and the local von Neumann algebra `N.localVonNeumannAlgebra R O`; the convention — +and why neither is a Lean notation — is stated in full in `QuantumSystem.Algebra.LocalNet.Net`. -/ @[expose] public section @@ -36,7 +44,7 @@ namespace LocalNet open scoped CausalOrthogonality -variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] +variable {K : Type*} [Preorder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] variable (N : LocalNet K) /-! ### Algebra of local observables @@ -46,7 +54,7 @@ These constructions apply to any abstract local net over a directed causal index /-- The **algebra of local observables** of the net: the algebraic inductive limit of the local algebras along the isotony embeddings. Its C⋆-completion is the quasi-local algebra. -/ -noncomputable abbrev quasiLocalAlgebra : Type _ := +noncomputable abbrev localObservables : Type _ := DirectLimit N.algebra (fun _ _ h => N.incl h) omit [Nonempty K] in @@ -55,12 +63,12 @@ omit [Nonempty K] in direct-limit constructions, since each `algebra O` is a `ℂ`-`*`-algebra and `incl` is a `*`-algebra homomorphism. -/ @[simp] lemma star_mk {O : K} (X : N.algebra O) : - star (⟦⟨O, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨O, star X⟩⟧ := rfl + star (⟦⟨O, X⟩⟧ : N.localObservables) = ⟦⟨O, star X⟩⟧ := rfl /-- The canonical embedding `𝔄(O) ↪ 𝔄_loc` of a local algebra into the algebra of local observables, as a unital ring homomorphism (the cocone of the inductive limit). -/ noncomputable def ιLocal (O : K) : - N.algebra O →+* N.quasiLocalAlgebra := + N.algebra O →+* N.localObservables := DirectLimit.Ring.of N.algebra (fun _ _ h => N.incl h) O /-- Compatibility of the cocone with the isotony embeddings: including `X` from `O` into the @@ -74,6 +82,11 @@ noncomputable def ιLocal (O : K) : N.ιLocal O (star X) = star (N.ιLocal O X) := (star_mk (N := N) X).symm +/-- The cocone is `ℂ`-linear: scalars act componentwise on the inductive limit. -/ +@[simp] lemma ιLocal_smul (c : ℂ) {O : K} (X : N.algebra O) : + N.ιLocal O (c • X) = c • N.ιLocal O X := + (DirectLimit.smul_def O X c).symm + /-- The cocone of the inductive limit absorbs the region-equality transport. -/ @[simp] lemma ιLocal_algebraCongr {O O' : K} (h : O = O') (x : N.algebra O) : N.ιLocal O' (N.algebraCongr h x) = N.ιLocal O x := by @@ -81,7 +94,7 @@ noncomputable def ιLocal (O : K) : /-- **Exhaustion**: every element of the algebra of local observables is the image of a local observable from some region — the union of the local algebras is the whole limit. -/ -theorem exists_ιLocal (z : N.quasiLocalAlgebra) : +theorem exists_ιLocal (z : N.localObservables) : ∃ (O : K) (X : N.algebra O), z = N.ιLocal O X := by induction z using DirectLimit.induction with | _ O X => exact ⟨O, X, rfl⟩ @@ -108,26 +121,28 @@ variable [N.Faithful] /-- The algebra of local observables is a normed ring under the C⋆-norm of the inductive limit (the inclusions are injective, hence isometric). -/ -noncomputable instance : NormedRing N.quasiLocalAlgebra := +noncomputable instance : NormedRing N.localObservables := DirectLimit.cstarNormedRing (fun _ _ h => Faithful.incl_injective h) +/-- The C⋆-norm of a local observable, viewed in the algebra of local observables, is its norm in + its own region's algebra: the connecting maps are isometric. -/ @[simp] lemma norm_mk {O : K} (X : N.algebra O) : - ‖(⟦⟨O, X⟩⟧ : N.quasiLocalAlgebra)‖ = ‖X‖ := rfl + ‖(⟦⟨O, X⟩⟧ : N.localObservables)‖ = ‖X‖ := rfl /-- The C⋆-norm is compatible with the `ℂ`-algebra structure. -/ -noncomputable instance : NormedAlgebra ℂ N.quasiLocalAlgebra where +noncomputable instance : NormedAlgebra ℂ N.localObservables where norm_smul_le c x := by induction x using DirectLimit.induction with | _ O X => rw [DirectLimit.smul_def, norm_mk, norm_mk]; exact norm_smul_le c X /-- `star` is isometric on the algebra of local observables. -/ -instance : NormedStarGroup N.quasiLocalAlgebra where +instance : NormedStarGroup N.localObservables where norm_star_le x := by induction x using DirectLimit.induction with | _ O X => rw [star_mk, norm_mk, norm_mk]; exact (norm_star X).le /-- The C⋆-identity holds on the algebra of local observables. -/ -instance : CStarRing N.quasiLocalAlgebra where +instance : CStarRing N.localObservables where norm_mul_self_le x := by induction x using DirectLimit.induction with | _ O X => rw [star_mk, DirectLimit.mul_def, norm_mk, norm_mk] @@ -136,29 +151,66 @@ instance : CStarRing N.quasiLocalAlgebra where /-- The **quasi-local C⋆-algebra** of a faithful net: the completion of the algebra of local observables. This is the AQFT quasi-local algebra `𝔄 = ‾⋃_O 𝔄(O)`. -/ noncomputable abbrev quasiLocalCStarAlgebra : Type _ := - UniformSpace.Completion N.quasiLocalAlgebra + UniformSpace.Completion N.localObservables noncomputable example : CStarAlgebra N.quasiLocalCStarAlgebra := inferInstance -/-- The canonical embedding `𝔄(O) → 𝔄` of a local algebra into the quasi-local C⋆-algebra, - as the completion coercion composed with the inductive-limit cocone. Its range is dense. -/ -noncomputable def ιLocalCStar (O : K) : - N.algebra O → N.quasiLocalCStarAlgebra := - (↑) ∘ N.ιLocal O +/-- The canonical **local embedding** `𝔄(O) → 𝔄` of a local algebra into the quasi-local + C⋆-algebra: the completion coercion composed with the inductive-limit cocone, bundled as a + unital `*`-homomorphism of `ℂ`-algebras. It is isometric (`norm_ιLocalCStar`) and therefore + injective (`ιLocalCStar_injective`), so each `𝔄(O)` sits in `𝔄` as an isomorphic copy — the + non-degeneracy the AQFT literature builds into its net axioms, here inherited from `Faithful`. -/-- The dense embedding is compatible with the isotony embeddings: including into a larger + A *single* such range is not dense: an isometric image of a complete space is complete, hence + closed, so it is dense only when it is all of `𝔄`. What is dense is the union over all regions + (`denseRange_iUnion_ιLocalCStar`), which is the `‾⋃_O 𝔄(O)` of the literature. -/ +noncomputable def ιLocalCStar (O : K) : + N.algebra O →⋆ₐ[ℂ] N.quasiLocalCStarAlgebra where + toFun := (↑) ∘ N.ιLocal O + map_one' := by simp + map_mul' X Y := by + simp only [Function.comp_apply, map_mul, UniformSpace.Completion.coe_mul] + map_zero' := by simp + map_add' X Y := by + simp only [Function.comp_apply, map_add, UniformSpace.Completion.coe_add] + commutes' c := by + simp only [Function.comp_apply, Algebra.algebraMap_eq_smul_one, N.ιLocal_smul, map_one, + UniformSpace.Completion.coe_smul, UniformSpace.Completion.coe_one] + map_star' X := by simp + +/-- The local embedding is the completion coercion after the inductive-limit cocone. -/ +lemma coe_ιLocalCStar (O : K) : ⇑(N.ιLocalCStar O) = (↑) ∘ N.ιLocal O := rfl + +/-- The local embedding is compatible with the isotony embeddings: including into a larger region first does not change the image in the quasi-local C⋆-algebra. -/ @[simp] lemma ιLocalCStar_incl {O O' : K} (h : O ≤ O') (X : N.algebra O) : - N.ιLocalCStar O' (N.incl h X) = N.ιLocalCStar O X := - congrArg _ (N.ιLocal_incl h X) + N.ιLocalCStar O' (N.incl h X) = N.ιLocalCStar O X := by + simp only [coe_ιLocalCStar, Function.comp_apply, ιLocal_incl] -/-- The dense embedding is a `*`-map: it intertwines the local and quasi-local involutions. -/ +/-- The local embedding is a `*`-map: it intertwines the local and quasi-local involutions. -/ @[simp] lemma ιLocalCStar_star {O : K} (X : N.algebra O) : - N.ιLocalCStar O (star X) = star (N.ιLocalCStar O X) := by - simp [ιLocalCStar] + N.ιLocalCStar O (star X) = star (N.ιLocalCStar O X) := + map_star _ X + +/-- **The local embedding is isometric**: the connecting maps of a faithful net are isometric, so + the C⋆-norm of `𝔄(O)` is the one it inherits from the quasi-local algebra. -/ +@[simp] lemma norm_ιLocalCStar {O : K} (X : N.algebra O) : + ‖N.ιLocalCStar O X‖ = ‖X‖ := by + rw [coe_ιLocalCStar, Function.comp_apply, UniformSpace.Completion.norm_coe] + exact N.norm_mk X + +/-- The local embedding is an isometry (bundled form of `norm_ιLocalCStar`). -/ +lemma isometry_ιLocalCStar (O : K) : Isometry (N.ιLocalCStar O) := + AddMonoidHomClass.isometry_of_norm _ (N.norm_ιLocalCStar (O := O)) + +/-- **The local embedding is injective**: it is isometric, so it is an embedding of `𝔄(O)` onto a + closed C⋆-subalgebra of the quasi-local algebra. -/ +lemma ιLocalCStar_injective (O : K) : Function.Injective (N.ιLocalCStar O) := + (N.isometry_ιLocalCStar O).injective /-- The local algebras are dense in the quasi-local C⋆-algebra: every element is a norm-limit of - local observables. -/ + local observables. Note the union: a single local algebra has *closed*, not dense, image + (`isometry_ιLocalCStar`). -/ theorem denseRange_iUnion_ιLocalCStar : Dense (⋃ O : K, Set.range (N.ιLocalCStar O)) := by refine UniformSpace.Completion.denseRange_coe.mono ?_ @@ -184,104 +236,106 @@ variable {N} (a : N.Covariance) /-- The **covariance action** `β_a ⟦⟨O, X⟩⟧ = ⟦⟨σO, β_O X⟩⟧` of a covariance on the algebra of local observables, as a ring homomorphism. Well-defined by naturality (`β_incl`). -/ -noncomputable def quasiLocalCovariance : N.quasiLocalAlgebra →+* N.quasiLocalAlgebra := - DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.quasiLocalAlgebra - (fun O => (N.ιLocal (a.region O)).comp (a.β O).toAlgEquiv.toAlgHom.toRingHom) +noncomputable def localObservableCovariance : N.localObservables →+* N.localObservables := + DirectLimit.Ring.lift N.algebra (fun _ _ h => N.incl h) N.localObservables + (fun O => (N.ιLocal (a.σ O)).comp (a.β O).toAlgEquiv.toAlgHom.toRingHom) (fun O O' h X => by - change N.ιLocal (a.region O') (a.β O' (N.incl h X)) = N.ιLocal (a.region O) (a.β O X) + change N.ιLocal (a.σ O') (a.β O' (N.incl h X)) = N.ιLocal (a.σ O) (a.β O X) rw [a.β_incl h] exact N.ιLocal_incl _ _) -@[simp] lemma quasiLocalCovariance_mk {O : K} (X : N.algebra O) : - a.quasiLocalCovariance (⟦⟨O, X⟩⟧ : N.quasiLocalAlgebra) = ⟦⟨a.region O, a.β O X⟩⟧ := +/-- Componentwise formula for the covariance action: `β_a ⟦⟨O, X⟩⟧ = ⟦⟨σO, β_O X⟩⟧`. -/ +@[simp] lemma localObservableCovariance_mk {O : K} (X : N.algebra O) : + a.localObservableCovariance (⟦⟨O, X⟩⟧ : N.localObservables) = ⟦⟨a.σ O, a.β O X⟩⟧ := rfl /-- The covariance action of the identity covariance is the identity: `β_{id} = id`. -/ -@[simp] lemma quasiLocalCovariance_id : - (Covariance.id N).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by +@[simp] lemma localObservableCovariance_id : + (Covariance.id N).localObservableCovariance = RingHom.id N.localObservables := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with - | _ O X => rw [quasiLocalCovariance_mk, RingHom.id_apply]; rfl + | _ O X => rw [localObservableCovariance_mk, RingHom.id_apply]; rfl /-- **Functoriality of the covariance action**: composing covariances composes their actions, `β_{a∘b} = β_a ∘ β_b`. -/ -@[simp] lemma quasiLocalCovariance_comp (a b : N.Covariance) : - (a.comp b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by +@[simp] lemma localObservableCovariance_comp (a b : N.Covariance) : + (a.comp b).localObservableCovariance = a.localObservableCovariance.comp b.localObservableCovariance := by refine RingHom.ext fun z => ?_ induction z using DirectLimit.induction with | _ O X => - simp only [RingHom.comp_apply, quasiLocalCovariance_mk] + simp only [RingHom.comp_apply, localObservableCovariance_mk] rfl /-- The covariance action sends the unit covariance to the identity: `β_1 = id`. -/ -@[simp] lemma quasiLocalCovariance_one : - (1 : N.Covariance).quasiLocalCovariance = RingHom.id N.quasiLocalAlgebra := by - rw [one_def, quasiLocalCovariance_id] +@[simp] lemma localObservableCovariance_one : + (1 : N.Covariance).localObservableCovariance = RingHom.id N.localObservables := by + rw [one_def, localObservableCovariance_id] /-- The covariance action is multiplicative: `β_{a·b} = β_a ∘ β_b`. -/ -lemma quasiLocalCovariance_mul (a b : N.Covariance) : - (a * b).quasiLocalCovariance = a.quasiLocalCovariance.comp b.quasiLocalCovariance := by - rw [mul_def, quasiLocalCovariance_comp] +lemma localObservableCovariance_mul (a b : N.Covariance) : + (a * b).localObservableCovariance = a.localObservableCovariance.comp b.localObservableCovariance := by + rw [mul_def, localObservableCovariance_comp] /-! #### The covariance action as a `*`-automorphism -/ /-- The covariance action is `ℂ`-linear: `β_a (c • z) = c • β_a z`, since each `β` is. -/ -lemma quasiLocalCovariance_smul (c : ℂ) (z : N.quasiLocalAlgebra) : - a.quasiLocalCovariance (c • z) = c • a.quasiLocalCovariance z := by +lemma localObservableCovariance_smul (c : ℂ) (z : N.localObservables) : + a.localObservableCovariance (c • z) = c • a.localObservableCovariance z := by induction z using DirectLimit.induction with | _ O X => - rw [DirectLimit.smul_def, quasiLocalCovariance_mk, quasiLocalCovariance_mk, DirectLimit.smul_def, - map_smul] - rfl + rw [DirectLimit.smul_def, localObservableCovariance_mk, localObservableCovariance_mk, + DirectLimit.smul_def, map_smul] /-- The covariance action preserves the involution: `β_a (star z) = star (β_a z)`, since each `β` is a `*`-isomorphism. -/ -lemma quasiLocalCovariance_star (z : N.quasiLocalAlgebra) : - a.quasiLocalCovariance (star z) = star (a.quasiLocalCovariance z) := by +lemma localObservableCovariance_star (z : N.localObservables) : + a.localObservableCovariance (star z) = star (a.localObservableCovariance z) := by induction z using DirectLimit.induction with | _ O X => - rw [star_mk, quasiLocalCovariance_mk, quasiLocalCovariance_mk, star_mk, map_star] - rfl + rw [star_mk, localObservableCovariance_mk, localObservableCovariance_mk, star_mk, map_star] /-- The covariance action as a `*`-algebra automorphism of the algebra of local observables, with the action of the inverse covariance `a⁻¹` as its inverse. -/ -noncomputable def quasiLocalCovarianceEquiv : - N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra where - toFun := a.quasiLocalCovariance - invFun := a⁻¹.quasiLocalCovariance +noncomputable def localObservableCovarianceEquiv : + N.localObservables ≃⋆ₐ[ℂ] N.localObservables where + toFun := a.localObservableCovariance + invFun := a⁻¹.localObservableCovariance left_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, inv_mul_cancel, quasiLocalCovariance_one, + rw [← RingHom.comp_apply, ← localObservableCovariance_mul, inv_mul_cancel, localObservableCovariance_one, RingHom.id_apply] right_inv z := by - rw [← RingHom.comp_apply, ← quasiLocalCovariance_mul, mul_inv_cancel, quasiLocalCovariance_one, + rw [← RingHom.comp_apply, ← localObservableCovariance_mul, mul_inv_cancel, localObservableCovariance_one, RingHom.id_apply] - map_mul' := map_mul a.quasiLocalCovariance - map_add' := map_add a.quasiLocalCovariance - map_smul' := a.quasiLocalCovariance_smul - map_star' := a.quasiLocalCovariance_star + map_mul' := map_mul a.localObservableCovariance + map_add' := map_add a.localObservableCovariance + map_smul' := a.localObservableCovariance_smul + map_star' := a.localObservableCovariance_star -@[simp] lemma quasiLocalCovarianceEquiv_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalCovarianceEquiv z = a.quasiLocalCovariance z := rfl +/-- The bundled `*`-automorphism agrees with the underlying ring homomorphism. -/ +@[simp] lemma localObservableCovarianceEquiv_apply (z : N.localObservables) : + a.localObservableCovarianceEquiv z = a.localObservableCovariance z := rfl -@[simp] lemma quasiLocalCovarianceEquiv_symm_apply (z : N.quasiLocalAlgebra) : - a.quasiLocalCovarianceEquiv.symm z = a⁻¹.quasiLocalCovariance z := rfl +/-- The inverse of the bundled `*`-automorphism is the action of the inverse covariance. -/ +@[simp] lemma localObservableCovarianceEquiv_symm_apply (z : N.localObservables) : + a.localObservableCovarianceEquiv.symm z = a⁻¹.localObservableCovariance z := rfl /-- A covariance of the net acts on the algebra of local observables by `*`-algebra automorphisms, assembled as a group homomorphism into the `*`-automorphism group. -/ -noncomputable def quasiLocalCovarianceHom : - N.Covariance →* (N.quasiLocalAlgebra ≃⋆ₐ[ℂ] N.quasiLocalAlgebra) where - toFun a := a.quasiLocalCovarianceEquiv +noncomputable def localObservableCovarianceHom : + N.Covariance →* (N.localObservables ≃⋆ₐ[ℂ] N.localObservables) where + toFun a := a.localObservableCovarianceEquiv map_one' := by ext z - simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_one, RingHom.id_apply, + simp only [localObservableCovarianceEquiv_apply, localObservableCovariance_one, RingHom.id_apply, StarAlgEquiv.one_apply] map_mul' a b := by ext z - simp only [quasiLocalCovarianceEquiv_apply, quasiLocalCovariance_mul, RingHom.comp_apply, + simp only [localObservableCovarianceEquiv_apply, localObservableCovariance_mul, RingHom.comp_apply, StarAlgEquiv.mul_apply] -@[simp] lemma quasiLocalCovarianceHom_apply (z : N.quasiLocalAlgebra) : - quasiLocalCovarianceHom a z = a.quasiLocalCovariance z := rfl +/-- The group homomorphism evaluates to the covariance action. -/ +@[simp] lemma localObservableCovarianceHom_apply (z : N.localObservables) : + localObservableCovarianceHom a z = a.localObservableCovariance z := rfl /-! #### The covariance automorphism of the quasi-local C⋆-algebra -/ @@ -291,41 +345,45 @@ variable [N.Faithful] /-- The covariance action is **isometric** on the algebra of local observables: each `β` is a `*`-isomorphism of C⋆-algebras, hence norm-preserving. -/ -lemma quasiLocalCovariance_norm (z : N.quasiLocalAlgebra) : - ‖a.quasiLocalCovariance z‖ = ‖z‖ := by +lemma localObservableCovariance_norm (z : N.localObservables) : + ‖a.localObservableCovariance z‖ = ‖z‖ := by induction z using DirectLimit.induction with | _ O X => - rw [quasiLocalCovariance_mk, norm_mk, norm_mk] + rw [localObservableCovariance_mk, norm_mk, norm_mk] exact StarAlgEquiv.norm_map _ X /-- The covariance automorphism of the algebra of local observables is uniformly continuous (it is an isometry), so it extends to the C⋆-completion. -/ -lemma quasiLocalCovarianceEquiv_uniformContinuous : - UniformContinuous a.quasiLocalCovarianceEquiv := +lemma localObservableCovarianceEquiv_uniformContinuous : + UniformContinuous a.localObservableCovarianceEquiv := (AddMonoidHomClass.isometry_of_norm _ (fun z => by - rw [quasiLocalCovarianceEquiv_apply]; exact a.quasiLocalCovariance_norm z)).uniformContinuous + rw [localObservableCovarianceEquiv_apply]; exact a.localObservableCovariance_norm z)).uniformContinuous /-- The inverse covariance automorphism is uniformly continuous as well (the action of `a⁻¹` is also an isometry). -/ -lemma quasiLocalCovarianceEquiv_symm_uniformContinuous : - UniformContinuous a.quasiLocalCovarianceEquiv.symm := by - have h : ∀ z, ‖a.quasiLocalCovarianceEquiv.symm z‖ = ‖z‖ := fun z => by - rw [quasiLocalCovarianceEquiv_symm_apply]; exact a⁻¹.quasiLocalCovariance_norm z +lemma localObservableCovarianceEquiv_symm_uniformContinuous : + UniformContinuous a.localObservableCovarianceEquiv.symm := by + have h : ∀ z, ‖a.localObservableCovarianceEquiv.symm z‖ = ‖z‖ := fun z => by + rw [localObservableCovarianceEquiv_symm_apply]; exact a⁻¹.localObservableCovariance_norm z exact (AddMonoidHomClass.isometry_of_norm _ h).uniformContinuous /-- The covariance automorphism of the quasi-local C⋆-algebra: the continuous extension of - `quasiLocalCovarianceEquiv` to the completion. -/ + `localObservableCovarianceEquiv` to the completion. -/ noncomputable def quasiLocalCStarCovarianceEquiv : N.quasiLocalCStarAlgebra ≃⋆ₐ[ℂ] N.quasiLocalCStarAlgebra := - UniformSpace.Completion.mapStarAlgEquiv a.quasiLocalCovarianceEquiv - a.quasiLocalCovarianceEquiv_uniformContinuous - a.quasiLocalCovarianceEquiv_symm_uniformContinuous + UniformSpace.Completion.mapStarAlgEquiv a.localObservableCovarianceEquiv + a.localObservableCovarianceEquiv_uniformContinuous + a.localObservableCovarianceEquiv_symm_uniformContinuous -@[simp] lemma quasiLocalCStarCovarianceEquiv_coe (z : N.quasiLocalAlgebra) : +/-- On local observables the extension to the completion agrees with the covariance action they + already carry. -/ +@[simp] lemma quasiLocalCStarCovarianceEquiv_coe (z : N.localObservables) : a.quasiLocalCStarCovarianceEquiv (↑z : N.quasiLocalCStarAlgebra) = - ↑(a.quasiLocalCovariance z) := + ↑(a.localObservableCovariance z) := UniformSpace.Completion.mapStarAlgEquiv_coe _ _ _ z +/-- The covariance automorphism of the quasi-local C⋆-algebra is continuous, being the continuous + extension of an isometry to the completion. -/ lemma quasiLocalCStarCovarianceEquiv_continuous : Continuous (⇑a.quasiLocalCStarCovarianceEquiv) := UniformSpace.Completion.continuous_map @@ -342,7 +400,7 @@ noncomputable def quasiLocalCStarCovarianceHom : (isClosed_eq (1 : N.Covariance).quasiLocalCStarCovarianceEquiv_continuous continuous_id) ?_ intro w - simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_one, RingHom.id_apply] + simp only [quasiLocalCStarCovarianceEquiv_coe, localObservableCovariance_one, RingHom.id_apply] map_mul' a b := by refine StarAlgEquiv.ext fun z => ?_ rw [StarAlgEquiv.mul_apply] @@ -351,8 +409,10 @@ noncomputable def quasiLocalCStarCovarianceHom : (a.quasiLocalCStarCovarianceEquiv_continuous.comp b.quasiLocalCStarCovarianceEquiv_continuous)) ?_ intro w - simp only [quasiLocalCStarCovarianceEquiv_coe, quasiLocalCovariance_mul, RingHom.comp_apply] + simp only [quasiLocalCStarCovarianceEquiv_coe, localObservableCovariance_mul, RingHom.comp_apply] +/-- The group homomorphism evaluates to the covariance automorphism of the quasi-local + C⋆-algebra. -/ @[simp] lemma quasiLocalCStarCovarianceHom_apply (z : N.quasiLocalCStarAlgebra) : quasiLocalCStarCovarianceHom a z = a.quasiLocalCStarCovarianceEquiv z := rfl From a130a0a89e43d668320f765d5cea6cdc3a36d5dc Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:43:41 +0000 Subject: [PATCH 099/113] feat: derive the split property from proper containment ProperContainment gives the 'suitably separated' region relation the split property needs (a causal collar strictly inside the larger region), with thickening and finite-lattice constructors. VonNeumannNet.SplitProperty and LocalNet.SplitProperty state the nested-form split property over a CausalIndexSet and derive the commutant form from it via locality. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../Algebra/LocalNet/SplitProperty.lean | 451 +++++++++++++++--- 1 file changed, 381 insertions(+), 70 deletions(-) diff --git a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean index 917088c..6d5f1cf 100644 --- a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean +++ b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean @@ -9,10 +9,11 @@ public import QuantumSystem.Algebra.VonNeumannAlgebra.SplitInclusion The **split property** of a local net, in the form of Buchholz (*Product states for local algebras*, Comm. Math. Phys. 36, 1974) and Doplicher–Longo (*Standard and split inclusions of -von Neumann algebras*, Invent. Math. 75, 1984): fix a representation `π` of the quasi-local -C⋆-algebra on a Hilbert space and form the **local von Neumann algebras** +von Neumann algebras*, Invent. Math. 75, 1984): fix a representation `R` of the quasi-local +C⋆-algebra on a Hilbert space, with representing map `R.π`, and form the **local von Neumann +algebras** - `𝓡(O) = π(𝔄(O))″` (`LocalNet.localVonNeumannAlgebra`); + `𝓡(O) = R.π(𝔄(O))″` (`LocalNet.localVonNeumannAlgebra`); the net has the split property when, for every properly contained pair of regions `O₁ ⋐ O₂`, the inclusion `𝓡(O₁) ≤ 𝓡(O₂)` is a split inclusion — some type I factor interpolates @@ -20,32 +21,74 @@ inclusion `𝓡(O₁) ≤ 𝓡(O₂)` is a split inclusion — some type I facto Proper containment `⋐` (`ProperContainment`) is the abstract form of the geometric relation "the closure of `O₁` lies in the interior of `O₂`" of the QFT literature; on a causal index set -it is model-dependent geometric input, like the causal orthogonality `⟂` itself. The class only -axiomatises necessary conditions (containment, monotonicity, and a causal collar inside the outer -region); it is *not* a complete axiomatisation of properness — e.g. on lattice regions, where the -empty region is orthogonal to everything, plain containment `⊆` also satisfies the axioms — so -the split property is always relative to the chosen `⋐`. Unlike `CausalOrthogonality (Finset α)`, -there is no canonical `ProperContainment` instance on lattice regions: a genuine collar needs a -metric or graph structure on the sites, supplied e.g. through `ProperContainment.ofThicken`. - -Because the quasi-local algebra requires a directed index set, this formulation states the split -property for directed `K` only (Buchholz's double-cone setting); split inclusions of local -algebras over non-directed families (e.g. wedges) can still be stated pointwise through -`VonNeumannAlgebra.IsSplitInclusion`. The representation is not assumed nondegenerate — for -degenerate representations the property can hold trivially, as in the literature, and substantive -downstream theorems impose nondegeneracy or cyclicity where they need it. +it is model-dependent geometric input, like the causal orthogonality `⟂` itself. Its axioms — +containment, monotonicity, and a nondegenerate causal collar inside the outer region — are +necessary conditions rather than a complete axiomatisation of properness, so the split property is +always relative to the chosen `⋐`. They do force `⋐` to be strict (`ProperlyContained.lt`), which +rules out plain containment `⊆`: a reflexive `⋐` would turn the split property into the demand +that every local algebra be a type I factor. Strict containment `⊂` does satisfy all three axioms on +lattice regions — `Λ₂ \ Λ₁` is a collar for it (`ProperContainment.ofSSubset`) — so, unlike +`CausalOrthogonality (Finset α)`, the absence of a canonical `ProperContainment` instance there is a +choice, not an impossibility: `⊂` admits *touching* pairs such as `{0} ⋐ {0, 1}`, which the +literature's closure separation excludes. Separation is what needs a metric or graph structure on +the sites, and it enters through the thickening operator of `ProperContainment.ofThicken`. + +The property is defined at the level of a **net of von Neumann algebras** (`VonNeumannNet`): an +isotone, local assignment `O ↦ 𝓡(O)` over a bare causal index set, with no directedness, no +quasi-local C⋆-algebra and no faithfulness. That is the level at which the index set of the split +property's own literature becomes expressible: the proper intervals of `S¹` are *not* directed +(two intervals covering the circle have no proper upper bound), as Köster's dissertation itself +notes at its definition of a chiral net. Wedges and spacelike cones are further standard +non-directed examples from the wider AQFT literature (not from the sources behind the extraction +note `docs/math/split-inclusion.md`). + +The representation-theoretic net above is one instance of that (`LocalNet.vonNeumannNet`), and +`LocalNet.SplitProperty` is `VonNeumannNet.SplitProperty` at it. The hypotheses +`[IsDirectedOrder K]`, `[Nonempty K]` and `[N.Faithful]` belong to *that instance*, not to the +property: the quasi-local algebra's direct limit needs a directed index set with a base point, and +its C⋆-norm needs injective isotony embeddings. The representation +is not assumed nondegenerate: `𝓡(O)` contains `1` regardless, since a von Neumann algebra is +unital, so a degenerate representation on a nonzero space can satisfy the property trivially +(`𝓡(O) = ℂ1` is a type I factor). On the *zero* space it cannot: a type I factor needs a nonzero +minimal projection, so `IsSplitInclusion` is then identically false. Substantive downstream +theorems impose nondegeneracy or cyclicity where they need it. ## Main definitions and results -* `ProperContainment` — the proper-containment relation `O₁ ⋐ O₂` on a causal index set. -* `LocalNet.localVonNeumannAlgebra` — the local von Neumann algebra `𝓡(O) = π(𝔄(O))″` of a - region in a representation of the quasi-local algebra, with isotony +* `ProperContainment` — the proper-containment relation `O₁ ⋐ O₂` on a causal index set, with + `ProperlyContained.le` / `.mono` / `.exists_orthogonal`, its strictness + (`ProperContainment.irrefl`, `ProperlyContained.lt`), the lattice model + `ProperContainment.ofThicken` built from a strictly enlarging thickening operator, the degenerate + lattice model `ProperContainment.ofSSubset` the axioms cannot exclude, and + `ProperContainment.exists_orthogonal_iff_not_subset`, which measures how much the collar axiom + says on a lattice index set (namely: only strictness). +* `LocalNet.localVonNeumannAlgebra` — the local von Neumann algebra `𝓡(O) = R.π(𝔄(O))″` of a + region in a representation of the quasi-local algebra, containing the represented local + observables (`π_ιLocalCStar_mem_localVonNeumannAlgebra`), with isotony (`localVonNeumannAlgebra_mono`) and locality (`localVonNeumannAlgebra_le_commutant_of_orthogonal`). -* `LocalNet.SplitProperty` — the split property of the net in the representation. -* `LocalNet.SplitProperty.isSplitInclusion` — the split inclusion of a properly contained pair; - Buchholz's tensor splitting between properly separated regions follows by applying - `VonNeumannAlgebra.IsSplitInclusion.exists_tensorDecomposition` to it. +* `VonNeumannNet` — an isotone, local net of von Neumann algebras over a causal index set, and + `VonNeumannNet.SplitProperty` — **the split property**, stated there. Its consequences: + `SplitProperty.isSplitInclusion` (the split inclusion of a properly contained pair; its tensor + splitting follows by applying `VonNeumannAlgebra.IsSplitInclusion.exists_tensor_decomposition` + to it), `SplitProperty.isSplitInclusion_of_le_of_properlyContained_of_le` (stability under + enlarging the pair), and `SplitProperty.isSplitInclusion_commutant` (the commutant form, + Borchers/Buchholz, `𝓡(O₁) ≤ 𝔑 ≤ 𝓡(O_B)′`, obtained from the nested form via locality). + Its degenerate side is `VonNeumannNet.splitProperty_of_complex`: on a one-dimensional Hilbert + space *every* net has the property, so no one-dimensional model is evidence about anything else. +* `LocalNet.vonNeumannNet` — the net of local von Neumann algebras of a representation, as a + `VonNeumannNet`, and `LocalNet.SplitProperty` — the split property at that instance, with the + three consequences above specialised to it. + +## Notation + +`𝔄(O)` and `𝓡(O)` in the prose above are documentation shorthand for the local C⋆-algebra +`N.algebra O` and the local von Neumann algebra `N.localVonNeumannAlgebra R O`; the convention — +and why neither is a Lean notation — is stated in full in `QuantumSystem.Algebra.LocalNet.Net`. + +`⊗̄` is documentation shorthand for the von Neumann (spatial) tensor product of algebras; that +convention is stated in full in `QuantumSystem.Algebra.VonNeumannAlgebra.TensorFactor`, where the +algebras it names (`HilbertTensor.vnTensorLeft` / `vnTensorRight`) are defined. -/ @[expose] public section @@ -56,13 +99,29 @@ open scoped CausalOrthogonality of `O₁` lies in the interior of `O₂`") under which the split property of a local net is stated. This is model-dependent geometric input on the causal index set, like `⟂` itself. - The axioms are necessary conditions, not a complete axiomatisation of properness: containment, - monotonicity under shrinking the inner and enlarging the outer region, and a **causal collar** - — the outer region contains a region causally orthogonal to the inner one - (`exists_orthogonal_of_properlyContained`). On the Haag–Kastler index set of nonempty double - cones the collar axiom expresses genuine properness; on index sets with a region orthogonal - to everything (such as the empty lattice region) it is weaker, and plain containment also - satisfies the axioms — the split property is therefore always relative to the chosen `⋐`. -/ + The axioms are containment, monotonicity under shrinking the inner and enlarging the outer + region, and a **causal collar** (`exists_orthogonal_of_properlyContained`): the outer region + contains a *nondegenerate* region causally orthogonal to the inner one. Nondegeneracy is + expressed as `¬ O₃ ≤ O₁`, the only sense a bare order affords — and it is what the + literature's separation condition actually delivers. Köster's chiral index set defines its own + `I ⋐ S¹` by "its causal complement `I' := S¹ ∖ Ī` is not the empty set", and `Ī₁ ⊂ I₂` with + `I₂` open forces a nonempty component of `I₂ ∖ Ī₁` that is a proper interval inside `I₂`, + disjoint from `I₁` and not contained in it. + + The collar makes `⋐` **irreflexive** (`ProperContainment.irrefl`), indeed strict + (`ProperlyContained.lt`), which is what the literature's typography `Ī₁ ⊂ I₂` is for: without + it plain containment `⊆` would satisfy the axioms, and a reflexive `⋐` would make the split + property demand that every local algebra *be* a type I factor + (`VonNeumannAlgebra.IsSplitInclusion.isTypeIFactor_of_self`) — the opposite of the type III₁ + structure expected of local algebras. The axioms remain necessary conditions rather than a + complete axiomatisation, so the split property is still relative to the chosen `⋐`; what they + now exclude is the degenerate choices. In particular they are *not* enough to exclude + **touching** regions: on a lattice index set the collar clause is equivalent to plain + `¬ Λ₂ ⊆ Λ₁` (`exists_orthogonal_iff_not_subset`), so a model that wants the literature's + separation must build it in — which is what `ofThicken`'s strictly enlarging thickening does. + Nothing forces `⋐` to be inhabited either: on a finite index set with no room for a collar it + is empty and the split property holds vacuously, which is correct — a downstream theorem + needing a genuine pair must say so itself. -/ class ProperContainment (K : Type*) [Preorder K] [CausalOrthogonality K] where /-- The proper-containment relation `O₁ ⋐ O₂` on regions. -/ ProperlyContained : K → K → Prop @@ -72,13 +131,22 @@ class ProperContainment (K : Type*) [Preorder K] [CausalOrthogonality K] where properlyContained_mono : ∀ ⦃O₀ O₁ O₂ O₃ : K⦄, O₀ ≤ O₁ → ProperlyContained O₁ O₂ → O₂ ≤ O₃ → ProperlyContained O₀ O₃ /-- **Causal collar**: a properly containing region contains a region causally orthogonal to - the inner one. -/ + the inner one and not contained in it. The last clause is the nondegeneracy that makes the + collar a genuine buffer rather than a region orthogonal to everything (such as the empty + lattice region); it is what forces `⋐` to be irreflexive. -/ exists_orthogonal_of_properlyContained : ∀ ⦃O₁ O₂ : K⦄, ProperlyContained O₁ O₂ → - ∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ + ∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ ∧ ¬ O₃ ≤ O₁ namespace ProperContainment -/-- `O₁ ⋐ O₂` : the region `O₁` is properly contained in `O₂`. -/ +/-- `O₁ ⋐ O₂` : the region `O₁` is properly contained in `O₂`. + + The glyph is topology's compact-containment symbol, used here for the *binary relation* the + QFT literature writes `Ī₁ ⊂ I₂`. Köster's dissertation uses the same glyph differently: there + `I ⋐ S¹` is a membership predicate ("`I` is a proper interval of `S¹`"), not a relation + between two regions of the index set — a reader coming from that source should not carry the + predicate reading into this notation (extraction note `docs/math/causal-index-set.md`, + convention (C7)). -/ scoped infixl:50 " ⋐ " => ProperContainment.ProperlyContained variable {K : Type*} [Preorder K] [CausalOrthogonality K] [ProperContainment K] @@ -95,40 +163,238 @@ theorem ProperlyContained.mono {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) /-- The causal collar of a proper containment (dot-notation form). -/ theorem ProperlyContained.exists_orthogonal {O₁ O₂ : K} (h : O₁ ⋐ O₂) : - ∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ := + ∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ ∧ ¬ O₃ ≤ O₁ := exists_orthogonal_of_properlyContained h +/-- **Proper containment is irreflexive**: no region is properly contained in itself. This is the + content of the collar's nondegeneracy clause — a collar inside `O` that is not contained in + `O` cannot exist — and it is what the literature's `Ī₁ ⊂ I₂` typography encodes. -/ +theorem irrefl (O : K) : ¬ (O ⋐ O) := by + rintro h + obtain ⟨_, hle, -, hnle⟩ := h.exists_orthogonal + exact hnle hle + +/-- A properly contained region is not above its container. -/ +theorem ProperlyContained.not_ge {O₁ O₂ : K} (h : O₁ ⋐ O₂) : ¬ O₂ ≤ O₁ := + fun hge => irrefl O₁ (h.mono le_rfl hge) + +/-- **Proper containment is strict**: `O₁ ⋐ O₂` implies `O₁ < O₂`. -/ +theorem ProperlyContained.lt {O₁ O₂ : K} (h : O₁ ⋐ O₂) : O₁ < O₂ := + lt_of_le_not_ge h.le h.not_ge + +/-- A thickening operator that strictly enlarges every nonempty region is enlarging on every + region: on the empty region `∅ ⊆ thicken ∅` is automatic. -/ +lemma subset_thicken_of_ssubset {α : Type*} {thicken : Finset α → Finset α} + (ssubset_thicken : ∀ Λ : Finset α, Λ.Nonempty → Λ ⊂ thicken Λ) (Λ : Finset α) : + Λ ⊆ thicken Λ := by + rcases Λ.eq_empty_or_nonempty with rfl | hne + · exact Finset.empty_subset _ + · exact (ssubset_thicken Λ hne).subset + +/-- **On lattice regions the collar clause says only that `Λ₂` is not contained in `Λ₁`.** With + `⟂ = Disjoint` on `Finset α` the region `Λ₂ \ Λ₁` is automatically orthogonal to `Λ₁`, so it + witnesses the collar as soon as it is nonempty; conversely a collar inside `Λ₂` that is not + inside `Λ₁` forbids `Λ₂ ⊆ Λ₁`. + + This is worth stating because it bounds what the `ProperContainment` axioms can be asked to + do. On a lattice index set they pin down strictness and nothing more: they do **not** by + themselves exclude *touching* pairs such as `{0} ⋐ {0, 1}`, which the literature does exclude + (a pair of local algebras of touching regions is not statistically independent, hence not + split — Buchholz's *Product states for local algebras* records that postulating normal product + states for touching regions already yields contradictions for the free field, the corpus's one + statement that the closure separation is *necessary*). + Genuine separation is therefore the model's job, not the class's — see `ofThicken`, + whose thickening operator supplies a buffer layer between `Λ₁` and the collar. -/ +lemma exists_orthogonal_iff_not_subset {α : Type*} {Λ₁ Λ₂ : Finset α} : + (∃ Λ₃ : Finset α, Λ₃ ≤ Λ₂ ∧ Λ₁ ⟂ Λ₃ ∧ ¬ Λ₃ ≤ Λ₁) ↔ ¬ Λ₂ ⊆ Λ₁ := by + classical + constructor + · rintro ⟨Λ₃, hle, -, hnle⟩ hsub + exact hnle (hle.trans hsub) + · intro hns + refine ⟨Λ₂ \ Λ₁, Finset.sdiff_subset, Finset.disjoint_sdiff, ?_⟩ + obtain ⟨x, hx₂, hx₁⟩ := Finset.not_subset.1 hns + exact fun hsub => hx₁ (hsub (Finset.mem_sdiff.2 ⟨hx₂, hx₁⟩)) + +/-- **Strict containment already satisfies the axioms**, on any lattice index set and with no + structure on the sites: containment and monotonicity are immediate, and `Λ₂ \ Λ₁` is a collar + (`exists_orthogonal_iff_not_subset`). So nothing in the class *prevents* a canonical lattice + instance — what it fails to deliver is separation, and this model is the witness of that + failure: it admits the *touching* pair `{0} ⋐ {0, 1}`, whose local algebras the literature + records as not statistically independent, hence not split. + + Deliberately a `def` rather than an `instance`, and never activated anywhere: it exists to + exhibit the gap, not to be used. A model that wants separation supplies a thickening operator + (`ofThicken`). -/ +@[reducible] def ofSSubset (α : Type*) : ProperContainment (Finset α) where + ProperlyContained Λ₁ Λ₂ := Λ₁ ⊂ Λ₂ + le_of_properlyContained _ _ h := le_of_lt h + properlyContained_mono _ _ _ _ h₀ h h₃ := (h₀.trans_lt h).trans_le h₃ + exists_orthogonal_of_properlyContained _ _ h := + exists_orthogonal_iff_not_subset.2 fun hsub => absurd (h.subset.antisymm hsub) (ne_of_lt h) + /-- Proper containment of lattice regions from a **thickening operator** (e.g. the - `r`-neighbourhood for a metric or graph structure on the sites): `Λ₁ ⋐ Λ₂` iff the - thickening of `Λ₁` still lies in `Λ₂`. The causal collar is the genuine one, - `Λ₂ \ thicken Λ₁`. -/ + `r`-neighbourhood for a metric or graph structure on the sites): `Λ₁ ⋐ Λ₂` iff the thickening + of `Λ₁` is a *strict* subset of `Λ₂`. + + The thickening is required to be *strictly* enlarging on nonempty regions + (`ssubset_thicken`). What that buys is the chain `Λ₁ ⊊ thicken Λ₁ ⊆ Λ₂` under `Λ₁ ⋐ Λ₂`, with + the collar `Λ₂ \ thicken Λ₁` disjoint from the whole of `thicken Λ₁` rather than merely from + `Λ₁`: the collar is separated from `Λ₁` *by the thickening's own notion of nearness*. + + Whether that is geometric separation is the thickening's business and is **not** a consequence + of the two hypotheses. The one-sided `thicken Λ = Λ ∪ Λ.image (· + 1)` is monotone and strictly + enlarging, yet `{0} ⋐ {-1, 0, 1, 2}` has collar `{-1, 2}`, which touches `{0}` from below. A + thickening that is a genuine neighbourhood operator — enlarging in *every* direction of + adjacency, as the 1-neighbourhood `ProperContainment.nbhd` of the integer chain is in + `QuantumSystem.Algebra.LocalNet.Examples` — does exclude *touching* pairs, which is the + exclusion the literature's `Ī₁ ⊂ I₂` typography performs and one the class axioms alone cannot + perform on a lattice (`exists_orthogonal_iff_not_subset`). What strictness rules out by itself + is `thicken := id`, i.e. the degenerate model `ofSSubset`, in which `{0} ⋐ {0, 1}` is admitted. + + On the empty region no strictness is asked, since a neighbourhood operator has + `thicken ∅ = ∅`; `∅ ⊆ thicken ∅` holds regardless and is all the axioms need there. -/ @[reducible] def ofThicken {α : Type*} [DecidableEq α] (thicken : Finset α → Finset α) - (subset_thicken : ∀ Λ, Λ ⊆ thicken Λ) (thicken_mono : Monotone thicken) : + (ssubset_thicken : ∀ Λ : Finset α, Λ.Nonempty → Λ ⊂ thicken Λ) + (thicken_mono : Monotone thicken) : ProperContainment (Finset α) where - ProperlyContained Λ₁ Λ₂ := thicken Λ₁ ⊆ Λ₂ - le_of_properlyContained _ _ h := (subset_thicken _).trans h - properlyContained_mono _ _ _ _ h₀ h h₃ := ((thicken_mono h₀).trans h).trans h₃ - exists_orthogonal_of_properlyContained Λ₁ Λ₂ _ := - ⟨Λ₂ \ thicken Λ₁, Finset.sdiff_subset, - Finset.disjoint_sdiff.mono_left (subset_thicken Λ₁)⟩ + ProperlyContained Λ₁ Λ₂ := thicken Λ₁ ⊂ Λ₂ + le_of_properlyContained _ _ h := (subset_thicken_of_ssubset ssubset_thicken _).trans h.subset + properlyContained_mono _ _ _ _ h₀ h h₃ := ((thicken_mono h₀).trans_lt h).trans_le h₃ + exists_orthogonal_of_properlyContained Λ₁ Λ₂ h := by + refine ⟨Λ₂ \ thicken Λ₁, Finset.sdiff_subset, + Finset.disjoint_sdiff.mono_left (subset_thicken_of_ssubset ssubset_thicken Λ₁), ?_⟩ + obtain ⟨x, hx₂, hx₁⟩ := Finset.exists_of_ssubset h + exact fun hsub => + hx₁ (subset_thicken_of_ssubset ssubset_thicken Λ₁ (hsub (Finset.mem_sdiff.2 ⟨hx₂, hx₁⟩))) end ProperContainment +/-! ### Nets of von Neumann algebras + +The split property is a statement about a net of *von Neumann* algebras, and it is stated here at +that level. A `VonNeumannNet` is an isotone, local assignment `O ↦ 𝓡(O)` of von Neumann algebras +on a fixed Hilbert space over a bare causal index set: no directedness, no quasi-local C⋆-algebra, +no faithfulness — none of which the property mentions. Non-directed index sets are therefore in +scope — as they must be: the proper intervals of `S¹`, the index set of the chiral split property, +are not directed (two intervals covering the circle have no *proper* upper bound), a point Köster's +dissertation makes explicitly. Wedges and spacelike cones are further standard non-directed +examples from the wider AQFT literature. + +The net of local von Neumann algebras of a representation of the quasi-local C⋆-algebra is one +instance (`LocalNet.vonNeumannNet`), and `LocalNet.SplitProperty` is this property at that +instance. +-/ + +open scoped ProperContainment VonNeumannAlgebra + +/-- A **net of von Neumann algebras** over a causal index set `K`, acting on a fixed Hilbert space + `H`: the assignment `O ↦ 𝓡(O)` together with **isotony** (`algebra_mono`) and **locality** + (`algebra_le_commutant_of_orthogonal`, Einstein causality `𝓡(O₁) ≤ 𝓡(O₂)′` for `O₁ ⟂ O₂`). + + This is the level at which the split property is stated in the literature — Buchholz's local + rings `𝓡(O)`, Doplicher–Longo's `W*`-inclusions, Köster's chiral nets assigning a von Neumann + algebra to each proper interval. The index set carries only a `Preorder` and `⟂`; in + particular it is not assumed directed, so the index sets those sources use are expressible. -/ +structure VonNeumannNet (K : Type*) [Preorder K] [CausalOrthogonality K] + (H : Type*) [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] where + /-- The local von Neumann algebra `𝓡(O)` assigned to a region. -/ + algebra : K → VonNeumannAlgebra H + /-- **Isotony**: a larger region carries a larger algebra. -/ + algebra_mono : Monotone algebra + /-- **Locality** (microcausality): causally orthogonal regions carry commuting algebras. -/ + algebra_le_commutant_of_orthogonal : ∀ ⦃O₁ O₂ : K⦄, O₁ ⟂ O₂ → algebra O₁ ≤ (algebra O₂)′ + +namespace VonNeumannNet + +variable {K : Type*} [Preorder K] [CausalOrthogonality K] +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- **The split property** of a net of von Neumann algebras (Buchholz; Doplicher–Longo): for every + properly contained pair of regions `O₁ ⋐ O₂`, some type I factor interpolates between the + local algebras, `𝓡(O₁) ≤ 𝔑 ≤ 𝓡(O₂)`. This is genuinely model-dependent input — it fails for + nets without the requisite phase-space (nuclearity) behaviour — and it is relative to the + chosen proper containment `⋐` (see `ProperContainment`). + + This is the *nested* form. The historically original *commutant* form is + `SplitProperty.isSplitInclusion_commutant`, which follows from this one through locality; the + converse needs Haag duality and is not available here. -/ +def SplitProperty [ProperContainment K] (vnNet : VonNeumannNet K H) : Prop := + ∀ ⦃O₁ O₂ : K⦄, O₁ ⋐ O₂ → + VonNeumannAlgebra.IsSplitInclusion (vnNet.algebra O₁) (vnNet.algebra O₂) + +/-- **Every net of von Neumann algebras on `ℂ` has the split property** — whatever the net, + whatever the proper containment. On the one-dimensional Hilbert space the only von Neumann + algebra is `𝓑(ℂ)` (`VonNeumannAlgebra.eq_boundedLinearOperators_complex`), a type I factor, so + every inclusion of the net is the split inclusion `𝓑(ℂ) ≤ 𝓑(ℂ)`. + + Stated here, rather than left implicit inside a witness, because it fixes what a + one-dimensional model can be evidence *for*: it inhabits `SplitProperty` and distinguishes + nothing — no net, no representation, no choice of `⋐`. The degeneracy is `dim H = 1` and + nothing else; it is the escape clause Halvorson–Müger's type III₁ proposition carries + explicitly ("either `𝓡 = ℂ1` or `𝓡` is a type III₁ factor"). -/ +theorem splitProperty_of_complex [ProperContainment K] (vnNet : VonNeumannNet K ℂ) : + vnNet.SplitProperty := by + intro O₁ O₂ _ + rw [VonNeumannAlgebra.eq_boundedLinearOperators_complex (vnNet.algebra O₁), + VonNeumannAlgebra.eq_boundedLinearOperators_complex (vnNet.algebra O₂)] + exact (VonNeumannAlgebra.isTypeIFactor_boundedLinearOperators (H := ℂ)).isSplitInclusion_self + +variable [ProperContainment K] {vnNet : VonNeumannNet K H} + +/-- **The split inclusion of a properly contained pair**: under the split property, `O₁ ⋐ O₂` + yields the split inclusion `𝓡(O₁) ≤ 𝓡(O₂)`. Buchholz's tensor splitting — a unitary + `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` carrying `𝓡(O₁)` into the tensor factor `𝓑(ℓ²(F)) ⊗̄ 1` and the + commutant `𝓡(O₂)′` into `1 ⊗̄ 𝓑(eH)`, with the interpolating type I factor and its commutant + identified exactly — is obtained by applying + `VonNeumannAlgebra.IsSplitInclusion.exists_tensor_decomposition` to the conclusion. -/ +theorem SplitProperty.isSplitInclusion (hs : vnNet.SplitProperty) {O₁ O₂ : K} (h : O₁ ⋐ O₂) : + VonNeumannAlgebra.IsSplitInclusion (vnNet.algebra O₁) (vnNet.algebra O₂) := + hs h + +/-- The split property extends to enlarged pairs: if `O₀ ≤ O₁ ⋐ O₂ ≤ O₃` then the inclusion + `𝓡(O₀) ≤ 𝓡(O₃)` is split as well. -/ +lemma SplitProperty.isSplitInclusion_of_le_of_properlyContained_of_le (hs : vnNet.SplitProperty) + {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) (h₃ : O₂ ≤ O₃) : + VonNeumannAlgebra.IsSplitInclusion (vnNet.algebra O₀) (vnNet.algebra O₃) := + hs (h.mono h₀ h₃) + +/-- **The commutant form of the split property** (Borchers' conjecture as displayed in Buchholz, + *Product states for local algebras*): for a properly contained pair `O₁ ⋐ O₂` and any region + `O_B` causally orthogonal to `O₂`, a type I factor interpolates between `𝓡(O₁)` and the + commutant `𝓡(O_B)′`, + + `𝓡(O₁) ≤ 𝔑 ≤ 𝓡(O_B)′`. + + This is the historically original shape of the property, for a *disjoint* pair with slack + rather than a nested one. The nested form implies it through locality + (`algebra_le_commutant_of_orthogonal`); the converse needs Haag duality, which is not assumed + anywhere here. Buchholz displays the symmetric four-term chain `𝓡(O₁) ⊂ M₁ ⊂ M₂′ ⊂ 𝓡(O₂)′` + with two interpolating type I factors; this is its one-sided compression, which is the form + the adopted definition of a split inclusion carries. -/ +theorem SplitProperty.isSplitInclusion_commutant (hs : vnNet.SplitProperty) {O₁ O₂ O_B : K} + (h : O₁ ⋐ O₂) (hd : O₂ ⟂ O_B) : + VonNeumannAlgebra.IsSplitInclusion (vnNet.algebra O₁) (vnNet.algebra O_B)′ := + (hs h).mono le_rfl (vnNet.algebra_le_commutant_of_orthogonal hd) + +end VonNeumannNet + namespace LocalNet open scoped ProperContainment VonNeumannAlgebra section LocalAlgebras -variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] +variable {K : Type*} [Preorder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] variable (N : LocalNet K) [N.Faithful] -/-- The **local von Neumann algebra** `𝓡(O) = π(𝔄(O))″` of a region in a representation of the +/-- The **local von Neumann algebra** `𝓡(O) = R.π(𝔄(O))″` of a region in a representation of the quasi-local C⋆-algebra: the von Neumann algebra generated by the image of the local algebra. - The generating set is star-closed (`𝔄(O)` is star-closed, and the embedding and `π` are - `*`-maps), so `VonNeumannAlgebra.generated` — which symmetrizes in general — is literally the - double commutant `π(𝔄(O))″` here. Since `π` is a possibly non-unital `*`-homomorphism, - `𝓡(O)` always contains `1` even when `π(𝔄(O))` does not, matching the `″` convention. -/ + The generating set is star-closed (`star_range_π_ιLocalCStar`), so + `VonNeumannAlgebra.generated` — which symmetrizes in general — is literally the double + commutant here (`coe_localVonNeumannAlgebra`). Since `R.π` is a possibly non-unital + `*`-homomorphism, `𝓡(O)` always contains `1` even when `R.π(𝔄(O))` does not, matching the `″` + convention. -/ noncomputable def localVonNeumannAlgebra (R : CStarRep N.quasiLocalCStarAlgebra) (O : K) : VonNeumannAlgebra R.H := VonNeumannAlgebra.generated (Set.range fun a : N.algebra O => R.π (N.ιLocalCStar O a)) @@ -138,6 +404,23 @@ lemma π_ιLocalCStar_mem_localVonNeumannAlgebra (R : CStarRep N.quasiLocalCStar (a : N.algebra O) : R.π (N.ιLocalCStar O a) ∈ N.localVonNeumannAlgebra R O := VonNeumannAlgebra.mem_generated_of_mem ⟨a, rfl⟩ +/-- The generating set of `𝓡(O)` is star-closed: `𝔄(O)` is star-closed, and both the embedding + into the quasi-local algebra and `R.π` are `*`-maps, so `Set.star_range` applies to the + composite. -/ +lemma star_range_π_ιLocalCStar (R : CStarRep N.quasiLocalCStarAlgebra) (O : K) : + star (Set.range fun a : N.algebra O => R.π (N.ιLocalCStar O a)) + = Set.range fun a : N.algebra O => R.π (N.ιLocalCStar O a) := + Set.star_range fun a => by rw [N.ιLocalCStar_star, map_star] + +/-- **`𝓡(O)` is literally the double commutant `R.π(𝔄(O))″`.** `VonNeumannAlgebra.generated` + symmetrizes its generating set in general; here the set is already star-closed + (`star_range_π_ιLocalCStar`), so no symmetrization happens and the definition agrees with the + `″` of the operator-algebra literature. -/ +lemma coe_localVonNeumannAlgebra (R : CStarRep N.quasiLocalCStarAlgebra) (O : K) : + (N.localVonNeumannAlgebra R O : Set (R.H →L[ℂ] R.H)) + = (Set.range fun a : N.algebra O => R.π (N.ιLocalCStar O a)).centralizer.centralizer := + VonNeumannAlgebra.coe_generated_of_star_eq (N.star_range_π_ιLocalCStar R O) + /-- **Isotony** of the local von Neumann algebras: `O ≤ O'` gives `𝓡(O) ≤ 𝓡(O')`. -/ lemma localVonNeumannAlgebra_mono (R : CStarRep N.quasiLocalCStarAlgebra) {O O' : K} (h : O ≤ O') : N.localVonNeumannAlgebra R O ≤ N.localVonNeumannAlgebra R O' := by @@ -165,46 +448,74 @@ lemma localVonNeumannAlgebra_le_commutant_of_orthogonal (R : CStarRep N.quasiLoc exact (N.ιLocalCStar_commute_of_orthogonal hd.symm (star b) a).map R.π exact key.trans_eq (VonNeumannAlgebra.commutant_generated _).symm +/-- **The net of local von Neumann algebras** of a representation, as a `VonNeumannNet`: isotony + is `localVonNeumannAlgebra_mono` and locality is + `localVonNeumannAlgebra_le_commutant_of_orthogonal`, both already proved. This is the bridge + from the C⋆-level net data to the von-Neumann-level object the split property is about. -/ +noncomputable def vonNeumannNet (R : CStarRep N.quasiLocalCStarAlgebra) : + VonNeumannNet K R.H where + algebra := N.localVonNeumannAlgebra R + algebra_mono _ _ h := N.localVonNeumannAlgebra_mono R h + algebra_le_commutant_of_orthogonal _ _ hd := + N.localVonNeumannAlgebra_le_commutant_of_orthogonal R hd + +/-- The algebras of the net `vonNeumannNet R` are the local von Neumann algebras themselves. -/ +@[simp] lemma vonNeumannNet_algebra (R : CStarRep N.quasiLocalCStarAlgebra) (O : K) : + (N.vonNeumannNet R).algebra O = N.localVonNeumannAlgebra R O := rfl + /-- **The split property** of a local net in a representation `π` of the quasi-local C⋆-algebra - (Buchholz; Doplicher–Longo): for every properly contained pair of regions `O₁ ⋐ O₂`, some - type I factor interpolates between the local von Neumann algebras, - `𝓡(O₁) ≤ M ≤ 𝓡(O₂)`. This is genuinely model-dependent input — it fails for nets without - the requisite phase-space (nuclearity) behaviour — and it is relative to the chosen proper - containment `⋐` (see `ProperContainment`). -/ + (Buchholz; Doplicher–Longo): the split property of the associated net of local von Neumann + algebras (`VonNeumannNet.SplitProperty`) — for every properly contained pair of regions + `O₁ ⋐ O₂`, some type I factor interpolates, `𝓡(O₁) ≤ M ≤ 𝓡(O₂)`. + + The property itself is defined at the von-Neumann-net level, where it needs neither a + directed index set nor a quasi-local C⋆-algebra; the hypotheses `[IsDirectedOrder K]`, + `[Nonempty K]` and `[N.Faithful]` here are the cost of *this instance*, whose local algebras + are built from a representation of the quasi-local C⋆-algebra. Nets over non-directed index + sets are stated through `VonNeumannNet.SplitProperty` directly. -/ def SplitProperty [ProperContainment K] (R : CStarRep N.quasiLocalCStarAlgebra) : Prop := - ∀ ⦃O₁ O₂ : K⦄, O₁ ⋐ O₂ → - VonNeumannAlgebra.IsSplitInclusion - (N.localVonNeumannAlgebra R O₁) (N.localVonNeumannAlgebra R O₂) + (N.vonNeumannNet R).SplitProperty end LocalAlgebras section SplitConsequences -variable {K : Type*} [PartialOrder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] +variable {K : Type*} [Preorder K] [CausalOrthogonality K] [IsDirectedOrder K] [Nonempty K] variable [ProperContainment K] {N : LocalNet K} [N.Faithful] variable {R : CStarRep N.quasiLocalCStarAlgebra} /-- The split property extends to enlarged pairs: if `O₀ ≤ O₁ ⋐ O₂ ≤ O₃` then the inclusion - `𝓡(O₀) ≤ 𝓡(O₃)` is split as well. -/ + `𝓡(O₀) ≤ 𝓡(O₃)` is split as well. Specialisation of + `VonNeumannNet.SplitProperty.isSplitInclusion_of_le_of_properlyContained_of_le`. -/ lemma SplitProperty.isSplitInclusion_of_le_of_properlyContained_of_le (hs : N.SplitProperty R) {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) (h₃ : O₂ ≤ O₃) : VonNeumannAlgebra.IsSplitInclusion (N.localVonNeumannAlgebra R O₀) (N.localVonNeumannAlgebra R O₃) := - hs (h.mono h₀ h₃) + VonNeumannNet.SplitProperty.isSplitInclusion_of_le_of_properlyContained_of_le hs h₀ h h₃ -/-- **Buchholz's tensor splitting between properly separated regions**, in split-inclusion form: - under the split property, every properly contained pair `O₁ ⋐ O₂` yields the split inclusion - `𝓡(O₁) ≤ 𝓡(O₂)`, whose full tensor splitting — a unitary `U : H ≃ₗᵢ ℓ²(F) ⊗̂ (eH)` carrying - `𝓡(O₁)` into the tensor factor `B(ℓ²(F)) ⊗̄ 1` and the dual algebra `𝓡(O₂)′` into - `1 ⊗̄ B(eH)`, with the interpolating type I factor and its commutant identified exactly — is - obtained by applying `VonNeumannAlgebra.IsSplitInclusion.exists_tensorDecomposition` to the - conclusion. (The instantiated existential is deliberately not restated here: spelling it out +/-- **The split inclusion of a properly contained pair**: under the split property, `O₁ ⋐ O₂` + yields the split inclusion `𝓡(O₁) ≤ 𝓡(O₂)`. Specialisation of + `VonNeumannNet.SplitProperty.isSplitInclusion`, whose docstring describes the tensor splitting + that follows. (The instantiated existential is deliberately not restated here: spelling it out over `R.H` forces the elaborator to unfold the quasi-local algebra inside `R`'s type, while consuming the general statement through this corollary is cheap.) -/ theorem SplitProperty.isSplitInclusion (hs : N.SplitProperty R) {O₁ O₂ : K} (h : O₁ ⋐ O₂) : VonNeumannAlgebra.IsSplitInclusion (N.localVonNeumannAlgebra R O₁) (N.localVonNeumannAlgebra R O₂) := - hs h + VonNeumannNet.SplitProperty.isSplitInclusion hs h + +/-- **The commutant form of the split property** (Borchers' conjecture as displayed in Buchholz, + *Product states for local algebras*): for a properly contained pair `O₁ ⋐ O₂` and any region + `O_B` causally orthogonal to `O₂`, a type I factor interpolates between `𝓡(O₁)` and the + commutant `𝓡(O_B)′`. Specialisation of + `VonNeumannNet.SplitProperty.isSplitInclusion_commutant`, whose docstring records what the + converse would need (Haag duality) and how this one-sided form relates to Buchholz's + symmetric four-term chain. -/ +theorem SplitProperty.isSplitInclusion_commutant (hs : N.SplitProperty R) {O₁ O₂ O_B : K} + (h : O₁ ⋐ O₂) (hd : O₂ ⟂ O_B) : + VonNeumannAlgebra.IsSplitInclusion + (N.localVonNeumannAlgebra R O₁) (N.localVonNeumannAlgebra R O_B)′ := + VonNeumannNet.SplitProperty.isSplitInclusion_commutant hs h hd end SplitConsequences From 9bc1131778b730a0fc463f5d0ef5d96ebfdcf716 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:43:52 +0000 Subject: [PATCH 100/113] feat: add witnesses for the local-net interfaces Inhabits every class/structure the local-net development introduces: ProperContainment.integerChain (a separating causal collar), trivialNet/ scalarNet/unitalRep/zeroHom (faithful nets and split-property instances), so the interfaces are not vacuously satisfiable. Registers the new module in the aggregate root. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- QuantumSystem.lean | 1 + QuantumSystem/Algebra/LocalNet/Examples.lean | 320 +++++++++++++++++++ 2 files changed, 321 insertions(+) create mode 100644 QuantumSystem/Algebra/LocalNet/Examples.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 16db151..836e01b 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -18,6 +18,7 @@ public import QuantumSystem.Algebra.CStarAlgebra.State public import QuantumSystem.Algebra.CStarAlgebra.State.Continuity public import QuantumSystem.Algebra.CStarAlgebra.State.Faithful public import QuantumSystem.Algebra.LocalNet.Covariance +public import QuantumSystem.Algebra.LocalNet.Examples public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.LocalNet.SplitProperty diff --git a/QuantumSystem/Algebra/LocalNet/Examples.lean b/QuantumSystem/Algebra/LocalNet/Examples.lean new file mode 100644 index 0000000..aa31524 --- /dev/null +++ b/QuantumSystem/Algebra/LocalNet/Examples.lean @@ -0,0 +1,320 @@ +module + +public import QuantumSystem.Algebra.LocalNet.SplitProperty + +/-! +# Witnesses for the local-net interfaces + +Every class and structure the local-net development introduces is inhabited here, by explicit +construction. Without such witnesses the theorems of `LocalNet.Net`, `LocalNet.QuasiLocalAlgebra` +and `LocalNet.SplitProperty` would be unfalsifiable: nobody could apply them, and no construction +could contradict them. In particular the split property, being a `Prop`-valued hypothesis that +nothing in the development proves, needs a model exhibited before it can be believed consistent. + +The witnesses are deliberately the smallest ones that are not degenerate in the way that matters. + +* **A separating proper containment.** `ProperContainment.integerChain` is the 1-neighbourhood + thickening on the integer chain, `Λ₁ ⋐ Λ₂` iff `nbhd Λ₁ ⊊ Λ₂`. What makes it *separating* is that + `nbhd` enlarges in both directions, so the collar `Λ₂ \ nbhd Λ₁` can touch `Λ₁` from neither side + and *touching* pairs are excluded. Strict enlargement alone would not do this — see the docstring + of `ProperContainment.ofThicken`, and `ProperContainment.ofSSubset` for the degenerate model the + class axioms admit. `ProperContainment.properlyContained_singleton` exhibits an actual pair, so + `⋐` is not empty and the split property below is not vacuously true. +* **A faithful local net.** `LocalNet.Examples.trivialNet` assigns `ℂ` to every region of the + integer chain, with identity isotony embeddings, built through the join-semilattice smart + constructor `LocalNet.mk'`; its `Faithful` instance is immediate. +* **A net of von Neumann algebras with the split property.** + `LocalNet.Examples.scalarNet` is the constant net at `𝓑(ℂ)`, and + `LocalNet.Examples.scalarNet_splitProperty` proves `VonNeumannNet.SplitProperty` for it. Locality + holds because bounded operators on `ℂ` commute. +* **The split property at the representation level, in two representations.** + `LocalNet.Examples.trivialNet_splitProperty` proves `LocalNet.SplitProperty` for `trivialNet` in + the *zero* representation on `ℂ`, and `LocalNet.Examples.unitalRep_splitProperty` in the *unital* + representation `LocalNet.Examples.unitalRep`, which sends `1` to `1` + (`LocalNet.Examples.unitalRep_π_one`). The second is there because the first alone would leave + the representation-level interface inhabited only by a degenerate `π`. +* **A refuter.** All the witnesses here inhabit the *positive* side of the interfaces; the negation + of `IsSplitInclusion` is kept inhabited by `VonNeumannAlgebra.not_isSplitInclusion_diagonalAlgebra` + (in `QuantumSystem.Algebra.VonNeumannAlgebra.SplitInclusion`, next to the predicate it refutes). + +What is deliberately *not* built here is a spin-system net with genuine tensor-product local +algebras — the physically interesting lattice model the module docs of `LocalNet.Net` and +`LocalNet.Covariance` describe. That is a construction in its own right, not a witness; these +witnesses establish consistency and applicability of the interfaces, nothing more. + +**The residual degeneracy, stated so it is not mistaken for evidence.** Every Hilbert space +appearing below is `ℂ`, and on `ℂ` the split property is *automatic*: the only von Neumann algebra +there is `𝓑(ℂ)` (`VonNeumannAlgebra.eq_boundedLinearOperators_complex`), so every net of von +Neumann algebras on `ℂ` splits (`VonNeumannNet.splitProperty_of_complex`), and both +representation-level witnesses below are instances of that one theorem. So the degeneracy is +`dim H = 1` — *not* the zero representation, which is why exchanging it for a unital one changes +nothing mathematically. This is the one reason the literature explicitly sets aside: +Halvorson–Müger's type III₁ proposition carries the escape clause "either `𝓡 = ℂ1` or `𝓡` is a +type III₁ factor", and a reflexive proper containment is rejected precisely because it would force +every local algebra to be type I. These witnesses show the interfaces are inhabited and applicable; +they are **not** evidence about nets whose local algebras are type III₁, and no argument should +treat them as such. The degeneracy is also forced rather than chosen at the C⋆ level: over +`Finset ℤ` with `⟂ = Disjoint`, any two disjoint regions lie under their union, so locality makes +every *constant* net commutative — a noncommutative witness needs the tensor-product net descoped +above. +-/ + +@[expose] public section + +open scoped CausalOrthogonality ProperContainment VonNeumannAlgebra + +namespace ProperContainment + +/-! ### A separating proper containment on the integer chain -/ + +/-- The **1-neighbourhood** of a finite set of integer sites: the region together with its two + neighbouring layers. This is the thickening operator of a nearest-neighbour spin chain. -/ +def nbhd (Λ : Finset ℤ) : Finset ℤ := Λ ∪ Λ.image (· - 1) ∪ Λ.image (· + 1) + +/-- A region is contained in its 1-neighbourhood. -/ +lemma subset_nbhd (Λ : Finset ℤ) : Λ ⊆ nbhd Λ := + fun _ hx => Finset.mem_union_left _ (Finset.mem_union_left _ hx) + +/-- The 1-neighbourhood is monotone. -/ +lemma monotone_nbhd : Monotone nbhd := fun _ _ h => + Finset.union_subset_union (Finset.union_subset_union h (Finset.image_subset_image h)) + (Finset.image_subset_image h) + +/-- The 1-neighbourhood **strictly** enlarges every nonempty region: it adds the site just above + the largest one. This is the hypothesis `ProperContainment.ofThicken` needs. -/ +lemma ssubset_nbhd (Λ : Finset ℤ) (hne : Λ.Nonempty) : Λ ⊂ nbhd Λ := by + refine (Finset.ssubset_iff_of_subset (subset_nbhd Λ)).2 ⟨Λ.max' hne + 1, ?_, ?_⟩ + · exact Finset.mem_union_right _ (Finset.mem_image.2 ⟨Λ.max' hne, Λ.max'_mem hne, rfl⟩) + · exact fun hmem => absurd (Λ.le_max' _ hmem) (by omega) + +/-- **The 1-neighbourhood absorbs both neighbours of every site of the region.** This — and not + the strict enlargement `ssubset_nbhd` — is what makes the induced proper containment + *separating*: the collar `Λ₂ \ nbhd Λ₁` avoids `nbhd Λ₁`, hence contains no site adjacent to + `Λ₁` on either side. A one-sided thickening satisfies the hypotheses of `ofThicken` just as + well and does not have this property. -/ +lemma add_mem_nbhd_of_mem {Λ : Finset ℤ} {x : ℤ} (hx : x ∈ Λ) (d : ℤ) (hd : d = 1 ∨ d = -1) : + x + d ∈ nbhd Λ := by + rcases hd with rfl | rfl + · exact Finset.mem_union_right _ (Finset.mem_image.2 ⟨x, hx, rfl⟩) + · exact Finset.mem_union_left _ + (Finset.mem_union_right _ (Finset.mem_image.2 ⟨x, hx, by omega⟩)) + +/-- **Proper containment on the integer chain**: `Λ₁ ⋐ Λ₂` iff the 1-neighbourhood of `Λ₁` is a + strict subset of `Λ₂`. The buffer layer `nbhd Λ₁ \ Λ₁` separates `Λ₁` from the collar on both + sides (`add_mem_nbhd_of_mem`), so touching pairs — which the literature excludes, since local + algebras of touching regions are not statistically independent — do not satisfy this relation. + + Deliberately a `def` rather than a global `instance`: this file is re-exported by the aggregate + root, so a global instance would silently resolve every downstream `⋐` on `Finset ℤ` to the + nearest-neighbour relation of this one witness. It is activated by `attribute [local instance]` + where this file needs it; a model that wants it elsewhere says so, either the same way or by + rebuilding it from the public `nbhd`, `ssubset_nbhd` and `monotone_nbhd`. -/ +@[reducible] noncomputable def integerChain : ProperContainment (Finset ℤ) := + ProperContainment.ofThicken nbhd ssubset_nbhd monotone_nbhd + +attribute [local instance] integerChain + +/-- **`⋐` is inhabited on the integer chain**: the single site `{0}`, whose 1-neighbourhood is + `{-1, 0, 1}`, is properly contained in `{-2, -1, 0, 1, 2}`. Recorded so that the split property + over this index set is not vacuously true. -/ +lemma properlyContained_singleton : ({0} : Finset ℤ) ⋐ ({-2, -1, 0, 1, 2} : Finset ℤ) := by + change nbhd {0} ⊂ ({-2, -1, 0, 1, 2} : Finset ℤ) + decide + +end ProperContainment + +namespace LocalNet.Examples + +attribute [local instance] ProperContainment.integerChain + +/-! ### A faithful local net -/ + +/-- The **trivial local net** over the integer chain: every region carries the C⋆-algebra `ℂ`, and + every isotony embedding is the identity. Locality holds because `ℂ` is commutative, and is + supplied only for the join region `Λ₁ ∪ Λ₂` — the smart constructor `LocalNet.mk'` pushes it + forward to every common superregion. -/ +noncomputable def trivialNet : LocalNet (Finset ℤ) := + LocalNet.mk' (fun _ : Finset ℤ => ℂ) (fun _ => StarAlgHom.id ℂ ℂ) (fun _ => rfl) + (fun _ _ _ => rfl) (fun _ x y => mul_comm x y) + +/-- The trivial net is faithful: its isotony embeddings are identities. -/ +instance : trivialNet.Faithful where + incl_injective _ := fun _ _ h => h + +/-! ### A covariance moving the regions -/ + +/-- **The unit translation of the integer chain**, as a covariance of the trivial net: the site + permutation `x ↦ x + 1` induces the region automorphism `Λ ↦ Λ + 1`, and every local algebra + being `ℂ` the covariance `*`-isomorphisms are identities. + + This is the witness that makes the covariance API testable. `LocalNet.Covariance.id` inhabits + the structure, but at the identity region map every naturality square of `Covariance` closes by + `rfl` and `Covariance.sitePerm`, `Covariance.exists_sitePerm` and + `Covariance.exists_eq_ofSitePerm` all speak about the trivial permutation. Here the region map + genuinely moves (`σ_shiftCovariance`), so those statements have content. -/ +noncomputable def shiftCovariance : trivialNet.Covariance := + LocalNet.Covariance.ofSitePerm (N := trivialNet) (Equiv.addRight (1 : ℤ)) + (fun _ => StarAlgEquiv.refl) (fun _ _ => rfl) + +/-- **The unit translation moves regions**: it carries the site `0` to the site `1`. So + `shiftCovariance` is not the identity covariance, and the site permutation recovered from it by + `LocalNet.Covariance.exists_sitePerm` is not the identity permutation. -/ +@[simp] lemma σ_shiftCovariance : shiftCovariance.σ ({0} : Finset ℤ) = {1} := rfl + +/-! ### A net of von Neumann algebras with the split property -/ + +/-- The **constant net at `𝓑(ℂ)`** over the integer chain. Isotony is trivial, and locality holds + because bounded operators on `ℂ` commute (`VonNeumannAlgebra.mul_comm_complex`), so every + algebra of the net lies in the commutant of every other. -/ +noncomputable def scalarNet : VonNeumannNet (Finset ℤ) ℂ where + algebra _ := 𝓑(ℂ) + algebra_mono _ _ _ := le_rfl + algebra_le_commutant_of_orthogonal _ _ _ := by + intro x _ + rw [VonNeumannAlgebra.mem_commutant_iff] + exact fun y _ => VonNeumannAlgebra.mul_comm_complex y x + +/-- **The constant net has the split property.** Together with + `ProperContainment.properlyContained_singleton` this is a non-vacuous model of + `VonNeumannNet.SplitProperty`. It is an instance of `VonNeumannNet.splitProperty_of_complex`, + which is also the reason it is no evidence about anything but inhabitation: on `ℂ` every net + splits. -/ +theorem scalarNet_splitProperty : scalarNet.SplitProperty := + VonNeumannNet.splitProperty_of_complex scalarNet + +/-! ### The split property at the representation level + +Two representations of `trivialNet.quasiLocalCStarAlgebra` on `ℂ`, both exhibiting +`LocalNet.SplitProperty`: the zero one, and — so that the interface is not inhabited by a +degenerate `π` alone — a unital one. +-/ + +/-- The zero `*`-representation of the quasi-local C⋆-algebra of the trivial net on `ℂ`. The + representation is degenerate as a `*`-map — it sends `1` to `0` — but that is *not* what makes + the split property hold below: `𝓡(O)` contains `1` regardless, since a von Neumann algebra is + unital, and on `ℂ` it is forced to be `𝓑(ℂ)` for every representation whatsoever + (`VonNeumannNet.splitProperty_of_complex`). The unital representation `unitalRep` below is the + same witness with the degeneracy of `π` removed. -/ +noncomputable def zeroHom : trivialNet.quasiLocalCStarAlgebra →⋆ₙₐ[ℂ] (ℂ →L[ℂ] ℂ) where + toFun _ := 0 + map_smul' _ _ := by simp + map_zero' := rfl + map_add' _ _ := by simp + map_mul' _ _ := (zero_mul (0 : ℂ →L[ℂ] ℂ)).symm + map_star' _ := (star_zero (ℂ →L[ℂ] ℂ)).symm + +/-- The zero representation of the trivial net's quasi-local C⋆-algebra, on `ℂ`. -/ +noncomputable def zeroRep : CStarRep trivialNet.quasiLocalCStarAlgebra where + H := ℂ + π := zeroHom + +/-- **The trivial net has the split property in the zero representation.** Its local von Neumann + algebras act on `ℂ`, where the only von Neumann algebra is `𝓑(ℂ)`, a type I factor. This + inhabits `LocalNet.SplitProperty` itself, not merely the `VonNeumannNet` form. -/ +theorem trivialNet_splitProperty : trivialNet.SplitProperty zeroRep := + VonNeumannNet.splitProperty_of_complex (trivialNet.vonNeumannNet zeroRep) + +/-! #### A unital representation + +The isotony embeddings of `trivialNet` are all the identity of `ℂ`, so its algebra of local +observables collapses onto `ℂ` and its quasi-local C⋆-algebra onto the completion of `ℂ`. Reading +off that scalar and letting it multiply gives a representation on `ℂ` that carries `1` to `1`. +-/ + +/-- **Evaluation of a local observable of the trivial net.** Every local algebra is `ℂ` and every + connecting map the identity, so the inductive limit maps onto `ℂ` by reading off the + component. -/ +noncomputable def evalLocal : trivialNet.localObservables →+* ℂ := + DirectLimit.Ring.lift trivialNet.algebra (fun _ _ h => trivialNet.incl h) ℂ + (fun _ => RingHom.id ℂ) (fun _ _ _ _ => rfl) + +/-- Evaluation reads off the component of a local observable. -/ +@[simp] lemma evalLocal_mk (O : Finset ℤ) (x : ℂ) : + evalLocal (⟦⟨O, x⟩⟧ : trivialNet.localObservables) = x := rfl + +/-- Evaluation preserves the involution: the involution of the limit acts componentwise, and on + `ℂ` it is complex conjugation on both sides. -/ +lemma evalLocal_star (z : trivialNet.localObservables) : + evalLocal (star z) = star (evalLocal z) := by + induction z using DirectLimit.induction with + | _ O X => rw [LocalNet.star_mk, evalLocal_mk, evalLocal_mk]; rfl + +/-- Evaluation is `ℂ`-linear: scalars act componentwise on the limit. -/ +lemma evalLocal_smul (c : ℂ) (z : trivialNet.localObservables) : + evalLocal (c • z) = c • evalLocal z := by + induction z using DirectLimit.induction with + | _ O X => rw [DirectLimit.smul_def, evalLocal_mk, evalLocal_mk]; rfl + +/-- **Evaluation is isometric**: the C⋆-norm of the limit is the norm of the component. -/ +lemma norm_evalLocal (z : trivialNet.localObservables) : ‖evalLocal z‖ = ‖z‖ := by + induction z using DirectLimit.induction with + | _ O X => rw [evalLocal_mk, LocalNet.norm_mk]; rfl + +/-- Evaluation extended to the quasi-local C⋆-algebra, by continuity from the dense image of the + local observables. -/ +noncomputable def evalQuasiLocal : trivialNet.quasiLocalCStarAlgebra →+* ℂ := + UniformSpace.Completion.extensionHom (β := ℂ) evalLocal + (AddMonoidHomClass.isometry_of_norm _ norm_evalLocal).continuous + +/-- The extension agrees with evaluation on the local observables. -/ +@[simp] lemma evalQuasiLocal_coe (z : trivialNet.localObservables) : + evalQuasiLocal (↑z : trivialNet.quasiLocalCStarAlgebra) = evalLocal z := + UniformSpace.Completion.extensionHom_coe _ _ z + +/-- The extension is continuous, being the continuous extension of a uniformly continuous map. -/ +lemma continuous_evalQuasiLocal : Continuous evalQuasiLocal := + UniformSpace.Completion.continuous_extension + +/-- The extension preserves the involution: it does so on the dense image, and both sides are + continuous. -/ +lemma evalQuasiLocal_star (z : trivialNet.quasiLocalCStarAlgebra) : + evalQuasiLocal (star z) = star (evalQuasiLocal z) := by + refine UniformSpace.Completion.induction_on z + (isClosed_eq (continuous_evalQuasiLocal.comp continuous_star) + (continuous_star.comp continuous_evalQuasiLocal)) fun w => ?_ + rw [UniformSpace.Completion.star_coe, evalQuasiLocal_coe, evalQuasiLocal_coe, evalLocal_star] + +/-- The extension is `ℂ`-linear: it is on the dense image, and both sides are continuous. -/ +lemma evalQuasiLocal_smul (c : ℂ) (z : trivialNet.quasiLocalCStarAlgebra) : + evalQuasiLocal (c • z) = c • evalQuasiLocal z := by + refine UniformSpace.Completion.induction_on z + (isClosed_eq (continuous_evalQuasiLocal.comp (continuous_const_smul c)) + ((continuous_const_smul c).comp continuous_evalQuasiLocal)) fun w => ?_ + rw [← UniformSpace.Completion.coe_smul, evalQuasiLocal_coe, evalQuasiLocal_coe, evalLocal_smul] + +/-- **The unital `*`-representation of the quasi-local algebra of the trivial net on `ℂ`**: + evaluate the quasi-local observable to a scalar, then let that scalar multiply. Unlike + `zeroHom` it carries `1` to `1` (`unitalRep_π_one`). -/ +noncomputable def unitalHom : trivialNet.quasiLocalCStarAlgebra →⋆ₙₐ[ℂ] (ℂ →L[ℂ] ℂ) where + toFun z := evalQuasiLocal z • (1 : ℂ →L[ℂ] ℂ) + map_smul' c z := by simp only [evalQuasiLocal_smul, smul_assoc, MonoidHom.id_apply] + map_zero' := by + rw [map_zero] + exact ContinuousLinearMap.ext fun z => by simp + map_add' _ _ := by + rw [map_add] + exact ContinuousLinearMap.ext fun z => by simp [add_mul] + map_mul' _ _ := by rw [map_mul, smul_mul_assoc, one_mul, smul_smul] + map_star' _ := by rw [evalQuasiLocal_star, star_smul, star_one] + +/-- The unital representation of the trivial net's quasi-local C⋆-algebra, on `ℂ`. -/ +noncomputable def unitalRep : CStarRep trivialNet.quasiLocalCStarAlgebra where + H := ℂ + π := unitalHom + +/-- **The unital representation is unital**: `π 1 = 1`. This is what `zeroRep` fails, and the + reason this second witness exists — without it the representation-level split property would be + inhabited only by a `π` that annihilates the whole algebra. -/ +@[simp] lemma unitalRep_π_one : unitalRep.π 1 = 1 := by + change evalQuasiLocal 1 • (1 : ℂ →L[ℂ] ℂ) = 1 + rw [map_one, one_smul] + +/-- **The trivial net has the split property in the unital representation too.** Like + `trivialNet_splitProperty` this is an instance of `VonNeumannNet.splitProperty_of_complex`: the + representation being unital changes the `*`-map but not the Hilbert space, and it is + `dim H = 1` that makes the property hold. Recorded so that the witness set for + `LocalNet.SplitProperty` is not confined to a degenerate representation. -/ +theorem unitalRep_splitProperty : trivialNet.SplitProperty unitalRep := + VonNeumannNet.splitProperty_of_complex (trivialNet.vonNeumannNet unitalRep) + +end LocalNet.Examples From 57af85c3cce10607a817919ce9525cc163f72dd2 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:44:00 +0000 Subject: [PATCH 101/113] docs: add extraction notes for causal index set and split inclusion /math-extract notes for the two objects formalized above: the causal index set of a Haag-Kastler net (CausalIndexSet) and the split inclusion of von Neumann algebras (VonNeumannAlgebra.IsSplitInclusion), drawn from HM06, GLRV99, NAA13, BGL93, BFV01, KOE03, dB74, DL84, HS17. Records the retrieval history for the five newly fetched sources in sources.md and indexes both notes in docs/math/README.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-extract/sources.md | 9 + docs/math/README.md | 2 + docs/math/causal-index-set.md | 1028 ++++++++++++++++++++++++ docs/math/split-inclusion.md | 589 ++++++++++++++ 4 files changed, 1628 insertions(+) create mode 100644 docs/math/causal-index-set.md create mode 100644 docs/math/split-inclusion.md diff --git a/.claude/skills/math-extract/sources.md b/.claude/skills/math-extract/sources.md index 89263d6..ff0cb3f 100644 --- a/.claude/skills/math-extract/sources.md +++ b/.claude/skills/math-extract/sources.md @@ -64,5 +64,14 @@ different object is in the wrong file. | Key | Work | Status | Cache | Version/Ed. | Last tried | Notes | |---|---|---|---|---|---|---| +| KOE03 | S. Köster, *Structure of Coset Models*, dissertation, arXiv math-ph/0308031 (2003) | retrieved | `references/arxiv-math-ph-0308031/` | arXiv | 2026-08-14 | arXiv LaTeX (rung 1), verbatim; single source file `mathphkoediss.tex` | +| HS17 | S. Hollands, K. Sanders, *Entanglement measures and their properties in quantum field theory*, arXiv 1702.04924 | retrieved | `references/arxiv-1702.04924/` | arXiv | 2026-08-14 | arXiv LaTeX (rung 1), verbatim. Citation-key trap: HS17's `buchholz_4` = Buchholz–Wichmann 1986, *not* Buchholz 1974; `buchholz_2` = BDF87; `doplicher_4` = DL84 (verified against its bibliography) | +| dB74 | D. Buchholz, *Product states for local algebras*, Comm. Math. Phys. 36 (1974) 287–304 | partial | `references/buchholz-1974-product-states/` | published | 2026-08-15 | Project Euclid PDF; MinerU `hybrid-engine --effort high`, pp. 1–8 of 18; mineru-unchecked. Cor. 2.4 proves product state ⇒ interpolating type I factors; the converse is asserted just after it. **locator p. 292 (Ch. II items a) and b)) is adjudicated**: the page number was recovered by extracting the OCR text layer of `mineru/downloaded/hybrid_auto/downloaded_origin.pdf` with `pypdf`, **independently of MinerU** — the page carries the running head `292 D. Buchholz` and reproduces the passage word for word including the typo `maped`. Tier stays **(b)** (`mineru-cross-checked-against-PDF-text-layer`) because no page *image* comparison is possible: `pdftoppm`, `pdftotext`, `mutool` and `gs` are all absent from this container. The same extraction resolves item b)'s footnote — it reads *This example is due to Araki*, so that construction is **Araki's, not Buchholz's**. The paper carries **three** different separation relations (translation buffer in Thm 2.2, closure in Ch. II a), positive distance in Ch. III); citing "dB74's separation condition" without saying which is ambiguous | +| DL84 | S. Doplicher, R. Longo, *Standard and split inclusions of von Neumann algebras*, Invent. Math. 75 (1984) 493–536 | partial | `references/doplicher-longo-1984-standard-split/` | published | 2026-08-14 | GDZ digitization (volume `PPN356556735_0075`, article div `LOG_0034`, found via the METS file); MinerU `hybrid-engine --effort high`, pp. 1–14 of 44 (§0–§4); mineru-unchecked. locator Prop. 1.2: says joint cyclic-separating vectors exist *under* standard action / properly infinite commutants — citing it for bare "properly infinite on separable ℋ" (as KOE03 does at its source.txt 6666–6669) drops needed hypotheses. §9–10 (the non-split field theories) not converted. Its §0 phrases the split property's separation as `space-like separated by non-zero distance` and cites dB74, whose cached scope (§III, smooth boundaries + positive distance, free neutral massive scalar) is **narrower** than that paraphrase | <!-- Append below. Newest last. --> +| HM06 | H. Halvorson, M. Müger, *Algebraic Quantum Field Theory*, in *Handbook of the Philosophy of Physics*, arXiv math-ph/0602036 | retrieved | `references/arxiv-math-ph-0602036/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `reconstruction.tex`. Leaves "spacelike separated" **undefined** and writes the causal complement `O'` with no formula, so it cannot be cited for either. Its `\begin{fact}` (strictly ⇒ strongly spacelike separated) carries no proof and no citation. Prop. `frees` is stated for *strongly* but its proof's first line says *strictly* — a typo; the proposition as stated is proved | +| GLRV99 | D. Guido, R. Longo, J. E. Roberts, R. Verch, *Charged sectors, spin and statistics in quantum field theory on curved spacetimes*, arXiv math-ph/9906019 | retrieved | `references/arxiv-math-ph-9906019/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `main.tex`. **Notation trap: `𝒪^⊥` denotes both the sieve `{𝒪₁ ∈ 𝒦 : 𝒪₁ ⊥ 𝒪}` (§3.1) and the point set `M ∖ J̄(𝒪)` (§2.1), in one paper.** Cross-reference errata: the Extension Theorem's proof cites "Lemma 3.A.4" where 3A.5 is needed and prints three spellings of one label; Lemma 3.6 says `dimension $\geq 2$` then treats dimension two as the remaining case; §3.5 refers to `hatduality` as a Lemma where the environment is a Proposition. locator §3.1 (`source.txt` 1218–1223): the axiom list for ⊥ is a),b),c) **only**, and the source says the list is a floor (`The necessary properties will be introduced as needed`); a **fourth** condition appears at `source.txt` 1878–1882, before Theorem 3.13 | +| NAA13 | P. Naaijkens, *Quantum spin systems on infinite lattices*, arXiv 1311.2717 | retrieved | `references/arxiv-1311.2717/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; multi-file (`aqft.tex`, `qlattice.tex`, `opalg.tex`, …), macros in `qlattice.tex`. The only corpus source stating `𝒪 = 𝒪″` for double cones, and it states it without proof. Its `𝒫_f(Γ)` **contains `∅`**, with `𝒜(∅) = ℂI` fixed explicitly — so any claim that the lattice index set fails an existence-of-a-⊥-partner condition is false for *this* index set | +| BGL93 | R. Brunetti, D. Guido, R. Longo, *Modular structure and duality in conformal quantum field theory*, arXiv funct-an/9302008 | retrieved | `references/arxiv-funct-an-9302008/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `main.tex`. locator Cor. 2.7: discharged by `\proof Immediate, see [\ref(Long1)].` and conditional on Remark 2.6's spectral hypothesis — do not cite it as an unconditional type III₁ result. locator Thm 3.3: its proof cites a **Lemma 3.4 that does not exist**; Lemma 3.2 is meant. Its "distal split property" (§3 assumption (b)) is an **existential over one pair of regions**, not a metric strengthening of the separation relation. Its non-split net `ℬ(𝒪) = 𝒜(π⁻¹𝒪)` is attributed to a **private remark** of Buchholz, so no locator can ever exist for the attribution | +| BFV01 | R. Brunetti, K. Fredenhagen, R. Verch, *The generally covariant locality principle*, arXiv math-ph/0112041 | retrieved | `references/arxiv-math-ph-0112041/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim. **The distributed source contains two complete `\begin{document}…\end{document}` bodies** — `source.txt` lines 118–2851 and 2957–4225 (`source.flat.txt` offsets 3687 and 144453). Only the first is the compiled paper; the second is a shorter earlier draft that even defines `\frakA` differently. **Take every locator from the first body**, and expect `grep -F` to return 2 for shared passages — that is not a duplicate-quote defect. Its `𝒦(M,ḡ)` is defined by two conditions only (relatively compact, causally convex), and openness/connectedness/non-emptiness are forced only by the *next* sentence's demand that each region be an object of `𝔐`; the two readings give different index sets. `cf.\ condition $(ii)$` points at orientation-preservation where causal convexity is condition (i), in **both** bodies, so authorial | diff --git a/docs/math/README.md b/docs/math/README.md index e24e6f9..f75affd 100644 --- a/docs/math/README.md +++ b/docs/math/README.md @@ -27,6 +27,8 @@ the product. | Object | Note | Implemented as | |---|---|---| +| Causal index set of a Haag–Kastler net | [causal-index-set.md](causal-index-set.md) | `CausalIndexSet` | +| Split inclusion of von Neumann algebras | [split-inclusion.md](split-inclusion.md) | `VonNeumannAlgebra.IsSplitInclusion` | <!-- One row per note. "Implemented as" is a fact recorded after the object is formalized — the fully-qualified declaration that ended up carrying it, or diff --git a/docs/math/causal-index-set.md b/docs/math/causal-index-set.md new file mode 100644 index 0000000..0b1db69 --- /dev/null +++ b/docs/math/causal-index-set.md @@ -0,0 +1,1028 @@ +--- +object: Causal index set of a Haag–Kastler net +slug: causal-index-set +status: draft +worst-tier: b +mathlib-rev: 5450b53e5ddc75d46418fabb605edbf36bd0beb6 +implemented-as: CausalIndexSet +revisions: + - 2026-08-15 · 4ec09ec · initial extraction · sources: HM06, GLRV99, NAA13, BGL93, BFV01, KOE03, dB74, DL84 + - 2026-08-15 · <working tree, uncommitted> · prior-art refresh after CausalIndexSet mixin addition · no new claims +--- + +<!-- +Macros used by the verbatim quotes below, transcribed from each source's own +preamble so that the quotes render as their authors wrote them: + \cA \cB \cH \cK \cL \cO \cP \cS \cW \cX GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \p GLRV99, main.tex:127 + \2 \7 \al \alg \norm \ol \wt \Om HM06, references/arxiv-math-ph-0602036/raw/reconstruction.tex:136,138,143,26,27,141,135,149 + \A \C \K \O \R BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 + \calA \calK \frakM \gb \obj BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) + \lok \Seins KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144,135 + \mc NAA13, references/arxiv-1311.2717/raw/qlattice.tex:73 +NAME COLLISION, recorded rather than silently resolved: GLRV99 defines +\p as \pi (main.tex:127) and HM06 defines \p as \psi +(reconstruction.tex:148). The table below carries GLRV99's, because the only +quote in this note using \p is GLRV99's (R2). No HM06 quote here uses it. +\alg is defined identically by HM06 and NAA13, so one definition serves both. +\2 and \7 are single-digit control sequences; they are TeX-legal via \def and +are transcribed as their sources write them. A renderer that rejects them +raises a visible parse error, which is the intended failure mode — editing the +quote is not, because those bytes are what the quote check verifies. +--> + +$$ +\def\cA{{\cal A}} +\def\cB{{\cal B}} +\def\cH{{\cal H}} +\def\cK{{\cal K}} +\def\cL{{\cal L}} +\def\cO{{\cal O}} +\def\cP{{\cal P}} +\def\cS{{\cal S}} +\def\cW{{\cal W}} +\def\cX{{\cal X}} +\def\p{\pi} +\def\2#1{{\mathcal #1}} +\def\7#1{{\mathbb #1}} +\def\al#1{{\mathfrak #1}} +\newcommand{\alg}[1]{\mathfrak{#1}} +\newcommand{\norm}[1]{\| #1\|} +\def\ol#1{{\overline #1}} +\def\wt#1{{\tilde #1}} +\def\Om{\Omega} +\def\A{{\cal A}} +\def\C{{\cal C}} +\def\K{{\cal K}} +\def\O{{\cal O}} +\def\R{{\cal R}} +\newcommand{\calA}{{\mathcal A}} +\newcommand{\calK}{{\mathcal K}} +\newcommand{\frakM}{{\mathfrak{Man}}} +\newcommand{\gb}{\boldsymbol{g}} +\newcommand{\obj}{\mbox{\rm Obj}} +\newcommand{\lok}[1]{{\mathcal #1}} +\newcommand{\Seins}{\mathsf{S}^1} +\newcommand{\mc}[1]{\mathcal{#1}} +$$ + +# Causal index set of a Haag–Kastler net + +## What this object is for + +A Haag–Kastler net assigns algebras to spacetime regions, and every axiom that +makes the assignment physics rather than bookkeeping — locality, duality, the +DHR selection criterion, the split property — is a statement about *which +regions stand in which relation to which*. The index set is where that +information lives: a partially ordered set of regions carried with a relation of +causal disjointness, and, for the independence properties, one or more +strengthenings of that relation. Its generality matters because the corpus's +main structural results split precisely along its axes — whether the order is +directed decides whether a quasi-local algebra exists at all, and which +strengthening of causal disjointness is in force decides whether an +independence theorem applies to a given pair of regions. + +## Definition + +### Variants as the sources write them + +| (D#) | Source | Level | Primitive | Membership conditions | Directed | ∅ ∈ 𝒦 | Tier | +|---|---|---|---|---|---|---|---| +| (D1) | [GLRV99] | abstract | relation ⊥ on a poset | a), b), c) | not required | not excluded | a | +| (D2) | [GLRV99] | concrete | ⊥ on subsets of M | regular diamond; `𝒪^⊥ ≠ ∅` | not in general; never if the Cauchy surface is compact | no | a | +| (D3) | [GLRV99] | pointwise | ⊥ on points of M | — (neighbourhood-buffer definition) | — | — | a | +| (D4) | [GLRV99] | operation | `Q^⊥ := M ∖ J̄(Q)` | — | — | — | a | +| (D5) | [GLRV99] | derived relations | ⊥̃, ⊥̂ from ⊥ | — | — | — | a | +| (D6) | [HM06] | concrete | "spacelike separated", primitive | open double cone in Minkowski | yes (Minkowski) | no | a | +| (D7) | [HM06] | strengthened relation | translation buffer | — | — | — | a | +| (D8) | [HM06] | strengthened relation | closures + enlargement | — | — | — | a | +| (D9) | [HM06] | separation for split | `Ō₁ ⊆ O₂` | — | — | — | a | +| (D10) | [NAA13] | concrete | "spacelike separated", primitive | double cone; records `𝒪 = 𝒪″` | yes | no | a | +| (D11) | [NAA13] | concrete, discrete | disjointness | finite subset of a countable Γ | yes | **yes** | a | +| (D12) | [BGL93] | concrete ×2 | causal complement | `𝒦̃`: open contractible precompact, closed under `′`; `𝒦`: double cones | `𝒦̃` no, `𝒦` yes | no | a | +| (D13) | [BGL93] | operation on S¹ | `I′ =` interior of the complement | — | — | — | a | +| (D14) | [KOE03] | concrete | operation `I ↦ I′` | connected, open, non-dense; `I′ ≠ ∅` | **no** | no | a | +| (D15) | [KOE03] | separation for split | `Ī₁ ⊂ I₂` | — | — | — | a | +| (D16) | [BFV01] | concrete | closure-based ⊥ | relatively compact, causally convex | not addressed | yes, read literally | a/b | +| (D17) | [BFV01] | operation | `O^⊥ =` largest causally separated open set | — | — | — | a | +| (D18) | [dB74] | separation ×3 | translation buffer / closure / positive distance | open, `𝒪′ ≠ ∅` | — | no | b | +| (D19) | [GLRV99] | concrete, net-dependent | ⊥ on sieves | causally closed, `𝒮^⊥ ≠ ∅`, ⊥̃-duality for `𝒮` or `𝒮^⊥` | — | no | a | +| (D20) | [GLRV99] | concrete, mixed | ⊥ across two families | regular diamonds ∪ wedges | — | no | a | + +**(D1) [GLRV99] §3.1, `source.txt` 1214–1226** — tier (a) — the abstract form + +> The causal structure enters in the form of the relation $\perp$ of causal disjointness, defined in Ch.\ 2, and here to be considered as a relation on the ordered set $\cal{K}$, satisfying \begin{description} \item{$a)$} $\cO_1\perp\cO_2\Rightarrow\cO_2\perp\cO_1$. \item{$b)$} $\cO_1\subset\cO_2$ and $\cO_2\perp\cO_3 \Rightarrow\cO_1\perp\cO_3$. \item{$c)$} Given $\cO_1\in\cK$, there exists an $\cO_2\in\cK$ such that $\cO_1\perp\cO_2$. \end{description} We write $\cO^\perp:=\{\cO_1\in\cK:\cO_1\perp\cO\}$. + +Restated at the head of the Appendix to Ch. 3 with the gloss that b) says +`$\cal{O}^\perp$ is a sieve of $\cal{K}$`. Here `𝒪^⊥` is a **subset of 𝒦**, not +a region — the opposite convention from (D4); see (C4). The abstraction is +deliberate: + +> Our discussion of superselection theory in this and in subsequent sections is in terms of a partially ordered set $\cal{K}$ together with a binary relation $\perp$. The necessary properties will be introduced as needed and there will be no specific reference to spacetime. + +**The list is therefore a floor, not a ceiling, and the source says so.** A +fourth condition appears later in the same chapter and is recorded as (D5′). + +**(D2) [GLRV99] §2.1 and §3.1** — tier (a) — regular diamonds + +> A set of the form $\cO = {\rm int}\,D(G)$ is a regular diamond provided $\cO^\perp$ is non-void and + +with (i) `Ḡ` compact and contractible to a point in `G`, `G` open in an acausal +Cauchy surface `C`; (ii) `∂G` a locally flat, two-sided topological +submanifold of `C`, smooth near points of each connected component. Then +`We let $\cK$ denote the set of regular diamonds in $M$, ordered under inclusion.` +Non-void causal complement is **in the definition**, which is how axiom c) is +secured. GLRV99 declines double cones and says why: + +> For these reasons, we have chosen to use the collection $\cK$ of regular diamonds rather than the collection of double cones whose causal complement has non-empty interior as an index set in a globally hyperbolic spacetime. + +`differs from (D6)/(D10) by:` a Cauchy-surface base with compactness, +contractibility and a two-sidedness condition, plus `𝒪^⊥ ≠ ∅`. Note the source +uses two different provisos in one sentence — `𝒪^⊥` **non-void** for diamonds, +**non-empty interior** for the declined double cones — and does not reconcile +them. + +**(D3) [GLRV99] §2.1** — tier (a) — causal disjointness of points, with a buffer + +> One says that two points $p$ and $q$ in $M$ are {\it causally disjoint}, in symbols $p \perp q$, if there are open neighbourhoods $U$ of $p$ and $V$ of $q$ such that there is no causal curve connecting $U$ and $V$ (i.e.\ $U \cap J(V) = \emptyset = V \cap J(U)$). Correspondingly one calls two subsets $P$ and $Q$ of $M$ causally disjoint if $p \perp q$ holds for all pairs $p \in P$ and $q \in Q$; this will be abbreviated as $P \perp Q$. + +The **open-neighbourhood buffer** makes this strictly stronger than "no causal +curve joins `p` and `q`", and (R4)'s proof consumes exactly that strength. As +defined, `p ⊥ p` is impossible, so `P ⊥ P` fails for every non-empty `P` and +holds vacuously for `P = ∅`. + +`differs from (D17) by:` GLRV99 buffers with neighbourhoods and quantifies over +points of `P`, `Q`; BFV01 uses no buffer and quantifies over points of the +**closures**. **The corpus contains two inequivalent ⊥'s and no source compares +them.** + +**(D4) [GLRV99] §2.1** — tier (a) — the causal complement as an operation on subsets + +> It is moreover worth mentioning that for any two subsets $P$ and $Q$ of a globally hyperbolic spacetime $(M,g)$ we have $P \perp Q$ if and only if $P \subset Q^{\perp}$, where the causal complement $Q^{\perp}$ of $Q \subset M$ is defined by $Q^{\perp} := M \backslash \overline{J(Q)}$ + +Complement of the **closure** of the causal hull, hence automatically open. + +**(D5) [GLRV99] Appendix to Ch. 3** — tier (a) — the two derived relations + +> There are two derived binary relations $\tilde\perp$ and $\hat\perp$ defined by supplementing $\cO_1\perp\cO_2$ by requiring that there exists an $\cO_3\in\cal{K}$ such that $$\cO_1\perp\cO_3,\,\,\cO_2\perp\cO_3$$ or such that $$\cO_1,\,\,\cO_2\subset\cO_3,$$ respectively. These relations automatically satisfy a) and b) but c) remains to be checked and will not prove to be a problem in our applications to curved spacetime. The operation of passing from $\perp$ to $\tilde\perp$ or $\hat\perp$ is idempotent and if $\cal{K}$ is directed, all three relations coincide. + +So `O₁ ⊥̃ O₂` demands a common ⊥-partner and `O₁ ⊥̂ O₂` a common upper bound. +Both are **purely order/⊥-theoretic**: neither mentions closures or distance. +The whole ⊥/⊥̃/⊥̂ distinction is the price of dropping directedness — see (R9). + +**(D5′) [GLRV99] Ch. 3, before Theorem 3.13, `source.txt` 1878–1882** — tier (a) +— the corpus's only collar-shaped condition on 𝒦 itself + +> In fact, the following result is valid for a directed set $\cal{K}$ with a binary relation $\perp$ such that given $\cal{O}\in\cal{K}$, there exists $\cO_1,\cO_2\in\cal{K}$ with $\cO,\cO_1\subset\cO_2$ and $\cO\perp\cO_1$. This condition is related to our use of the Borchers Property. + +For every `O` there are `O₁, O₂` with `O ⊆ O₂`, `O₁ ⊆ O₂` and `O ⊥ O₁` — in the +vocabulary of (D5), **every `O` has an `O₁` with `O ⊥̂ O₁`**, i.e. axiom c) +strengthened from ⊥ to ⊥̂. Stated as a hypothesis of one theorem alongside +directedness, not as a standing axiom. + +`differs from (D5) by:` (D5) is a relation *between two given regions*; this is +a **∀∃ statement about 𝒦**. Every other collar in the corpus is of the former +kind or is topological ((D8), (D9)). **No source compares the two shapes.** + +**(D6) [HM06] §2.1** — tier (a) — open double cones in Minkowski + +> An open \emph{double cone} in Minkowski spacetime is the intersection of the causal future of a point $x$ with the causal past of a point $y$ to the future of $x$. Let $\2K$ be the set of open double cones in Minkowski spacetime + +No poset axioms are stated; the order is inclusion, used silently. **HM06 never +defines "spacelike separated"** — it is an undefined primitive from the +Microcausality assumption onward, and the causal complement is written `O'` with +no formula. See (C1). + +`differs from (D2) by:` no Cauchy-surface base, no regularity, and **no +requirement that the causal complement be non-void**. + +**(D7) [HM06] §3.3** — tier (a) — strictly spacelike separated + +> Two double cones $O_1,O_2$ are said to be \emph{strictly spacelike separated} just in case there is a neighborhood $N$ of zero such that $O_1+x$ is spacelike separated from $O_2$ for all $x\in N$. + +A translation-buffer condition; **requires a translation group**. + +**(D8) [HM06] §3.3** — tier (a) — strongly spacelike separated + +> Two double cones $O_1$ and $O_2$ are said to be \emph{strongly spacelike separated} just in case there are double cones $\wt O_i$ such that $\ol O_i\subseteq \wt O_i$, and $\wt O_1,\wt O_2$ are spacelike. + +with the ordering claim + +> In terms of logical strength, the following concept lies between spacelike separation and strict spacelike separation; furthermore, this concept makes sense for spacetimes without a translation group. + +`differs from (D5) by:` the shapes are not the same. (D5)'s clauses ask for +**one** further region related to both by ⊥ or by ≤; (D8) asks for **two** +enlargements, one per region, each containing the region's **closure**. (D8) +uses the topological closure, **which is not available in (D1)'s data**, so +"strongly spacelike separated" is not expressible in GLRV99's abstract language. +`sources claim equivalence:` no — no source in the corpus mentions the other's +relation. + +**(D9) [HM06] §2.4** — tier (a) — the separation carrying the split property + +> the \emph{funnel property} if for any double cones $O_1,O_2$ with $\ol O_1$ contained in $O_2$, the pair $(\al R(O_1),\al R(O_2))$ is a split inclusion. + +The relation is `closure(O₁) ⊆ O₂`. **HM06 gives it no name and no symbol.** +Purely topological: no causal structure, no metric, no positive distance. + +**(D10) [NAA13] §1.2** — tier (a) — double cones, recorded as causally complete + +> As the basic regions we consider \emph{double cones}\index{double cone} $\mc{O}$, defined as the intersection of (the interior of) a forward and backward light-cone. Note that a double cone is causally complete: $\mc{O} = \mc{O}''$, where a prime $'$ denotes taking the causal complement. + +`differs from (D6) by:` the same family, presented as an intersection of cones +rather than through two points, **plus the causal-completeness observation HM06 +never makes**. NAA13 is the corpus's only source stating `𝒪 = 𝒪″`, and states it +as an observation, not as a membership condition — contrast (D19). + +**(D11) [NAA13] §2.4** — tier (a) — the lattice index set, with `∅` a member + +> Let $\Gamma$ be as above. We will write $\mc{P}(\Gamma)$ for the set of all subsets of $\Gamma$. Similarly, $\mc{P}_f(\Gamma)$ is the subset of all \emph{finite} subsets of $\Gamma$. + +> For convenience we will set $\alg{A}(\emptyset) = \mathbb{C} I$, since multiples of the identity are contained in $\alg{A}(\Lambda)$ for all $\Lambda \in \mc{P}_f(\Gamma)$. + +Finite subsets of a countable Γ, ordered by inclusion, ⊥ = plain disjointness. +**Directed**, with a **least element ∅**, a distributive lattice, and its +complement operation `Λ^c` leaves 𝒦. GLRV99 licenses exactly this replacement of +causal disjointness by "its Euclidean counterpart, disjointness". Because +`∅ ∈ 𝒦`, **⊥ is reflexive at ∅** and axiom c) holds for free — see (C11), (H1). + +**(D12) [BGL93] §1, Prop. 1.3** — tier (a) — two index sets in one paper + +> In the following we shall consider the family $\tilde\K$ of the subregions of $\tilde M$ which are images of double cones in $M$ under conformal transformations in $\tilde\C$. + +> All elements of $\tilde\K$ are open contractible precompact submanifolds of $\tilde M$. They are a fundamental set of neighborhoods for $\tilde M$. + +> The space-like complement $\O'$ of a region $\O\in\tilde\K$ belong to $\tilde\K$. + +> The family $\tilde\K$ is not a net, in fact the union of a region and of its causal complement is not contained in any region of $\tilde\K$. + +and, for the same paper's other index set, + +> Since the family $\K$ is a direct set, the map $\O\to\A(\O)$ is indeed a net and the quasilocal $C^*$-algebra $\A_0$ is defined as the direct limit of the local algebras. + +**`𝒦̃` is the corpus's only index set literally closed under the causal +complement**, so on it `𝒪 ↦ 𝒪′` is an *operation*; on every other index set it +is only a relation. One paper, two index sets, opposite on directedness and +opposite on closure under `′`. + +**(D13) [BGL93] §2** — tier (a): `where $I'$ is the interior of the complement of $I$.` +`differs from (D14) by:` presentation only — interior-of-complement versus +complement-of-closure. The two sources write different formulas for the same set +and neither remarks on it. + +**(D14) [KOE03] §2** — tier (a) — proper intervals of the circle + +> The localisation regions are open, non-dense intervals contained in the circle, called the {\em proper intervals}. A connected, open subset $I$ of $\Seins$ is a proper interval, denoted by $I\Subset\Seins$, if its {\em causal complement} $I':= \Seins\setminus\overline{I}$ is not the empty set. + +Membership requires connected, open, non-dense, and `I′ ≠ ∅` — as in (D2) and +unlike (D6)/(D10). Locality is stated as `{\em Locality\label{ax:loc}:} For $I_1\subset I_2'$,` +so **the primitive is the operation `I ↦ I′`** and ⊥ is derived, the reverse of +(D1). Interchangeable only because 𝒦 is closed under `′` here. The index set is +not directed and the source draws the terminological consequence: + +> The set of proper intervals in $\Seins$ is not directed with respect to the partial order defined by inclusion and thus is not a net in the proper sense of the word. + +**(D15) [KOE03] §1.3** — tier (a) — the chiral split separation + +> a chiral net $\lok{B}$ has the split property, if for any pair $I_{1,2}$ of proper intervals satisfying $\overline{I_1}\subset I_2$ there is a type $I$ factor $\lok{M}$ interpolating between $\lok{B}(I_1)$ and $\lok{B}(I_2)$ + +`differs from (D9) by:` **nothing mathematical** — two traditions, one relation, +and neither names it or gives it a symbol. KOE03 also takes the one step in the +corpus connecting the topological and order-theoretic collar families: + +> we conclude that there is $I_3\Subset\Seins$ satisfying $I_1\cup I_2' \subset I_3$ + +i.e. `Ī₁ ⊂ I₂` yields a common upper bound for `I₁` and `I₂′`, which with +`I₁ ∩ I₂′ = ∅` says exactly `I₁ ⊥̂ I₂′`. + +**(D16) [BFV01] §2.4, first document body** — tier (a) literal / (b) as intended + +> We denote by $\calK(M,\gb)$ the set of all subsets in $M$ which are relatively compact and contain with each pair of points $x$ and $y$ also all $\gb$-causal curves in $M$ connecting $x$ and $y$ (cf.\ condition $(ii)$ in the definition of $\frakM$). + +Two conditions only: **relatively compact** and **causally convex**. Read +literally, `∅`, singletons and spacelike point-pairs are members. The next +sentence silently demands far more — each `(O, ḡ_O)` must lie in `obj(𝔐)`, whose +manifolds are `Hausdorff, paracompact, and connected` — so the intended index set +is open, connected, non-empty and globally hyperbolic. **The two readings give +different index sets**, and the inference to the second is tier (b). + +**(D17) [BFV01] §2.1, first document body** — tier (a) — closure-based ⊥ + +> Two subsets $O_1$ and $O_2$ in $M$ are called causally separated if they cannot be connected by a causal curve, i.e.\ if for all $x \in \overline{O_1}$, $J^{\pm}(x)$ has empty intersection with $\overline{O_2}$. By $O^{\perp}$ we denote the causal complement of $O$, i.e.\ the largest open set in $M$ which is causally separated from $O$. + +**BFV01's plain "causally separated" already excludes touching regions**, unlike +(D3) and (D14). `O^⊥` is given by a maximality characterisation with **no +set-theoretic formula**, unlike (D4) and (D14). + +**(D18) [dB74] Ch. II–III** — tier (b), `mineru-unchecked` except where noted — +three separation shapes in one paper + +- *translation buffer*, Thm 2.2: + > Let $\hat{O}_{1}$ and $\hat{O}_{2}$ be two spacelike separated regions such that $O_{1} + N \subset \hat{O}_{1}$ and $O_{2} + N \subset \hat{O}_{2}$ . +- *closure*, Ch. II item a), **p. 292** (tier (b), + `mineru-cross-checked-against-PDF-text-layer`): + > If the closures of the regions $O_{1}$ and $O_{2}$ are not spacelike separated, then, at least for the free field, it is easy to show that one runs into contradictions if one postulates the existence of normal product states for such regions. + **The corpus's only statement that the closure relation is *necessary*.** +- *positive distance*, Ch. III: + > Both regions shall have smooth boundaries and the distance between $O_{1}$ and $O_{2}$ is supposed to be greater than zero. + +dB74's index set carries openness and `𝒪′ ≠ ∅`, stated as the scope of its +Reeh–Schlieder assumption rather than as a definition. + +`differs from (D7) by:` HM06 translates one region and asks it stay spacelike to +the other; dB74 translates a region and asks it stay **inside a larger region**. +Same buffer idea, two different relations. + +**(D19) [GLRV99] Appendix Ch. 3 and §4.2** — tier (a) — an index set that depends on the net + +> We choose $\cL$ to be the set of non-empty causally closed subsets $\cS$ of $M$ with non-empty causal complements such that for the given net $\cA$ $\tilde\perp$--duality holds either for $\cS$ or for $\cS^\perp$. + +> This choice has the disadvantage of depending on the theory under consideration but it allows a smooth treatment of endomorphisms. + +`differs from every other (D#) by:` **the index set is a function of the net.** +Causal closedness `𝒮 = 𝒮^⊥⊥` is here a *membership condition*, where (D10) +records it as an observation. + +**(D20) [GLRV99] Ch. 5** — tier (a) — diamonds together with wedges + +> Now we consider a net $\cO \mapsto\cA(\cO)$ of von~Neumann algebras indexed by elements $\cO \in \cK \cup \cW$ where $\cK$ is the set of regular diamonds and $\cW$ is a set of wedges with the properties discussed in the previous section + +The corpus's only index set containing **unbounded** elements as first-class +members, and the only one that is not a single geometric family. A form that +builds boundedness into 𝒦 cannot state GLRV99's Ch. 5 hypotheses. + +### Adopted general form + +Fix a partially ordered set `𝒦`, whose elements are called *regions*, and a +binary relation `⊥` on `𝒦`, read *causally disjoint*. The pair `(𝒦, ⊥)` is a +**causal index set** when + +1. `O₁ ⊥ O₂` implies `O₂ ⊥ O₁`; +2. `O₁ ≤ O₂` and `O₂ ⊥ O₃` imply `O₁ ⊥ O₃` — equivalently, `O^⊥ := {O₁ ∈ 𝒦 : O₁ ⊥ O}` is downward closed in `𝒦` for every `O`; +3. for every `O₁ ∈ 𝒦` there exists `O₂ ∈ 𝒦` with `O₁ ⊥ O₂`. + +There are no further hypotheses: the order is **not** assumed directed, `⊥` is +**not** assumed irreflexive, `𝒦` carries **no topology** and no +causal-complement operation into itself, no element is assumed causally complete, +no region is assumed open, bounded or non-empty, and `𝒦` may be empty. Standing +hypotheses of the sources that this form deliberately does not carry are (A1) +directedness, (A7) openness and path-connectedness, (A10) causal completeness and +(A11) global hyperbolicity of an ambient spacetime, each of which is a row in +`## Hypotheses` rather than part of the definition. + +$$ +\text{(a) } O_1 \perp O_2 \Rightarrow O_2 \perp O_1,\qquad +\text{(b) } O_1 \le O_2,\ O_2 \perp O_3 \Rightarrow O_1 \perp O_3,\qquad +\text{(c) } \forall O_1\, \exists O_2,\ O_1 \perp O_2 . +$$ + +This is (D1), verbatim [GLRV99] §3.1 up to notation. It is the corpus's only +abstract axiomatisation, it is stated twice and with a declared motive, and every +concrete index set in the corpus is an instance of it — double cones, regular +diamonds, proper intervals of `S¹`, `𝒦̃`, `𝓛`, `𝒦 ∪ 𝒲`, wedges and `𝒫_f(Γ)` were +each checked against a), b), c). (X18) rejects the alternative of taking the +causal complement as an **operation into 𝒦**: the separating object is a double +cone in Minkowski, whose ⊥-partners have no maximum, while `𝒦̃` and the proper +intervals do support the operation; the sieve-valued operation +`O ↦ O^⊥ ⊆ 𝒦` is `equivalent` and is GLRV99's own notation. (X19) rejects adding +causal completeness as an axiom: a three-element antichain satisfies a), b), c) +with `B^⊥⊥ ⊋ ↓B`. (X25)–(X27) reject the quantifier and heredity variants. + +**Three costs of this choice, recorded rather than left to be rediscovered.** + +- **(H1)** Axiom c) does not deliver what the corpus uses it for. Adjoin a least + element `0` to *any* poset and set `⊥ := {(0,O),(O,0)}`; a), b), c) all hold. + So every poset underlies a causal index set and the form has **no + order-theoretic content**. In particular a form omitting irreflexivity may not + be credited with (X3)'s consequence that comparable regions are never ⊥, nor + with (X6)'s that `𝒦` is not a chain — both need irreflexivity, which is + independent of a), b), c). GLRV99's own text warns that the list is a floor. +- **(H2)** [BFV01]'s primary object is a **category** of spacetimes with + isometric embeddings, whose causality condition quantifies over pairs of + morphisms into a common spacetime. This form covers BFV01's *derived* net over + `𝒦(M,ḡ)` and not BFV01's theory. +- **(T) is not expressible.** The hypothesis under which the two candidate + separation relations for the split property are ordered — see below — is + topological, and a bare poset with ⊥ cannot state it. This is the same + obstruction as (D8)'s. + +**The separation relation for the split property is not adopted as a single +relation.** The corpus carries at least six phrasings — (D5)'s ⊥̃ and ⊥̂, (D5′), +(D7), (D8), (D9)/(D15), and (D18)'s three — and states exactly one implication +between any two of them ([HM06]'s `fact`, (R25), asserted there and proved in +this note). What can be said is: + +**(T) — the causal complement abuts the region.** `Ō ∩ cl(O^⊥) ≠ ∅` for every +`O ∈ 𝒦`; equivalently `dist(Ō, O^⊥) = 0`; equivalently, there is no buffer +between a region and its causal complement. *No source states (T); it is this +note's, extracted from the case analysis below.* + +**Ordering theorem** (this note's, not any source's). Let `𝒦` be a base of +**non-empty open** subsets of a topological space `M`, let ⊥ be induced by an +operation `O ↦ O^⊥` into the open sets by `O₃ ⊥ O₁ ⟺ O₃ ⊆ O₁^⊥`, and let +`O ∩ O^⊥ = ∅`. If **(T)** holds then `Ō₁ ⊆ O₂` implies the collar clause +`∃O₃ ∈ 𝒦 : O₃ ≤ O₂, O₃ ⊥ O₁, O₃ ⊄ O₁`. + +*Proof.* By (T) pick `x ∈ Ō₁ ∩ cl(O₁^⊥)`. Since `Ō₁ ⊆ O₂` with `O₂` open, `O₂` +is a neighbourhood of `x`, so meets `O₁^⊥`; hence `O₂ ∩ O₁^⊥` is non-empty open +and, `𝒦` being a base, contains some `O₃ ∈ 𝒦`. Then `O₃ ≤ O₂`; `O₃ ⊆ O₁^⊥` +gives `O₃ ⊥ O₁`; and `O₃ ⊄ O₁` because `O₃ ⊆ O₁^⊥`, `O₁ ∩ O₁^⊥ = ∅` and +`O₃ ≠ ∅`. ∎ + +Compactness of `Ō₁` is not used; openness of `O₂` is. The implication is +**strict**: (X15) direction 2 gives internally tangent double cones satisfying +the collar clause and failing `Ō₁ ⊆ O₂`. (T) holds for double cones (the +intersection is the waist sphere), for regular diamonds (secured by GLRV99's +two-sidedness clause), for the proper intervals of `S¹` (the two endpoints) and +for `𝒦̃` (tier (b), by transporting the Minkowski computation along a conformal +map); it **fails** for `𝒫_f(Γ)`, where discreteness puts a buffer of width 1 +between a set and its complement, and for any index set containing a region with +empty causal complement. So the two forms are `ordered-under-(T)`, neither +`incomparable` nor `ordered`. + +## Notation and conventions + +| (C#) | Axis | This note | Per source | Translation | +|---|---|---|---|---| +| (C1) | is "spacelike separated" defined? | ⊥ is primitive, axiomatised | [GLRV99] (D3) and [BFV01] (D17) define it; **[HM06] and [NAA13] leave it undefined** and write the complement `O'` with no formula. tier (a)/(b) | none available: the two definitions that exist are inequivalent | +| (C2) | directedness of 𝒦 | not assumed | [HM06] and [GLRV99] both remark it may fail and say what is lost; [BGL93] and [KOE03] make it a terminological matter. tier (a) | (R1), (R19), (R16), (R40) | +| (C3) | causal vs plain disjointness | ⊥ abstract | [GLRV99] licenses replacing causal disjointness by "its Euclidean counterpart, disjointness" on the circle; [NAA13] (D11) does it on a lattice. tier (a) | on a discrete Γ the two coincide by fiat | +| (C4) | what `O^⊥` denotes | a subset of 𝒦 | [GLRV99] uses `𝒪^⊥` for **both** the sieve `{𝒪₁ ∈ 𝒦 : 𝒪₁ ⊥ 𝒪}` (D1) and the point set `M ∖ J̄(𝒪)` (D4), in one paper; [BFV01], [KOE03], [BGL93] use the point-set reading only. tier (a) | (R13): `μ`, `ν` are mutually inverse on causally closed sets and sieves, which is the precise sense in which the two readings agree | +| (C5) | openness of regions | not assumed | open in [GLRV99], [BGL93], [KOE03], [dB74]; unstated but automatic in [HM06], [NAA13]; **absent from [BFV01]'s literal definition** and forced by its next sentence. tier (a)/(b) | — | +| (C6) | irreflexivity of ⊥ | not assumed | **no source states it as an axiom**; forced for non-empty regions by (D3)'s pointwise definition; permitted by a), b), c); holds at `∅` in (D11). tier (a)/(b) | (H1); (X3) | +| (C7) | **[KOE03]'s `⋐` is a membership predicate, not containment** | — | `I ⋐ S¹` abbreviates "`I` is a proper interval of `S¹`"; the separation is written `\overline{I_1}\subset I_2`. tier (a) | **a reader who takes `I₁ ⋐ I₂` to mean `Ī₁ ⊆ I₂` reads the wrong relation into every axiom of that source**; the two symbols appear side by side in (D15) | +| (C8) | the word "net" | the map `O ↦ 𝒜(O)` | = **directed family** in [BGL93] and [KOE03], who therefore say `𝒦̃` and the proper intervals "are not a net"; = the map in [HM06], [NAA13], [GLRV99], [BFV01]. tier (a) | under the first reading, [BGL93] Prop. 1.3(v) is a statement about the *index set*, not the algebras | +| (C9) | extending the net outside 𝒦 | not adopted | three devices for `𝒜(𝒮)`: norm closure of the algebras inside `𝒮` ([NAA13], explicit); smallest C\*-algebra generated by them ([BFV01], for `S^⊥⊥`); additivity plus enlarging the index set ([GLRV99]); **undefined** ([HM06] writes `\al A(O')` with no definition). tier (a) | a *choice*, not a theorem; nothing in the corpus shows two devices agree | +| (C10) | boundedness | not assumed | compact base ([GLRV99]), precompact ([BGL93]), relatively compact ([BFV01]), finite ([NAA13]), **non-dense** ([KOE03]), automatic ([HM06]), **dropped** ([GLRV99] (D20)). tier (a) | non-dense on `S¹` is **not** a compactness condition — every subset of `S¹` is relatively compact — but is what makes the complement non-empty | +| (C11) | is `∅ ∈ 𝒦`? | not excluded | **in**: [NAA13]'s `𝒫_f(Γ)` with `𝒜(∅) = ℂI` (tier (a)); [BFV01] read literally (tier (b)). **out**: [GLRV99], [BGL93], [KOE03], [HM06], [dB74] — in every case as a by-product of the construction, never as a stated condition. tier (a)/(b) | `∅` is ⊥ to everything **including itself**, so admitting it makes ⊥ reflexive and satisfies c) for free — this is (H1)'s concrete form | + +## Results and dependencies + +### (R1) Directedness ⇒ the quasi-local algebra exists; without it the construction is unavailable + +- Source: [GLRV99] §1.1 · tier (a) · **asserted** +- Verbatim: + > If $\cK$ is directed, then one can form the ``quasilocal algebra'', i.e.\ the smallest $C^*$-algebra containing all the local algebras $\cA(\cO)$. It is the norm closure of the union of the local algebras, $\overline{\bigcup_{\cO}\cA(\cO)}$. In the generic case where $\cK$ is not directed, this possibility is denied to us. +- Depends on: (A1); [ext: the C\*-inductive-limit construction — the norm closure of an upward-directed union of C\*-subalgebras of a common ambient algebra is a C\*-algebra and is the smallest one containing them all. tier (d), not retrieved] +- This is why GLRV99's superselection apparatus is cohomological rather than algebraic. + +### (R2) Essential duality lies strictly between locality and Haag duality + +For a representation family, the dual net is `𝒜_π^d(𝒪) := ⋂_{𝒪₁ ⊥ 𝒪} π_{𝒪₁}(𝒜(𝒪₁))′`; +*essential duality* asks that it be local, *Haag duality* that it equal +`π_𝒪(𝒜(𝒪))″`. + +- Source: [GLRV99] §1.1 · tier (a) · **asserted** +- Verbatim: + > This property is stronger than locality but not as strong as Haag duality which demands that $\p_{\cO}(\cA(\cO))'' = \cA_{\p}^d(\cO)$ for all $\cO \in \cK$. +- Depends on: (R7); the availability of `𝒪^⊥` as an index set, i.e. (D1) + +### (R3) [GLRV99] Lemma 2.1 — the regular diamonds absorb any point of the causal complement + +Let `𝒪` be a regular diamond and `p ∈ 𝒪^⊥`. Then some regular diamond `𝒪₁` +satisfies `𝒪 ∪ {p} ⊂ 𝒪₁`. + +- Source: [GLRV99] Lemma 2.1 · tier (a) · **sketched in source**, full proof cited elsewhere +- Depends on: (D2)'s regularity conditions; (A11); [ext: Brown — a compact, locally flatly embedded, two-sided topological submanifold boundary admits a collar neighbourhood, so the base of a regular diamond has an open neighbourhood in the same Cauchy surface with the same regularity. tier (d), not retrieved]; [ext: Verch — the detailed proof, and the existence of an acausal Cauchy surface through `p` meeting `J(Ḡ)` inside a regularity-preserving neighbourhood. tier (d), not retrieved] +- Proof route: (1) fix a smooth foliation into acausal Cauchy surfaces [global hyperbolicity, (A11)]; (2) enlarge `Ḡ` to a neighbourhood that is again a regular base [ext: Brown]; (3) find an acausal Cauchy surface through `p` with `J(Ḡ)` inside the transported neighbourhood [ext: Verch]; (4) attach a tubular neighbourhood of a curve to `p` [the two-sidedness clause of (D2)]. +- Step 3 is load-bearing and rests entirely on the unfetched reference. + +### (R4) [GLRV99] Lemma 2.2 — the causally disjoint pairs of points are pathwise connected, with one exception + +- Source: [GLRV99] Lemma 2.2 · tier (a) · **proved in source** +- Verbatim: + > ${\cal X}_{M,g}$ is pathwise connected except when its Cauchy surfaces are noncompact and 1--dimensional in which case there are precisely two path--components corresponding to $x$ being causally to the left or to the right of $y$. +- Depends on: (A11); (A2a); (D3) — the *neighbourhood-buffered* form of ⊥, consumed in step 2 and not replaceable by the naive reading; [ext: elementary homotopy theory — a strong deformation retract induces a bijection of path components. tier (d), not retrieved] +- Proof route: (1) build a homotopy retracting onto pairs in one Cauchy surface [the foliation, (A11)]; (2) check the image stays in `𝒳_{M,g}` — **this step consumes exactly (D3)'s open-neighbourhood buffer and fails for the naive reading of ⊥**; (3) conclude a bijection on path components [ext: homotopy theory]; (4) split by the topology of the Cauchy surface [(A2a)]. +- GLRV99 records `It may be known to experts, but as we have not found it in the literature, we put it on record here.`, so the corpus is this row's primary source. + +### (R5) [GLRV99] Lemma 3A.1 / Cor. 3A.2 — connectedness transported from the space to the poset + +- Source: [GLRV99] Lemma 3A.1, Cor. 3A.2 · tier (a) · **proved in source** (3A.1); **asserted** (3A.2) +- Verbatim: + > Let $\cal{P}$ be a base for the topology of a space $M$ and ordered under inclusion and suppose the elements of $\cal{P}$ are open, (non-empty) and path--connected. Then an open subset $X$ of $M$ is path--connected if and only if $\cP_X$:=$\{\cO\in\cP:\cO\subset X\}$ is connected. +- Depends on: (A6); (A7) +- The bridge lemma of the whole apparatus: every connectedness claim GLRV99 makes about the *poset* is obtained by applying this to a topological one. + +### (R6) The poset of regular diamonds is connected, each `𝒪^⊥` is connected, and the graph of ⊥ is connected — except in two dimensions + +- Source: [GLRV99] §3.1 · tier (a) · **proved in source** as a two-step derivation +- Verbatim: + > By virtue of Lemma 3A.1, we know that $\cal{K}$ is connected and, see Lemma 2.2, that $\cO^\perp$ is connected except when $M$ is two dimensional with a non--compact Cauchy surface. +- Depends on: (R4); (R5); (A6); (A2a) + +### (R7) The dual-net operation is an antitone Galois-type map + +`𝒜 ⊂ 𝒜^dd`; `𝒜 ⊂ ℬ` implies `ℬ^d ⊂ 𝒜^d`; hence `𝒜^d = 𝒜^ddd`; and `𝒜` local +implies `𝒜^dd` local. + +- Source: [GLRV99] §3.2 · tier (a) · **proved in source** +- Verbatim: + > is the largest net local relative to $\cA^d$, $\cA\subset\cA^{dd}$. However $\cA\subset\cB$ implies $\cB^d\subset\cA^d$, so that $\cA^d=\cA^{ddd}$. A net $\cA$ is said to be {\it local} if $\cA\subset\cA^d$ and then $\cA^{dd}\subset\cA^d=\cA^{ddd}$ so that $\cA^{dd}$ is local, too. +- Depends on: (D1) a), b), c) — GLRV99 notes relative locality satisfies their analogues +- Proof route: (1) `𝒜^d` is the largest net relatively local to `𝒜` [the formula]; (2) `𝒜 ⊂ 𝒜^dd` [step 1]; (3) `d` is order reversing, so `𝒜^d = 𝒜^ddd` [steps 1–2]; (4) locality propagates [step 3]. +- The algebra-side shadow of the ⊥-Galois connection on 𝒦; the index-set version is (R9). + +### (R8) The Extension Theorem — connectedness of each `𝒪^⊥` lets essential duality replace Haag duality + +- Source: [GLRV99] Thm 3A.7 · tier (a) · **proved in source** +- Verbatim: + > If each $\cal{O}^\perp$ is connected, every object $\pi$ of {\rm Rep}$^\perp\cA$ admits a unique extension to an object of {\rm Rep}$^\perp\cA^{dd}$. Furthermore there is a canonical isomorphism of $W^*$--categories {\rm Rep}$^\perp\cA$ and {\rm Rep}$^\perp\cA^{dd}$. +- Depends on: (A3); (R7); [GLRV99] Lemma 3A.5; [GLRV99] Thm 3A.6 +- The printed proof cites "Lemma 3.A.4" where Lemma 3A.5 is needed — see `## Not investigated`. + +### (R9) ⊥̃ and ⊥̂ inherit a) and b) but not c); both operations are idempotent; all three relations coincide when 𝒦 is directed + +- Source: [GLRV99] Appendix Ch. 3 · tier (a) · **asserted in source; proved in this note** +- Verbatim: the quote under (D5). +- Depends on: (D1) a), b), c); (A1) for the coincidence clause +- Proof (coincidence): `⊥ ⊆ ⊥̂` — directedness supplies a common upper bound, and uses **no axiom**. `⊥ ⊆ ⊥̃` — given `O₁ ⊥ O₂`, directedness supplies `O₄ ≥ O₁, O₂`, c) supplies `O₃` with `O₄ ⊥ O₃`, and b) applied twice gives `O₁ ⊥ O₃` and `O₂ ⊥ O₃`; this uses **b), c) and directedness, but not a)**. +- Proof (idempotence): `⊥̂` is idempotent with **no axiom** — its defining clause is already carried by `⊥̂`. `⊥̃` is idempotent **using a)**: if `O₃` witnesses `O₁ ⊥̃ O₂`, then `O₂` witnesses `O₁ ⊥̃ O₃`, which needs `O₃ ⊥ O₂` obtained from `O₂ ⊥ O₃` by symmetry. +- So **a) is load-bearing for idempotence of ⊥̃ and for nothing else in this cluster, while b) and c) are load-bearing for the coincidence.** No source locates this. + +### (R10) For regular diamonds the gap between ⊥ and ⊥̃ is a boundary effect + +- Source: [GLRV99] Appendix Ch. 3 · tier (a) · **proved in source** for the implication, **asserted** for the exhaustion +- Verbatim: + > the difference between the relations $\perp$ and $\tilde\perp$ is, in this sense, a boundary effect. +- Depends on: (D2); (R9) + +### (R11) On the sieves with non-trivial causal complement, ⊥̃ = ⊥̂ + +- Source: [GLRV99] Appendix Ch. 3 · tier (b) read · **proved in source** (one line) +- Depends on: (R9); sieves closed under union +- GLRV99's diagnosis of why the two differ on regular diamonds: `The difference between $\tilde\perp$ and $\hat\perp$ merely reflects the potential difficulty of finding suitably large regular diamonds.` — i.e. exactly a failure of directedness. + +### (R12) [GLRV99] Lemma 3A.3 — components of a poset from components of a covering family of sieves + +- Source: [GLRV99] Lemma 3A.3 · tier (a) · **proved in source** +- Depends on: each member of the covering family is a sieve; `I` connected for the second clause + +### (R13) [GLRV99] Lemma 3.A4 — `μ` and `ν` are mutually inverse on causally closed open sets and sieves + +With `μ(X) := {𝒪 ∈ 𝒦 : 𝒪 ⊂ X}` and `ν(𝒮) := ⋃{𝒪 : 𝒪 ∈ 𝒮}`. + +- Source: [GLRV99] Lemma 3.A4 · tier (a) · **proved in source** +- Verbatim: + > When restricted to causally closed open sets and sieves, the maps $\mu$ and $\nu$ are inverses of one another. +- Depends on: (A6); (A9); (A10) +- **This is the result most directly about the object of this note**: it is the precise sense in which the poset `(𝒦, ⊥)` loses no information relative to the causally closed open sets of `M`, and it is what reconciles (C4)'s two readings of `𝒪^⊥`. + +### (R14) [GLRV99] Lemma 3.6 and its dimensional case analysis — the components of `Σ^⊥₁` determine the braiding + +In dimension `> 2` the relevant poset of 1-simplices is connected; in dimension +two with non-compact Cauchy surfaces it has exactly two components; in dimension +two with compact Cauchy surfaces the graph of ⊥ is connected but the simplex +poset still has two components. + +- Source: [GLRV99] Lemma 3.6 and the discussion following · tier (a) · **proved in source** +- Depends on: (R4); (R6); (R12); (D2) +- **This is where the index set alone decides whether the statistics is symmetric or braided.** + +### (R15) A net tending spacelike to infinity exists when 𝒦 is directed and when the Cauchy surface is non-compact; the compact case is open + +- Source: [GLRV99] §3.1 · tier (a) · **asserted** +- Verbatim: + > Such a net obviously exists whenever $\cal{K}$ is directed but it continues to exist for an arbitrary globally hyperbolic spacetime with a noncompact Cauchy surface. The question of whether one can find a suitable substitute for globally hyperbolic spacetimes with compact Cauchy surfaces is still open, +- Depends on: (A1); (A11) +- The geometric input to the construction of a left inverse, hence to the classification of statistics and charge conjugation. GLRV99's own mitigation is (A19). + +### (R16) The regular diamonds are not directed in general and are **never** directed when the Cauchy surface is compact + +- Source: [GLRV99] §3.1 · tier (a) · **asserted** +- Verbatim: + > may not be directed although it will be in cases of interest. However, when $M$ is globally hyperbolic with a compact Cauchy surface, $\cK$ will never be directed and we shall meet problems akin to those on the circle. +- Depends on: (D2)'s `𝒪^⊥ ≠ ∅` clause — the unstated reason is that a diamond over the whole compact Cauchy surface would have empty causal complement +- This makes (R1)'s negative half bite, and is why (R15)'s compact case is open. + +### (R17) [GLRV99] — duality for ⊥̂ follows from duality for ⊥ plus additivity, via Lemma 2.1 + +- Source: [GLRV99] §5.2 · tier (a) · **proved in source** +- Verbatim: + > Under the above assumptions, the net satisfies duality for the relation $\hat\perp$, namely $$ \cA(\cO)=\cap_{\cO_1\hat\perp\cO}\cA(\cO_1)' $$ +- Depends on: (R3); additivity of the net; (A17) +- Proof route: (1) Lemma 2.1 gives, for each point of `𝒪₁`, regions witnessing `𝒪 ⊥̂ 𝒪_x` [(R3)]; (2) additivity and duality collapse the two intersections [additivity, (A17)]. +- **The only place in the corpus where (R3) does real work in the main line**, and the justification for GLRV99's remark that the two notions of duality coincide for additive nets over regular diamonds. + +### (R18) [GLRV99] — closed-form causal complement on a wedge index set + +`W(E,t)^⊥ = W(E′,t)`, with `E′` the interior of the complement of the hemisphere `E`. + +- Source: [GLRV99] §5.1 · tier (a) · **asserted** (`The following proposition immediately follows.`) +- Verbatim: + > {$(i)$} $W(E,t)^{\perp} =\hat{r}_{\partial E,t}W(E,t)=W(E',t)$, where $E'$ denotes the interior of the complement of $E$. +- Depends on: (D20) +- The corpus's only closed-form computation of `^⊥` outside Minkowski and conformal settings; the source also records that each wedge here is a diamond, so the two families are not disjoint. + +### (R19) [HM06]'s account of directedness — and it disagrees with (R1) + +HM06 derives the inductive limit from isotony alone and then notes that +non-directedness can in many cases be circumvented. + +- Source: [HM06] §2.1 · tier (a) · **cited elsewhere** +- Verbatim: + > In some spacetimes, the set of double cones is not directed. In many such cases, it is still possible to define the quasilocal algebra by means of more sophisticated techniques \cite{glob}. +- Depends on: [ext: Fredenhagen, *Global observables in local quantum physics* — a construction of a global observable algebra for a net over a non-directed index set, so that failure of directedness does not by itself obstruct the passage to a single ambient C\*-algebra. tier (d), not retrieved] +- **The corpus's most important unreconciled disagreement.** (R1) says the construction is *denied*; this says it can often be circumvented. The two are not formally contradictory — GLRV99 denies the naive norm closure, which HM06 does not claim — but the reconciliation lives in an unfetched article. + +### (R20) Reeh–Schlieder plus `Ō₁ ⊂ 𝒪₂` gives a standard inclusion + +- Source: [HM06] §2.4 · tier (a) · **asserted** +- Verbatim: + > Then if $O_1,O_2$ are double cones such that the closure $\ol{O}_1$ of $O_1$ is contained in $O_2$, then the pair $(\alg{R}(O_1),\alg{R}(O_2))$ is a standard inclusion of von Neumann algebras. +- Depends on: (A5); (D9) +- **The clearest instance in the corpus of a theorem whose only geometric content is a relation on 𝒦.** The unstated intermediate step — that `Ō₁ ⊂ 𝒪₂` makes `𝒪₁′ ∩ 𝒪₂` contain a region — is itself a claim about 𝒦 that no source proves; it is exactly the collar clause, and the Ordering theorem above is its proof under (T). + +### (R21) The funnel property implies the Hilbert space is separable + +- Source: [HM06] Prop. `separable` · tier (a) · **proved in source** +- Depends on: (A13); (A5); [DL84] Prop. 1.6 as an independent route (tier (b), `mineru-unchecked`) +- HM06 records that this is the only place in its chapter where separability is needed, and is openly sceptical of its physical warrant. + +### (R22) Concrete models exist in which the funnel property fails + +- Source: [HM06] §2.4 · tier (a) *for HM06 making the claim*; the claim itself **cited elsewhere** +- Depends on: [ext: Horuzhy, *Introduction to Algebraic Quantum Field Theory* — exhibits models of a net of local algebras in which no type I factor interpolates between the algebras of a region and of a larger region containing its closure. tier (c), no locator, not retrieved] +- No such model is named in any fetched source; (R39) supplies a named one by a different route. + +### (R23) The funnel property holds for free fields + +- Source: [HM06] §2.4 · tier (a) for the claim · **cited elsewhere** — and the cited source is [dB74], in this corpus +- Depends on: (R57); (R60) + +### (R24) Schlieder from microcausality, weak additivity and the spectrum condition, for strictly spacelike separated pairs + +- Source: [HM06] Prop. `schlieder` · tier (a) · **cited elsewhere** +- Depends on: (D7); [ext: Schlieder — for a pair of commuting von Neumann algebras arising from spacelike separated regions of a net with weak additivity and positive energy, the product of two non-zero elements, one from each, is non-zero. tier (d), not retrieved] + +### (R25) "Strongly spacelike separated" lies strictly between spacelike and strictly spacelike separated + +- Source: [HM06] §3.3 · tier (a) · **asserted in source; proved in this note** +- Verbatim: + > \begin{fact} If $O_1$ and $O_2$ are strictly spacelike separated, then they are strongly spacelike separated. \end{fact} +- Depends on: (D7); (D8); (A: 𝒦 contains, for each region, an enlargement containing its closure) +- Proof: from a neighbourhood `N` of `0` with `O₁ + x` spacelike to `O₂` for all `x ∈ N`, pick `ε` with `B(0,ε) ⊆ N`; translation covariance gives `O₁ + x` spacelike to `O₂ + y` for `|x|,|y| < ε/2`, and the unions over those translates are the required enlargements. **The proof is model-specific**: it needs 𝒦 closed under small enlargements, which (D2) records that double cones in a curved spacetime lack. + +### (R26) Schlieder from microcausality and property B, for strongly spacelike separated pairs + +- Source: [HM06] Prop. `frees` · tier (a) · **proved in source** +- Depends on: (A20); (D8) +- The printed proof opens "Let `O₁` and `O₂` be **strictly** spacelike separated" where the statement says **strongly**; the proof's second sentence is the definition of *strongly* unpacked, so the proposition as stated is proved and the first line is a typo. + +### (R27) The split property fails for a wedge and its causal complement + +- Source: [HM06] §3.3 · tier (a) · **proved in source** +- Depends on: `ℛ(W)` and `ℛ(W′)` being type III₁ factors; HM06's remark that a factor and its commutant have the same type +- HM06's own type III₁ proposition carries the escape clause `Then either $\al R=\7C I$ or $\al R$ is a type III$_1$ factor.`, so every argument of the shape "split for all pairs ⇒ type I ⇒ contradiction" silently assumes the local algebras are not the scalars. + +### (R28) The funnel property upgrades to the split property for strictly spacelike separated pairs + +- Source: [HM06] §3.3 · tier (a) · **asserted** +- Depends on: (A13); (D7) + +### (R29) The implication chain among independence notions + +- Source: [HM06] §3.2 · tier (b) read · **cited elsewhere** +- Depends on: [ext: Summers — a survey ordering the independence conditions for a pair of commuting von Neumann algebras by logical strength. tier (c), no locator, not retrieved] + +### (R30) [BGL93] Prop. 1.3 — five index-set properties of `𝒦̃`, including that it is closed under `′` and is not directed + +- Source: [BGL93] Prop. 1.3 · tier (a) · **asserted** (`\proof Immediate.`) +- Verbatim: the three clauses quoted under (D12). +- Depends on: `M̃` the universal covering of compactified Minkowski space and `𝒞̃` its conformal group +- Clause (v) is `proved` on inspection, but the proof needs `𝒪″ = 𝒪`, which BGL93 never states. + +### (R31) For the double cones of Minkowski space, directedness is what makes the quasilocal algebra a direct limit + +- Source: [BGL93] §1 · tier (a) · **asserted** +- Verbatim: the `direct set` quote under (D12). + +### (R32) The conformal net extends uniquely to the covering + +- Source: [BGL93] Lemma 1.9, Prop. 1.10 · tier (a) · **proved in source** +- Depends on: (R30)(ii) — transitivity of the conformal action on `𝒦̃` + +### (R33) Essential duality holds automatically for a conformally covariant pre-cosheaf + +- Source: [BGL93] Thm 2.3 · tier (a) · **proved in source** +- Depends on: (R32); [BGL93] Prop. 2.1 + +### (R34) Duality on `S¹` holds with no assumption beyond positivity of the energy + +- Source: [BGL93] §2 · tier (a) · **asserted** for the models +- Depends on: (R33); [ext: Hislop–Longo — for the free massless scalar field the modular group of the algebra of a double cone acts geometrically, giving duality. tier (c), no locator, not retrieved] +- (R42) identifies by name what this describes: duality on the light-ray is equivalent to **strong additivity**, and fails because the complement of an interval of `ℝ` is disconnected while on `S¹` it is a single proper interval. + +### (R35) [BGL93] Cor. 2.7 — under conformal invariance plus a spectral condition, every local algebra is the hyperfinite type III₁ factor + +- Source: [BGL93] Remark 2.6, Cor. 2.7 · tier (a) for the statement; the result **cited elsewhere** (`\proof Immediate, see [\ref(Long1)].`) · **survives at (c), `unverified`** +- Depends on: (R36); conformal invariance; exponential eigenvalue growth; [ext: Longo — the interpolating type I factor structure forces the hyperfinite type III₁ factor. tier (c), no locator, not retrieved] +- **How much weight this can carry:** it is conditional on Remark 2.6's spectral hypothesis and on an unretrieved citation, so an argument needing "local algebras are not type I" should hang on [HM06]'s type III₁ proposition instead, carrying its `ℂ𝟙` escape clause. + +### (R36) The "distal split property" is an existential over a single pair of regions + +- Source: [BGL93] §3 assumption (b) · tier (a) · it is an **assumption**, not a result +- Verbatim: + > \item{$(b)$} Distal split property holds, i.e there exist two regions $\O_1\subset \O'_2$ in $M$ such that $\R(\O_1)$ and $\R(\O_2)$ generates a $W^*$-tensor product. +- **It imposes no relation on 𝒦 at all** — one split pair anywhere suffices — and is therefore strictly weaker than the funnel property, not a metric strengthening of the separation relation. It upgrades to the universal form under a **transitively acting symmetry group and `d > 2`**. + +### (R37) The distal split property forces uniqueness of the covariant representation + +- Source: [BGL93] Thm 3.1 · tier (a) · **proved in source** +- Depends on: (R36) + +### (R38) Essential duality for wedges from geometric modular action + +- Source: [BGL93] Thm 3.3 · tier (a) · **proved in source** by reference to earlier proofs +- Depends on: (R33) +- The printed proof cites a "Lemma 3.4" that does not exist; Lemma 3.2 is meant. + +### (R39) A named non-split net: `ℬ(𝒪) = 𝒜(π⁻¹𝒪)` + +Let `𝒜` be a Poincaré covariant net on `(d+1)`-dimensional Minkowski space and +`π` the projection onto `d` dimensions; then `𝒪 ↦ 𝒜(π⁻¹𝒪)` is a net on `d` +dimensions which BGL93 labels non-split. + +- Source: [BGL93] §3, closing paragraph · tier (a) for the construction; the attribution is to a **private remark** of Buchholz, so **no locator can ever exist** · **proved in source** as a short verification +- Depends on: (R38) +- **The corpus's only concrete non-split example.** BGL93 only *labels* it non-split and leaves unwritten both that `ℬ` satisfies its assumption (a) and the contraposition; and the argument needs `d > 2`. (R59)(b) reaches the same conclusion by a route with fewer external edges. + +### (R40) The proper intervals of `S¹` are not directed + +- Source: [KOE03] §1.2 · tier (a) · **asserted** +- Verbatim: the quote under (D14). +- Depends on: `I′ ≠ ∅` as a membership condition +- **The corpus's load-bearing non-directed index set.** + +### (R41) What the failure of directedness costs: DHR must be replaced, and Doplicher–Roberts reconstruction is lost + +- Source: [KOE03] §1.3 · tier (a) · **cited elsewhere** +- Depends on: (R40) + +### (R42) Haag duality on `S¹` follows from the general assumptions but may fail on the light-ray + +- Source: [KOE03] §1.3 · tier (a) · **asserted** (`S¹` half) +- Depends on: (R40) +- The mechanism is the index set's topology: the complement of an interval of `ℝ` is disconnected, of an interval of `S¹` is a single proper interval. + +### (R43) Strong additivity of a subnet removes the isotony problem for local relative commutants + +- Source: [KOE03] §1.2–1.3 · tier (a) · **proved in source** +- Depends on: (R42); locality; the `⋐` relation + +### (R44) The dual net on the light-ray makes any chiral theory strongly additive + +- Source: [KOE03] §1.3 · tier (a) · **cited elsewhere** +- Depends on: (R42) + +### (R45) Inner and outer continuity of the local algebras along the `⋐` relation + +- Source: [KOE03] §1.3 · tier (a) · **cited elsewhere** +- Depends on: scale invariance + +### (R46) The split property for chiral nets is stated over the `Ī₁ ⊂ I₂` relation + +- Source: [KOE03] §1.3 · tier (a) · **definition** plus an **asserted/cited** implication from nuclearity +- Verbatim: the quote under (D15). +- Depends on: [ext: Buchholz–Wichmann — a nuclearity condition on the energy-level density implies the split property for sufficiently separated regions. tier (d), no locator, not retrieved] + +### (R47) Double cones are causally complete + +- Source: [NAA13] §1 · tier (a) · **asserted** +- Verbatim: the quote under (D10). + +### (R48) The lattice index set is directed, ⊥ is disjointness, and the quasi-local algebra is the inductive limit + +- Source: [NAA13] §2.4 · tier (a) · **proved in source** at the level of the construction +- Depends on: Γ countable; (A1), used silently + +### (R49) C\*-level duality `𝒜(Λ)^c = 𝒜(Λ^c)` for finite Λ + +- Source: [NAA13] §2.4 · tier (a) · **proved in source** for the finite case +- Depends on: (R48); [ext: NAA13's cited text — the relative commutant of a finite-region algebra inside the quasi-local algebra of a spin system is the algebra of the complementary region. tier (c), no locator, not retrieved] + +### (R50) Haag duality for cones: one inclusion is free from locality, the other is an assumption + +- Source: [NAA13] §3 · tier (a) · the easy inclusion **proved in source** +- Depends on: (R48) + +### (R51) The superselection criterion quantifies over the cone index set + +- Source: [NAA13] §3 · tier (a) · **sketched** +- Depends on: (R50) +- Cones are named as an index set here and by [GLRV99] and are **defined by neither**; the definition lives on the unfetchable list. + +### (R52) [BFV01] — the index set of a locally covariant theory + +- Source: [BFV01] §2.4, first document body · tier (a) · **definition** +- Verbatim: the quote under (D16). +- Depends on: `(M,ḡ)` an object of `𝔐` + +### (R53) [BFV01] — the causal complement as a largest open set + +- Source: [BFV01] §2.1, first document body · tier (a) · **definition** +- Verbatim: the quote under (D17). +- The existence of a *largest* such open set is not argued. + +### (R54) [BFV01] Prop. `localnet` — a locally covariant theory yields a Haag–Kastler net over `𝒦(M,ḡ)` + +- Source: [BFV01] Prop. `localnet`, first document body · tier (a) · **proved in source**, all four clauses +- Depends on: (R52); (R53); the functor axioms +- **The corpus's only derivation of the Haag–Kastler index-set structure from a categorical datum**, and the reason (H2) is a scope limit rather than a defect. + +### (R55) [BFV01] — the fattening lemma: causally separated regions can be enlarged while staying causally separated + +- Source: [BFV01], inside the proof of Prop. `localnet`, first document body · tier (a) · **asserted** +- Depends on: (R52); (R53); (A11) +- BFV01 asserts in one sentence what [GLRV99] (R3) sketches over a page. + +### (R56) [BFV01] — the inductive limit attributed to isotony alone + +- Source: [BFV01] §2.4 footnote, first document body · tier (a) · **asserted** +- Depends on: isotony; and, unstated, that the bounded open subsets of Minkowski space are directed + +### (R57) [dB74] — the `𝒩`-thickened separation relation and the "almost factors" standing hypothesis + +- Source: [dB74] §II · tier (b), `mineru-unchecked` · **cited elsewhere** +- Verbatim: the shape-1 and standing-hypothesis quotes under (D18). +- Depends on: (A5) in dB74's form — Ω cyclic and separating for open regions with non-empty spacelike complement + +### (R58) [dB74] Cor. 2.4 — a normal product state yields interpolating type I factors, and conversely + +- Source: [dB74] Cor. 2.4 · tier (b), `mineru-unchecked` · **proved in source**; the converse **asserted** +- Depends on: (R57) + +### (R59) [dB74] — two classes of configurations admitting **no** normal product state + +(a) regions whose closures are not spacelike separated (asserted, free field); +(b) any two spacelike separated regions each mapped into itself by a common +translation. + +- Source: [dB74] §II, items a) and b), **p. 292** · tier (b), `mineru-cross-checked-against-PDF-text-layer` · (a) **asserted**, (b) **proved in source** +- Depends on: isotony; clustering; (A5) +- **(b) is the corpus's most economical non-example**: it needs no type classification, and it covers both (R27)'s wedge pair (**in `d ≥ 3` only** — in 1+1 no translation fixes both `W` and `W′`, so the two routes are incomparable rather than nested) and every region of (R39)'s net. Neither source cites dB74 for it. The footnote on item b) reads *This example is due to Araki*. + +### (R60) [dB74] — the positive result for the free neutral massive scalar field + +- Source: [dB74] §III · tier (b), `mineru-unchecked` · **proved in source** (the proof runs past the converted pages, so no route) +- Depends on: (D18) shape 3 — smooth boundaries and positive distance + +### (R61) [DL84] — the split property expresses independence of regions separated by non-zero distance + +- Source: [DL84] §0 · tier (b), `mineru-unchecked` · **asserted** +- Verbatim: + > expresses the statistical independence of any bounded region in space-time from any other region space-like separated by non-zero distance +- Depends on: (D18) shape 3, which DL84 echoes from dB74 — and dB74's cached scope (R60) is narrower than either DL84's or HM06's paraphrase. + +### (R62) [DL84] — the split property is stated with **no separation relation at all** + +- Source: [DL84] §1 · tier (b), `mineru-unchecked` · **definition** +- **The cleanest evidence in the corpus that the separation relation belongs to the index set and not to the algebras**: at the two-algebra level it simply is not present. + +### (R63) [DL84] announces field theories that do not satisfy the split property + +- Source: [DL84] §§9–10, **not converted** · tier (b) for the announcement +- Would supply further concrete non-split examples; the highest-value extension available to a later run. + +## Hypotheses + +| (A#) | Statement | Class | Evidence | Witness | Scope | Tier | Used by | +|---|---|---|---|---|---|---|---| +| (A1) | 𝒦 is directed under inclusion | model-dependent | [GLRV99] §3.1; [KOE03] §1.2; [HM06] §2.1 | fails: the proper intervals of `S¹` ([KOE03], stated outright); also the regular diamonds of any globally hyperbolic spacetime with compact Cauchy surface ([GLRV99], class fact, no spacetime named). holds: the open double cones of Minkowski | local | a | (R1), (R9), (R15), (R16), (R19), (R31), (R40), (R48) | +| (A2) | 𝒦 is connected as a poset | provable | [GLRV99] Lemma 3A.1 applied to (A2a) | — | local | a | (R6), (R14) | +| (A2a) | `M` is path-connected | model-dependent | implicit in [GLRV99] §2.1, explicit in [BFV01] §2 (`connected`) | fails: the disjoint union of two copies of Minkowski space (tier (b) — the ingredients are quoted, the assembly is mine). holds: 4-dimensional Minkowski | standing, **implicit** in [GLRV99] | a/b | (R2), (R4), (R6) | +| (A3) | each `𝒪^⊥` is connected | model-dependent | [GLRV99] §3.1, §3.2 | fails: regular diamonds in 2-dimensional Minkowski space, where the complement splits into a left and a right part. holds: 4-dimensional Minkowski | local | a | (R6), (R8), (R14) | +| (A4) | the graph of ⊥ is connected | model-dependent | [GLRV99] Lemma 2.2, proof read | fails: 2-dimensional Minkowski (Cauchy surface `ℝ`). holds: dimension `> 2` | local | a | (R14) | +| (A5) | the vacuum is cyclic and separating for local algebras | provable / assumed | [HM06] §2.3; [dB74] §II as a standing assumption | — | standing in [dB74] | a/b | (R20), (R21), (R57), (R59) | +| (A6) | 𝒦 is a base for the topology of `M` | provable | [GLRV99] Lemma 3A.1 and `Both sets have in common that they form a base for the topology of $M$` | — | local | a | (R5), (R6), (R13), and the Ordering theorem | +| (A7) | members of 𝒦 are open, non-empty, path-connected | provable | [GLRV99] §2.1 regularity conditions | — | local | a | (R5), (R6) | +| (A8) | condition c) for ⊥, ⊥̃, ⊥̂ | definitional for ⊥; provable for ⊥̃, ⊥̂ in the applications | [GLRV99] §3.1 and Appendix Ch. 3 (`c) remains to be checked`) | — | standing / local | a | (R7), (R9) | +| (A9) | ⊥ on `Open(M)` is *local*: `X ⊆ ⋃𝒪ᵢ` with every `𝒪ᵢ ⊥ 𝒪` gives `X ⊥ 𝒪` | provable | [GLRV99] Appendix Ch. 3, asserted as obvious | — | local | a | (R13) | +| (A10) | members of 𝒦 are causally complete, `𝒪 = 𝒪^⊥⊥` | provable for the index sets used | [NAA13] §1 and [GLRV99] §2.1 both assert it without proof; **independent of a),b),c)** by (X19) | — | mixed: membership condition in (D19), observation in (D10) | a | (R13), (R30) | +| (A11) | `(M,g)` is globally hyperbolic | model-dependent | [GLRV99] §2.1; [BFV01] §2, both standing | no failing spacetime is named in the corpus; the classical examples rest on recall, so this row is at best (d) on the failing side | standing | a/d | (R3), (R4), (R15), (R55) | +| (A12) | the vacuum Hilbert space is separable | provable relative to (A13) | [HM06] Prop. `separable`; [KOE03] builds it into its axioms; [DL84] Prop. 1.6 independently (tier (b), `mineru-unchecked`) | — | standing in [HM06], [KOE03] | a/b | (R21) | +| (A13) | the funnel / split property | model-dependent | [HM06] §2.4; [BGL93] §3; [KOE03] §1.3 | fails: [BGL93]'s dimensional-reduction net (R39), and every configuration of (R59)(b). holds: the free neutral massive scalar field (R60); conformal nets under (R35) | local | a | (R21), (R23), (R28), (R35), (R37) | +| (A14) | how much separation the independence results need | model-dependent | [HM06] §3.3; [dB74] §II–III; [DL84] §0; [BGL93] §3 | fails: two double cones in 4-dimensional Minkowski whose closures touch (R59)(a). holds: the same pair pushed apart | local | a/b | (R20), (R24), (R25), (R26), (R28), (R59), (R61) | +| (A15) | every region has non-empty causal complement | model-dependent | [dB74] §II standing; membership condition in (D2), (D14), (D19) | fails: a time-slab around a compact Cauchy surface in [BFV01]'s `𝒦(M,ḡ)`. holds: every open double cone in Minkowski | standing in [dB74] | a/b | (R16), and axiom c) | +| (A16) | members of [BFV01]'s `𝒦(M,ḡ)` are open and connected | model-dependent | [BFV01] §2.4 — **not in the definition, forced by the next sentence** | fails on the literal reading: `∅`, `{x}`, and `{x,y}` for `x`, `y` spacelike. holds: any relatively compact causally convex open connected set | standing, **implicit** | a/b | (R52), (R54), and (X15) direction 1 | +| (A17) | Haag duality, or essential duality, for a given index set | model-dependent — **and dependent on which index set** | [BGL93] Thm 2.3; [KOE03] §1.3; [GLRV99] §1.1; [HM06]; [NAA13] §3 | fails: [BGL93]'s net `𝒜ₙ` on the light-ray, i.e. a non-strongly-additive chiral theory. holds: conformally covariant pre-cosheaves (R33); the free massless scalar (R34) | standing / local | a | (R2), (R8), (R17), (R42), (R50) | +| (A18) | surjectivity of the projection from the graph of ⊥ onto 𝒦 | provable | [GLRV99] §3.1, asserted | — | local | a | (R14) | +| (A19) | local intertwiners equal global intertwiners | provable for Minkowski; open in general | [GLRV99] Ch. 5, postulated | — | local | a | (R15)'s mitigation | +| (A20) | property B | provable from microcausality, the spectrum condition and weak additivity | [HM06] Prop. `prop-B`; [GLRV99] §3.2 | — | standing in [HM06] | a | (R26) | +| (A21) | the time-slice axiom | provable for a named model | [BFV01] §4 — the CCR/Weyl algebra of the Klein–Gordon equation on any globally hyperbolic spacetime | — | local | a | — | +| (A22) | the wedges separate spacelike points, i.e. regular diamonds are intersections of wedges | open | [GLRV99] Ch. 5, assumed | neither a proof nor a failing spacetime could be produced | local | a | (R18), (R20)'s wedge analogue | + +## Degeneracies and boundary cases + +| Case | Effect on the adopted form | Tier | +|---|---|---| +| intended case is nonvacuous | named instances abound and were checked one by one against a), b), c): open double cones in Minkowski ([HM06], [NAA13]); regular diamonds in a globally hyperbolic spacetime ([GLRV99]); proper intervals of `S¹` ([KOE03]); `𝒦̃` ([BGL93], c) via Prop. 1.3(iv)); `𝓛` and `𝒦 ∪ 𝒲` ([GLRV99]); wedges in Minkowski (c) via the opposite wedge); `𝒫_f(Γ)` ([NAA13]) | a | +| zero object / scalars | `𝒦 = ∅`: a), b), c) hold vacuously; no effect. `𝒦` a single element: c) fails unless that element is self-orthogonal | — | +| finite-dimensional | not a meaningful axis for an index set; the discrete analogue is `𝒫_f(Γ)` with `Γ` finite, which still satisfies c) via `∅` | — | +| commutative | not a meaningful axis; the order-theoretic analogue is `𝒦` a chain, which is **not** excluded by the adopted form (it is excluded only under irreflexivity — (X6), (H1)) | — | +| non-separable / non-σ-finite | no effect: these are conditions on the Hilbert space, and (A12) makes separability a *consequence* of (A13) rather than an input | b | +| type III | the intended case: the local algebras of an interesting net are type III₁, and (X32) turns that into the reason the collar clause cannot be dropped — subject to [HM06]'s `ℂ𝟙` escape clause | a/c | +| non-unital / degenerate representation | no effect at index-set level; [NAA13] fixes `𝒜(∅) = ℂI` explicitly rather than allowing a degenerate algebra | a | +| universally orthogonal index element | **admitted**: `∅ ∈ 𝒦` is ⊥ to everything including itself in (D11), and a bottom element ⊥ to everything is exactly (H1)'s construction. It satisfies c) while making c)'s intended guarantee empty | a | +| everything ⊥ everything | a), b), c) all hold; the *net* over such an index set collapses to a commutative one by locality, but the form itself is not contradicted | — | +| quantifier swap in c): `∀O₁ ∃O₂` ↦ `∃O₂ ∀O₁` | meaning changes: taking `O₁ := O₂` forces `O₂ ⊥ O₂`. False on double cones, true on `𝒫_f(Γ)` via `∅` — (X25) | — | +| quantifier swap: "∃ one region ⊥ to all *others*" | genuinely different from both, separated by the 2-element antichain — (X26) | — | +| quantifier swap inside the collar clause | `∃ one collar ∀ nested pairs` is false for double cones (the collar must fit inside arbitrarily small outer regions) and, under the strict collar clause, false for `𝒫_f(Γ)` too — (X28) | — | +| hypothesis dropped: a) symmetry | independent — witness: a 3-cycle on a 3-element antichain satisfies b), c) and fails a). Consequence: idempotence of ⊥̃ fails, by (R9) | — | +| hypothesis dropped: b) heredity | independent — witness: `{A ≤ B, C, D}` with `⊥ = {(B,C),(A,D)}` symmetrised. Consequence: `𝒪^⊥` is no longer a sieve, so (R13) and (R7) fail | — | +| hypothesis dropped: c) | independent — witness: a single element with `⊥ = ∅`. Consequence: `⊥ ⊆ ⊥̃` fails even under directedness, by (R9) | — | +| hypothesis reversed: b) anti-heredity | false in every geometric model; with a top element it produces a *top* orthogonal to everything including itself, **not** the everything-⊥-everything model — (X27) | — | +| hypothesis added: irreflexivity | strictly stronger — not derivable from a), b), c) (witness: (H1)'s bottom-element model). It is what would buy "comparable regions are never ⊥" and "𝒦 is not a chain" | — | +| hypothesis added: causal completeness | strictly stronger — 3-element antichain witness, (X19) | — | +| collar clause dropped from the separation relation | the split property degenerates to `𝒜(O) ⊆ 𝒩 ⊆ 𝒜(O)`, forcing every local algebra to be type I — (X32) | a/c | + +## Rejected formulations and refuted claims + +**Append-only.** + +| id | Candidate or claim | Disposition | Discriminator | Tier | Date | +|---|---|---|---|---|---| +| (X15) | the collar clause and the closure form `Ō₁ ⊆ O₂` as *the* separation relation for the split property | rejected (both, as the single adopted relation) | **(X1) separating object**, both directions — collar without closure: internally tangent double cones `O₂ = {|x₀|+\|x⃗\| < 1}`, `O₁ = {|x₀|+\|x⃗−c\| < 1/2}`, `c = (1/2,0,0)`, with collar `O₃ = {|x₀|+\|x⃗+c\| < 1/8}`, using the verified criterion that `D(B(a,r))` and `D(B(b,s))` are spacelike iff `\|a−b\| ≥ r+s`; closure without collar: `Λ₁ = Λ₂ = {0}` in `𝒫_f(ℤ)`, and (non-degenerately) `O = (−ε,ε)×Σ ⊂ O₂ = (−2ε,2ε)×Σ` over a compact Cauchy surface Σ. **(X5) conditional equivalence** — under (T) the closure form is strictly stronger; see the Ordering theorem | a/b | 2026-08-15 | +| (X18) | the causal complement as an **operation into 𝒦**, `O₁ ⊥ O₂ ⟺ O₂ ≤ O₁^⊥` | rejected | **(X1) separating object** — a double cone in Minkowski: the double cones spacelike to it have no maximum (translate away, then dilate inside `O′`). `𝒦̃` and the proper intervals of `S¹` do support the operation | a | 2026-08-15 | +| (X18′) | the complement as a **sieve-valued** operation `O ↦ {O₁ : O₁ ⊥ O}` | equivalent | — ([GLRV99] writes exactly this: `We write $\cO^\perp:=\{\cO_1\in\cK:\cO_1\perp\cO\}$.`) | a | 2026-08-15 | +| (X19) | causal completeness `O = O″` as an axiom | rejected | **(X1) separating object** — the 3-element antichain `{A,B,C}` with `⊥ = {(A,B),(B,A),(A,C),(C,A)}` satisfies a), b), c) while `B^⊥⊥ = {B,C} ⊋ ↓B`. Geometric realisation: a spacelike disc and its domain of dependence share a causal complement | — | 2026-08-15 | +| (X24) | [BGL93]'s *distal split property* as a phrasing of the separation relation | rejected | **(X5) conditional equivalence** — as written it is an existential over one pair of regions and constrains 𝒦 not at all; it upgrades to the universal form only under a transitively acting symmetry group **and** `d > 2` | a | 2026-08-15 | +| (X25) | c) with the quantifiers swapped | rejected | **(X2) degeneracy** — forces a self-orthogonal element; false on double cones, true on `𝒫_f(Γ)` via `∅` | — | 2026-08-15 | +| (X26) | "∃ one region ⊥ to all *others*" | rejected | **(X1) separating object** — the 2-element antichain `{A,B}` with `A ⊥ B`: the `≠`-form holds, the `∀`-including-self form fails | — | 2026-08-15 | +| (X27) | b) with the inclusion reversed (anti-heredity) | rejected | **(X1) separating object** — false in every geometric model. *The parenthetical claim that with a top element it collapses to everything-⊥-everything is itself refuted*: witness `{A, B ≤ T}` with `⊥ = {(A,B),(B,A)} ∪ {(T,X),(X,T)} ∪ {(T,T)}`, where `A ⊥̸ A` | — | 2026-08-15 | +| (X28) | one collar for all nested pairs | rejected | **(X1) separating object** — double cones: the collar must lie inside arbitrarily small outer regions | — | 2026-08-15 | +| (X32) | dropping the collar clause, leaving `O₁ ≤ O₂` | rejected | **(X2) degeneracy** — the split property becomes `𝒜(O) ⊆ 𝒩 ⊆ 𝒜(O)`, forcing every local algebra type I, contradicting the type III₁ structure — with [HM06]'s escape clause `Then either $\al R=\7C I$ or $\al R$ is a type III$_1$ factor.` attached | a/c | 2026-08-15 | +| (X9) | *claim*: [BFV01]'s `𝒦(M,ḡ)` is not an instance of the adopted form, witnessed by `∅`, `{x}`, `{x,y}` and a time-slab | refuted as stated | read literally `∅ ∈ 𝒦(M,ḡ)`, and BFV01's ⊥ is vacuously true against `∅`, so **c) holds everywhere via `∅`** and three of the four witnesses show only that BFV01's regions need not be open or connected. What survives: under the reading forced by BFV01's own `obj(𝔐)` sentence, c) fails at a time-slab around a compact Cauchy surface — **one witness, conditional on a reading BFV01 never states** | a | 2026-08-15 | +| (X7) | *claim*: the lattice index set is excluded by c) | refuted as stated — re-scoped | **[NAA13]'s own `𝒫_f(Γ)` contains `∅`** and fixes `𝒜(∅) = ℂI`, so c) holds even for finite Γ. The claim is about a variant with `∅` removed, not about the corpus's lattice index set | a | 2026-08-15 | +| (X6) | *claim*: the adopted form excludes chains | refuted as applied | the derivation uses **irreflexivity**, which is independent of a), b), c) — witness (H1)'s bottom-element model. The form is not credited with it | — | 2026-08-15 | +| (H1) | *claim about the adopted form*: axiom c) delivers "every region has somewhere spacelike to it" | refuted | adjoin a least element `0` to any poset and set `⊥ = {(0,O),(O,0)}`; a), b), c) hold, so **every poset underlies a causal index set**. Concretely, with `𝒜(0) = ℂ𝟙` the dual net is `B(ℋ)` everywhere and Haag duality forces `𝒜(O) = B(ℋ)` | — | 2026-08-15 | +| (H2) | *scope*: the adopted form expresses [BFV01]'s theory | refuted | BFV01's primary object is a category whose causality condition quantifies over **pairs of morphisms into a common spacetime**; `𝒦(M,ḡ)` is a derived poset obtained by fixing one object. The form covers the derived net, not the theory | a | 2026-08-15 | +| (X-R25) | *claim* [HM06] `fact`: strictly spacelike separated ⇒ strongly spacelike separated, asserted with no proof and no citation | promoted to proved | proof written out at (R25); **not trivial** — it needs 𝒦 closed under small enlargements, which [GLRV99] records that double cones in a curved spacetime lack | a | 2026-08-15 | +| (X-R9) | *claim* [GLRV99]: passing to ⊥̃ or ⊥̂ is idempotent, and all three coincide when 𝒦 is directed, asserted with no proof | promoted to proved | proofs written out at (R9), locating which axiom does which work | a | 2026-08-15 | +| (X-frees) | *claim*: [HM06] Prop. `frees` is proved for a different hypothesis than it states | refuted | the proof's second sentence is the definition of *strongly* unpacked; `strictly` in its first line is a typo and the proposition as stated is proved | a | 2026-08-15 | +| (X-Cor2.7) | *claim*: [BGL93] Cor. 2.7 establishes type III₁ for local algebras | survives at (c), `unverified` | discharged by `\proof Immediate, see [\ref(Long1)].` and conditional on Remark 2.6's spectral hypothesis; the cited work is not retrieved. **The locator is into BGL93, which was retrieved at tier (a), so it is a permitted locator; the `c` in the tier column is the verification status of the *result*, whose proof lies in an unretrieved work** | c | 2026-08-15 | +| (X-1.3v) | *claim*: [BGL93] Prop. 1.3(v) (that `𝒦̃` is not directed) is immediate | promoted to proved | the verification is immediate **given `𝒪″ = 𝒪`**, which BGL93 never states | a | 2026-08-15 | + +## Prior art + +| System | Found | Relation to variants | How searched | Measured at | +|---|---|---|---|---| +| this repository | `CausalOrthogonality` (`QuantumSystem/Algebra/LocalNet/Net.lean`) — a class over a `Preorder` with fields `Orthogonal`, `orthogonal_symm`, `orthogonal_mono_left` | **still weaker than (D1) alone**: a) and b) present, **c) absent from this class specifically** — c) has since been split off into the separate mixin `CausalIndexSet` (see below), so `CausalOrthogonality` by itself remains a strict sub-axiomatisation, exactly as before this revision. The docstring now names the split explicitly and gives three ways the corpus secures c) (membership condition, admitting `∅`, or not at all — citing (D2)/(D14), (D11), (D16)). Irreflexivity still absent, deliberately; no causal-complement operation, no causal completeness, no directedness in the class | `Grep` for `Causal\|complement\|Haag\|duality\|DHR\|superselection` over `QuantumSystem/`; full read of `Net.lean`; `lean_local_search "CausalIndexSet"`; `lean_hover_info` on both classes | working tree, 2026-08-15 | +| this repository | `CausalIndexSet` (`QuantumSystem/Algebra/LocalNet/Net.lean`) — a new `Prop`-valued mixin class over `[Preorder K] [CausalOrthogonality K]` with the single field `exists_orthogonal : ∀ O₁, ∃ O₂, O₁ ⟂ O₂` | **the combination `CausalOrthogonality K` + `CausalIndexSet K` realizes (D1) exactly** — a), b), c) together, with no further hypotheses: no irreflexivity, no directedness, no causal-complement operation into `K`, no causal completeness. The docstring states this identification in so many words (`An ordered K with [CausalOrthogonality K] and this mixin is exactly the adopted general form of the extraction note`). Previously (X18) and (X19) were rejections of *additional* axioms this class still correctly does not carry — a causal-complement operation into `K` and causal completeness respectively — and that remains true: `CausalIndexSet` adds only c), nothing from (X18)/(X19)'s rejected strengthenings | `lean_hover_info` and `lean_declaration_file` on `CausalIndexSet`; `lean_references` (no consumers found); full read of `Net.lean` | working tree, 2026-08-15 | +| this repository | `instance : CausalOrthogonality (Finset α)` with `Orthogonal := Disjoint`, and `instance : CausalIndexSet (Finset α)` proved by `⟨fun Λ => ⟨∅, Finset.disjoint_empty_right Λ⟩⟩` | **same as (D11)**, and the `CausalIndexSet (Finset α)` instance is the Lean realization of exactly the route (X7)/(D11) already document for the concrete lattice case: `∅` is disjoint from every finite set, so `∅` is the witness for `exists_orthogonal`, matching NAA13's `𝒫_f(Γ) ∋ ∅` device that (X7) identifies as how axiom c) is secured for the lattice index set (the docstring of the instance states this explicitly: "the empty region is disjoint from every region, so causal complements exist for free"). The other (D-concrete) branches — double cones, regular diamonds, `S¹` intervals — have no instance anywhere | greps for `Minkowski`, `Lorentz`, `double cone`, `diamond`, `spacetime`, `wedge` return only docstring prose; full read of the `CausalIndexSet (Finset α)` instance and its docstring | working tree, 2026-08-15 | +| this repository | `ProperContainment` (`QuantumSystem/Algebra/LocalNet/SplitProperty.lean`) with the collar field `∃ O₃, O₃ ≤ O₂ ∧ O₁ ⟂ O₃ ∧ ¬ O₃ ≤ O₁` | **the collar branch of the separation family** — closest to (D5′) among the literature forms, though (D5′) quantifies over all regions rather than relativising to a given outer region. Weaker than (D8)/(D9)/(D15): no closure, no distance. The repository proves the exact strength of its own clause (`exists_orthogonal_iff_not_subset`), namely that on `Finset α` it is equivalent to strict inclusion — which is (X15) direction 1 rediscovered | same | working tree, 2026-08-15 | +| this repository | `ProperContainment.ofThicken` and the `Finset ℤ` 1-neighbourhood instance | **stronger than the class** — the literature's separation is recovered by a buffer layer, at model level | same | working tree, 2026-08-15 | +| this repository | `LocalNet`, `VonNeumannNet`, `LocalNet.Covariance` | consuming structures; `Covariance` is an automorphism group of a fixed index set, **unrelated to (D-categorical)** — no functor from a category of spacetimes exists here | same | working tree, 2026-08-15 | +| this repository | could not find: a causal-complement operation, causal completeness, Haag duality, additivity, spacelike cones, or any DHR material at index-set level | — | same | working tree, 2026-08-15 | +| Mathlib | order-theoretic substrate only: `Disjoint`, `SetRel`, `SimpleGraph`, `Metric.AreSeparated`, `Metric.thickening`, `closure`/`interior` | **substrate**; nothing expresses a causal-disjointness relation on a poset | `lean_local_search`, `Grep` over `.lake/packages/mathlib`, `lean_leansearch`, `lean_loogle`, `lean_leanfinder` | mathlib rev `5450b53e5ddc75d46418fabb605edbf36bd0beb6` | +| Mathlib | could not find: an abstract orthogonality relation on an order with the heredity axiom, causal structure, Lorentzian geometry, or anything AQFT-shaped | — | same queries | mathlib rev `5450b53e5ddc75d46418fabb605edbf36bd0beb6` | +| Lean, outside Mathlib | `physlib`: `Lorentz.Vector.causallyUnrelated`, `causalDiamond`, `CausalCharacter` | **substrate at event level** for (D-concrete); no regions, no index set, no AQFT net | web and repository search | 2026-08-15 | +| Lean, outside Mathlib | an orthomodular-lattice development was reported but not retrieved | (D-complement)-shaped, tier (d) | web search | 2026-08-15 | +| Isabelle AFP | Schutz's Minkowski axioms; GNS; no-faster-than-light entries | **event-level substrate**; the index set is absent | AFP topic index and entry pages | 2026-08-15 | +| Coq/Rocq | could not find any causal index set or AQFT net, having searched the mathcomp and CoqQ indices and general web queries | — | web searches | 2026-08-15 | +| any system | could not find a formalization of Haag–Kastler nets over a causal index set, nor of causal-set structure carrying a *disjointness* rather than a causal *order* | — | web searches, Lean Zulip site-scoped queries | 2026-08-15 | + +## Open questions + +- (R19) versus (R1): does the failure of directedness deny the quasi-local algebra, or can it be circumvented? The reconciliation lives in an unfetched Fredenhagen article. **This is the corpus's most consequential unresolved disagreement.** +- (A5)/(R15): whether a substitute for a net tending spacelike to infinity exists over a compact Cauchy surface — [GLRV99]'s own stated open problem. +- (A22): whether the wedges of a spherically symmetric spacetime separate spacelike points; neither a proof nor a failing spacetime could be produced. +- Whether (D3)'s neighbourhood-buffered ⊥ and (D17)'s closure-based ⊥ are equivalent; no source in the corpus compares them, and (R4)'s proof consumes the buffer. +- Whether the ordering theorem's hypothesis (T) is the weakest such condition, and whether it has a purely order-theoretic surrogate — the adopted form cannot state (T). +- (R63): which field theories [DL84] §§9–10 exhibits as non-split; those pages were not converted. +- (R22): a funnel-property counterexample at a checkable tier; the corpus's only pointer is unfetchable, and (R39)'s alternative rests on a private communication. + +## Sources + +**Append-only.** + +| Key | Work | Status | Cache | Version | Tier reached | Retrieved | +|---|---|---|---|---|---|---| +| HM06 | H. Halvorson, M. Müger, *Algebraic Quantum Field Theory*, in *Handbook of the Philosophy of Physics*, arXiv math-ph/0602036 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-math-ph-0602036/` | arXiv | a | 2026-08-15 | +| GLRV99 | D. Guido, R. Longo, J. E. Roberts, R. Verch, *Charged sectors, spin and statistics in quantum field theory on curved spacetimes*, arXiv math-ph/9906019 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-math-ph-9906019/` | arXiv | a | 2026-08-15 | +| NAA13 | P. Naaijkens, *Quantum spin systems on infinite lattices*, arXiv 1311.2717 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-1311.2717/` | arXiv | a | 2026-08-15 | +| BGL93 | R. Brunetti, D. Guido, R. Longo, *Modular structure and duality in conformal quantum field theory*, arXiv funct-an/9302008 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-funct-an-9302008/` | arXiv | a | 2026-08-15 | +| BFV01 | R. Brunetti, K. Fredenhagen, R. Verch, *The generally covariant locality principle*, arXiv math-ph/0112041 | retrieved (arXiv LaTeX, verbatim) — **the cache holds two complete document bodies; all locators here are from the first** | `references/arxiv-math-ph-0112041/` | arXiv | a | 2026-08-15 | +| KOE03 | S. Köster, *Structure of Coset Models*, dissertation, arXiv math-ph/0308031 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-math-ph-0308031/` | arXiv | a | 2026-08-14 | +| dB74 | D. Buchholz, *Product states for local algebras*, Comm. Math. Phys. 36 (1974) 287–304 | retrieved **partial** — pp. 1–8 of 18 via MinerU; p. 292 additionally cross-checked against the PDF's own text layer with `pypdf`, independently of MinerU | `references/buchholz-1974-product-states/` | published | b | 2026-08-14 | +| DL84 | S. Doplicher, R. Longo, *Standard and split inclusions of von Neumann algebras*, Invent. Math. 75 (1984) 493–536 | retrieved **partial** — pp. 1–14 of 44 (§0–§4) via MinerU | `references/doplicher-longo-1984-standard-split/` | published | b | 2026-08-14 | +| HAAG | R. Haag, *Local Quantum Physics* | not retrieved — not attempted this run | — | — | d | 2026-08-15 | +| ROB76 | J. E. Roberts, *Local cohomology and superselection structure*, Comm. Math. Phys. 51 (1976) | not retrieved — not attempted this run | — | — | d | 2026-08-15 | +| BW-NETS | H. Baumgärtel, M. Wollenberg, *Causal Nets of Operator Algebras* — [GLRV99]'s cited treatment of nets over posets with a causal-disjointness relation | not retrieved — not attempted this run | — | — | d | 2026-08-15 | +| BF82 | D. Buchholz, K. Fredenhagen, *Locality and the structure of particle states*, Comm. Math. Phys. 84 (1982) — the source of the spacelike-cone index set | not retrieved — not attempted this run | — | — | d | 2026-08-15 | +| HOR | S. S. Horuzhy, *Introduction to Algebraic Quantum Field Theory* — [HM06]'s pointer to funnel-property counterexamples | not retrieved — not attempted this run | — | — | c | 2026-08-15 | +| FRED93 | K. Fredenhagen, *Global observables in local quantum physics* — the reconciliation of (R1) with (R19) | not retrieved — not attempted this run | — | — | d | 2026-08-15 | +| DHR | S. Doplicher, R. Haag, J. E. Roberts, *Local observables and particle statistics* I, II | not retrieved — not attempted this run | — | — | d | 2026-08-15 | + +Further works cited by the corpus and not retrieved (Schlieder, Brown, Verch, Keyl, Borchers, Hislop–Longo, Dimock, Longo, Buchholz–Schulz-Mirbach, Buchholz–Wichmann, Buchholz–D'Antoni, Yngvason, Guido–Longo–Wiesbrock, Fredenhagen–Gabbiani, Fredenhagen–Jörß, Summers, Araki, Sakai, Kay–Wald): every claim through them carries a substitution sentence and no locator. One of them — [BGL93]'s attribution of (R39) to Buchholz — is a *private communication*, so no locator can ever exist for it. + +## Not investigated + +- **The `[ext]` gap.** Lane 5 swept only the formalization landscape; **no lane checked any external mathematical result**. The refutation pass fetched none. Every one of the external edges above — Fredenhagen's global-observables construction (which decides the (R1)/(R19) disagreement), Horuzhy's funnel counterexamples, Schlieder, Brown, Verch, Keyl, Hislop–Longo, Longo, Buchholz–Wichmann, Summers, and the DHR papers — remains unexamined, so (R19), (R22), (R24), (R29), (R34), (R35), (R46), (R49) and the external legs of (R3) rest entirely on attestations. +- **Unconverted pages.** dB74 pp. 9–18, including the proof underlying (R60); DL84 pp. 15–44, including the §§9–10 non-split field theories of (R63). +- **No page-image comparison was possible** — `pdftoppm`, `pdftotext`, `mutool` and `gs` are all absent from this container — so **no MinerU quote reaches tier (a)**. dB74's p. 292 was cross-checked against the PDF's own text layer, which removes the MinerU-inference risk for that passage only; DL84 was not cross-checked at all. +- **Spacelike cones** are named as an index set by [GLRV99] and [NAA13] and **defined by neither**; [HM06] defers to an unfetchable source. No (D#) row exists for them and none can be written from this corpus, so whether the cone index set is an instance of the adopted form is **unverified**, not covered. +- **[GLRV99] Ch. 5's labelled geometric assumptions** (a), (b), (c), (c′) were read only as far as (A19) and (A22) required — the single largest gap in the hypothesis lane. [KOE03]'s coset and subnet machinery and [NAA13]'s lattice chapters were swept only for index-set statements. +- **Degeneracy probes skipped**: whether (T) is preserved under passing to `𝒦̃`-style conformal orbits in general; whether ⊥̃ and ⊥̂ can be separated on a *corpus* index set (they coincide on `S¹` and fail together on the sieve poset — the only separating object found was constructed for the purpose); closure-separation versus positive distance for unbounded regions. +- **Errata found but not chased**: [GLRV99]'s Extension-Theorem proof cites Lemma 3.A.4 where 3A.5 is needed, and prints three spellings of one label; its Lemma 3.6 says `dimension $\geq 2$` and then treats dimension two as the remaining case; [BGL93] Thm 3.3's proof cites a Lemma 3.4 that does not exist; [BFV01]'s `cf.\ condition $(ii)$` points at orientation-preservation where causal convexity is condition (i), **in both document bodies, so authorial rather than a conversion artefact**. +- **Not opened**: HS17 (`references/arxiv-1702.04924/`), cached from a previous run and outside this corpus. diff --git a/docs/math/split-inclusion.md b/docs/math/split-inclusion.md new file mode 100644 index 0000000..9c1da76 --- /dev/null +++ b/docs/math/split-inclusion.md @@ -0,0 +1,589 @@ +--- +object: Split inclusion of von Neumann algebras +slug: split-inclusion +status: draft +worst-tier: c +mathlib-rev: 5450b53e5ddc75d46418fabb605edbf36bd0beb6 +implemented-as: VonNeumannAlgebra.IsSplitInclusion +revisions: + - 2026-08-14 · 4d8a21b · initial extraction · sources: KOE03, HS17, dB74, DL84 + - 2026-08-15 · 4ec09ec · format migration: variant grid, nonvacuity row, adopted-form display · no new claims + - 2026-08-15 · 4ec09ec (working tree) · prior-art locator refresh after rename/refactor (`exists_tensor_decomposition`, `VonNeumannNet`) · no new claims + - 2026-08-15 · <working tree, uncommitted> · prior-art refresh after the diagonal-algebra non-split witness · no new claims +--- + +<!-- +Macros used by the verbatim quotes below, transcribed from each source's own +preamble so that the quotes render as their authors wrote them: + \lok KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144 + \A HS17, references/arxiv-1702.04924/raw/main.tex:151 + \H HS17, main.tex:196 — \renewcommand, not \newcommand: \H is the + Hungarian-umlaut accent in KaTeX's own macro table, which is why the + source redefines it too + \bC HS17, main.tex:97 +The definitions are scoped to this file: the renderer resets its macro table +per document, so a later note may transcribe the same names differently. +--> + +$$ +\newcommand{\lok}[1]{{\mathcal #1}} +\newcommand{\A}{\mathfrak{A}} +\renewcommand{\H}{\mathcal{H}} +\def\bC{{\mathbb C}} +$$ + +# Split inclusion of von Neumann algebras + +## What this object is for + +A split inclusion upgrades mere commutation of two von Neumann algebras to +*statistical independence*: an intermediate type I factor lets states be +prescribed independently on the two sides, as if the pair acted on a tensor +product. In local quantum physics the split property of a net (split inclusions +for all suitably separated region pairs) is the standing regularity hypothesis +behind the type III₁ structure of local algebras, the quantum Noether theorem, +and the finiteness/positivity theory of entanglement measures. The general +two-algebra form matters because the literature proves its structure theory +(canonical interpolating factor, product states, tensor decompositions) at that +level and only then specialises to nets. + +## Definition + +### Variants as the sources write them + +| (D#) | Source | Level | Interpolating 𝔑 squeezed against | Extra data | Tier | +|---|---|---|---|---|---| +| (D1) | [KOE03] | net (chiral) | larger local algebra 𝔅(I₂) | — | a | +| (D2) | [HS17] | pair | — (abstract isomorphism 𝔄_A ∨ 𝔄_B ≅ 𝔄_A ⊗ 𝔄_B, no interpolating factor) | — | a | +| (D3) | [HS17] | pair | commutant 𝔄_B′ | vector \|Ψ⟩ cyclic for each, separating for the join | a | +| (D4) | [dB74] | net (QFT regions) | commutant ℛ(O₂)′ | normal product state | b | +| (D5) | [HS17] | pair | undefined ("intermediate" never pinned) | — | a | +| (D6) | [DL84] | pair | arbitrary second algebra B | — | b | +| (D7) | [DL84] | pair | — (split after tensoring with an auxiliary type I factor M) | auxiliary type I factor M | b | + +**(D1) [KOE03] §2.2 ("Split property for chiral subnets"), eq. `eq:splitprop`, source.txt 1697–1707** — tier (a) — net-level, nested form + +> a chiral net $\lok{B}$ has the split property, if for any pair $I_{1,2}$ of proper intervals satisfying $\overline{I_1}\subset I_2$ there is a type $I$ factor $\lok{M}$ interpolating between $\lok{B}(I_1)$ and $\lok{B}(I_2)$ + +with the display Λ: 𝔅(I₁) ⊂ 𝔐 ⊂ 𝔅(I₂), Ī₁ ⊂ I₂ ⋐ S¹. A net-level property, +quantified over all pairs of proper intervals with closure containment, +demanding a type I **factor** squeezed against the **local algebra of the +larger region**. KOE03 presents it as "the usual definition (adapted to our +context; cf FG93 definition 2.11)" — the wording is KOE03's adaptation, and the +FG93 locator is KOE03's citation (tier (c) toward FG93, not retrieved). KOE03 +also asserts, without listing them: "There are equivalent formulations of this +property." + +**(D2) [HS17] §2, displayed definition, source.txt 985–993** — tier (a) — statistical independence + +> The algebras $\A_A$ and $\A_B$ are said to be statistically independent iff there is an isomorphism of the v. Neumann algebras $\A_A\vee\A_B \simeq \A_A\otimes\A_B$. + +For two commuting von Neumann algebras on a common ℋ, with ∨ and ⊗ defined at +the definition site and the notion pinned as "$W^*$-independence in the product +sense" (citation florig, not retrieved). + +`differs from (D1) by:` single-pair, no net, abstract isomorphism instead of an interpolating factor. +`sources claim equivalence:` no — HS17 says only that statistical independence "is closely related" to the split property. (X4) shows it strictly weaker in general; DL84 identifies it with **quasi-split** (D7), equivalent to split under a semi-standard state. + +**(D3) [HS17] §2, "Split property" paragraph, source.txt 995–1005** — tier (a) — the split, commutant form + +Given statistical independence and a vector |Ψ⟩ cyclic for 𝔄_A and 𝔄_B and +separating for 𝔄_A ∨ 𝔄_B (written inside the definitional paragraph as "there +is typically a vector…"), there is a unitary W: ℋ → ℋ⊗ℋ with WaW\* = π_A(a)⊗1, +WbW\* = 1⊗π_B(b); setting 𝔑 = W\*(𝔅(ℋ_A)⊗1)W gives 𝔄_A ⊂ 𝔑 ⊂ 𝔄_B′, + +> which is also called the ``split''. The split and the unitary $W$ are unique (for given $|\Psi \rangle \in\H$) if we require that + +W\*(|Ψ⟩⊗|Ψ⟩) lies in the natural cone of |Ψ⟩ for 𝔄_A ⊗ 𝔄_B. 𝔑 depends on the +chosen |Ψ⟩. + +`differs from (D1) by:` the type I factor is squeezed against the **commutant** 𝔄_B′, not the larger local algebra; no regions. In the chiral dictionary the two agree iff Haag duality 𝔅(I₂) = 𝔅(I₂′)′ holds — neither source invokes duality at its definition site. +`sources claim equivalence:` HS17 presents (D2) + |Ψ⟩ ⇒ (D3) as an entailment ("entails"), no proof, citing DL84 and BW86. The machinery is proved in [DL84] Thm 2.1 (tier (b), mineru-unchecked; see (R7)). + +**(D4) product-state formulation [dB74], attested through [KOE03] and now read in [dB74] pp. 1–8** — tier (b), mineru-unchecked + +[dB74] Cor. 2.4: in its QFT standing structure (local rings with Reeh–Schlieder +vacuum, "almost factor" property, regions with slack), a normal product state +for the pair yields interpolating type I factors realizing Borchers' display +ℛ(O₁) ⊂ 𝔐₁ ⊂ 𝔐₂′ ⊂ ℛ(O₂)′. The converse is asserted: + +> It is obvious, but still worth mentioning, that the existence of factors $M_{1}$ and $M_{2}$ with the properties specified above implies the existence of normal product states. + +**Caution (refutation finding):** "split ⇔ faithful normal product state" is +**false for abstract commuting pairs** — the (X4) witness carries a faithful +normal product state yet is not split. The abstract relation is [DL84] §1: +normal product state / product isomorphism ⇔ **quasi-split** (D7), and + +> Under very general circumstances, for example if there exists a semi-standard state, the split and quasi-split properties are equivalent + +dB74's equivalence is honest because its QFT standing structure supplies the +standardness; KOE03's use of the criterion in (R1) is inside that structure and +is sound. + +`sources claim equivalence:` KOE03 attests both directions of (D1) ⇔ (D4) to dB74 (proof of `prop:subsplit`, source.txt 1765–1769, and source.txt 9753–9758) — for local algebras in the QFT setting, now grounded at (b) by the dB74 fetch, with the standardness proviso above. + +**(D5) [HS17] "intermediate type I subfactors", source.txt 2293–2300** — tier (a) usage row; notion undefined in the corpus + +Thm `Thm:dominance` quantifies over "intermediate type I subfactors" +𝔑_A ⊂ 𝔄_A, 𝔑_B ⊂ 𝔄_B; "intermediate" (between which algebras) and "exhausting +𝔄" in the following remark are never defined in HS17. Recorded as a gap, not +filled. Partially grounded by [DL84]'s dyadic interpolation chain (see (R9)). + +**(D6) [DL84] Definition 1.4 (p. 497 of Invent. Math. 75)** — tier (b), mineru-unchecked — the bare two-algebra form + +> 1.4. Definition. A $W^*$ -inclusion $(A, B)$ is split if there exists a type I factor $N$ such that $A \subset N \subset B$ . + +where a W*-inclusion is a pair A ⊆ B of von Neumann algebras, + +> (of course $A$ and $B$ have the same identity) + +No vector, no separability, no factoriality of the endpoints. Standardness +(a vector cyclic and separating for A, B and A′∧B — Def. 1.1) is a separate +refinement layer; for a non-trivial **standard** split inclusion, separability +of the GNS space and proper infiniteness of A, B, A′∧B are *theorems* +([DL84] Prop. 1.6, tier (b), mineru-unchecked). + +`differs from (D1)/(D3) by:` no net, no commutant: the second algebra is arbitrary. Both (D1) and (D3) are instances (take B := 𝔅(I₂), resp. B := 𝔄_B′). + +**(D7) [DL84] §1, quasi-split** — tier (b), mineru-unchecked + +> We shall also say that $(A,B)$ is quasi-split if there exists a type I factor $M$ such that $(A\otimes \mathbb{1},B\otimes M)$ is split. + +DL84 (citing its ref. [12]) states: (A,B) is quasi-split iff there is an +isomorphism A∨B′ → A⊗B′ with ab′ ↦ a⊗b′ — i.e. exactly the (D2) shape for the +pair (A, B′). Split ⇒ quasi-split; equivalence under a semi-standard state +(quote under (D4)). The (X4) witness is quasi-split but not split. + +### Adopted general form + +Fix a complex Hilbert space ℋ, of arbitrary dimension. All von Neumann algebras +act on ℋ and contain 1_ℋ; that the interpolating factor shares the unit is +*derived* from Λ(1) ⊆ 𝔑, not assumed (degeneracy table, "non-unital" row). +A **W*-inclusion** is a pair (Λ(1), Λ(2)) of von Neumann algebras on ℋ with +Λ(1) ⊆ Λ(2). The inclusion is **split** iff there exists a type I factor 𝔑 on +ℋ with Λ(1) ⊆ 𝔑 ⊆ Λ(2). There are no further hypotheses: no factoriality or +type restriction on the endpoints, no separability of ℋ, no distinguished +vector, and no non-triviality clause (the inclusion is trivially split whenever +either endpoint is a type I factor). + +$$ +\Lambda(1) \;\subseteq\; \mathfrak{N} \;\subseteq\; \Lambda(2), +\qquad \mathfrak{N} \text{ a type I factor on } \mathcal{H}. +$$ + +At net level: a local net O ↦ 𝓡(O) has the **split property** iff for every +suitably separated pair of regions — Ī₁ ⊂ I₂ in the chiral/interval case, +a positive-distance corridor in the Minkowski case — the inclusion +𝓡(O₁) ⊆ 𝓡(O₂) is split (the *nested* form). The *commutant* form — for each +admissible disjoint pair, 𝓡(O_A) ⊆ 𝔑 ⊆ 𝓡(O_B)′ is split — is the historical +original (Borchers' conjecture as displayed in [dB74]); the nested form implies +it via locality (𝓡(O₂) ⊆ 𝓡(O₂′)′), and the converse holds under Haag duality, +which no fetched source assumes at its definition site. This note adopts the +nested form at net level and treats the commutant form as a conditionally +equivalent variant, so that every net-level row below says which of the two its +source states. + +Justification: the single-inclusion core is (D6) — up to notation verbatim +[DL84] Definition 1.4 — and subsumes (D1) and (D3) as instances. (X1) and (X2) +discriminate both clauses of "type I factor": an interpolating factor of +arbitrary type is strictly weaker ((X1), hyperfinite III₁ identity inclusion), +and an interpolating type I *algebra* is strictly weaker ((X2), ℂ⊕ℂ ⊆ ℂ⊕ℂ). +(X4) shows the statistical-independence/quasi-split candidate (D2)/(D7) +strictly weaker in general (a 5-dimensional separating object), with +equivalence restored exactly under a semi-standard state ([DL84] §1). The +net-level choice resolves the refutation's hole H1 by picking one quantified +property and recording the conditional equivalence instead of an ambiguous +disjunction. + +## Notation and conventions + +| (C#) | Axis | This note | Per source | Translation | +|---|---|---|---|---| +| (C1) | standing setting, chiral | — | [KOE03] def:chcotheo, source.txt 953–982: chiral net on **explicitly separable** ℋ; proper interval I ⋐ S¹ open, connected, non-dense; I′ := S¹∖Ī. tier (a) | — | +| (C2) | separation of the region pair | nested closure containment | [KOE03] Ī₁ ⊂ I₂ (inside the definition); [HS17] dist(A,B) > 0 ("finite safety-corridor"). tier (a) both | on S¹ they agree (Ī₁ ⊂ I₂ ⇔ disjoint closures with two open arcs between); on a non-compact Cauchy surface dist > 0 is strictly stronger than disjoint closures; the corpus never confronts the two | +| (C3) | HS17 standing conventions | — | "Hilbert spaces are always assumed (or manifestly) separable."; inner products anti-linear in the **first** entry; ∨, ⊗ defined at the (D2) site. tier (a) | — | +| (C4) | which "statistical independence" | W*-independence in the product sense | [HS17] pins by citation (florig); [KOE03] footnote flags the family of inequivalent notions (sS90). Both citations unfetched | none available in corpus | +| (C5) | factor vs type I subalgebra | factor (definitional) | definitions in all sources demand type I **factors**; [HS17]'s proofs use type I subalgebras merely "chosen to be" factors (source.txt 4360). tier (a) | (X2): the algebra form is strictly weaker | +| (C6) | net-level property vs single inclusion | both; single inclusion is primary | [KOE03] net-level (D1); [HS17] per-pair object (D3); [DL84] abstract pair (D6). tier (a)/(b) | net-level = ∀ admissible pairs, single-inclusion form | +| (C7) | meaning of ≅ in (D2) | abstract *-isomorphism | [HS17] displayed definition: isomorphism of von Neumann algebras; its intro glosses ≅ as "up to unitary equivalence" (spatial). Internal wobble, unremarked in the source. tier (a) | under the spatial reading the candidate becomes the (X7) tensor form, which *is* equivalent to split | + +## Results and dependencies + +### (R1) Heredity: chiral subnets inherit the split property and nuclearity + +Let 𝔄 ⊂ 𝔅 be a chiral subnet. If 𝔅 has the split property (is nuclear), then 𝔄 +has the split property (is nuclear). + +- Source: [KOE03] `prop:subsplit`, source.txt 1748–1782 · tier (a) · **proved in source** +- Verbatim: + > Let $\lok{A}\subset\lok{B}$ be a chiral subnet. If $\lok{B}$ has the split property (is nuclear), then $\lok{A}$ has the split property (is nuclear). +- Proof route: restrict 𝔄 to its vacuum subrepresentation; by the dB74 + criterion it suffices to produce a faithful normal product state on + 𝔄(I₁)e_𝔄 ∨ 𝔄(I₂′)e_𝔄; modular covariance (A15) makes A ↦ Ae_𝔄 an + isomorphism on 𝔄(I₃), I₃ ⊇ I₁ ∪ I₂′; pull back a product state from 𝔅. +- Depends on: (D4)/[dB74] criterion (tier (b), mineru-unchecked, with the + standardness proviso under (D4)); (A15) modular covariance; hypothesis (A13). +- Note: KOE03 demands a *faithful* normal product state where dB74 Cor. 2.4 + needs only a normal one (faithfulness is manufactured in dB74 Thm 2.2) — + a harmlessly stronger input. + +### (R2) Nuclearity ⇒ split + +BW-nuclearity (a5): Θ_{β,r}: a ↦ e^{−βH}π₀(a)|0⟩ nuclear with +‖Θ_{β,r}‖₁ ≤ e^{(c/β)ⁿ}) implies the split property for pairs with +dist(A,B) > 0; chiral version with L₀ in place of H. + +- Source: [HS17] source.txt 1199 (cites BDF87); [KOE03] source.txt 1709–1716 + and 9174–9278 (nuclearity formulated by BW86; chiral implication via FG93, + its lemma 2.12 — locator is KOE03's citation) · tier (a) attestations, result + **(c)** · cited elsewhere +- Conventions: one result under two conventions (H-form and L₀-form). +- Attribution note (refutation-verified): KOE03 attaches no citation to the + implication itself — BW86 is credited with the nuclearity condition and the + free-field case, FG93 with the chiral implication; HS17 credits BDF87. Not a + contradiction; the unfetched originals would adjudicate. +- Depends on: [ext: Buchholz–Wichmann (BW86) — formulates energy nuclearity and + establishes it for the free scalar field, deriving causal/statistical + independence of sufficiently separated local algebras. tier (c), no locator, + not retrieved]; [ext: Buchholz–D'Antoni–Fredenhagen (BDF87) — HS17's citation + target for nuclearity ⇒ split. tier (c), no locator, not retrieved]; + [ext: Gabbiani–Fröhlich (FG93) — translates the implication to chiral nets on + S¹. tier (c), not retrieved]. + +### (R3) Modular nuclearity a5′) ⇒ statistical independence; a5′) ⇒ a5) + +- Source: [HS17] source.txt 2337–2349 · tier (a) attestation, results (c) · + asserted / cited elsewhere +- Depends on: [ext: Buchholz–D'Antoni–Longo, *Nuclear maps and modular + structures I* — modular nuclearity implies energy nuclearity in Minkowski + space without the quantitative bounds. tier (c), no locator, not retrieved]; + edge to (R2). + +### (R4) Split ⇒ local algebras ≅ centre ⊗ hyperfinite type III₁ factor + +- Source: attested in [KOE03] source.txt 1718–1731 · tier (c) · cited elsewhere +- Depends on: [ext: BDF87 — under the split property (plus its standing + assumptions, for nets in 3+1-dimensional Minkowski space) local von Neumann + algebras factorise as centre ⊗ hyperfinite type III₁ factor. tier (c), no + locator, not retrieved]; [ext: Haagerup — uniqueness of the injective type + III₁ factor. tier (c), not retrieved]; [ext: FG93 — chiral translation. + tier (c), not retrieved]. +- Flag (refutation): KOE03 and HS17 attribute *different hypothesis-sets* to + BDF87 (split alone, here, vs nuclearity + scale invariance in (R5)); read + this row as KOE03's compression, not as a theorem shape. + +### (R5) Nuclearity + asymptotic scale invariance ⇒ direct sums of type III₁ factors + +- Source: attested in [HS17] source.txt 1201 · tier (c) · cited elsewhere + ([ext: BDF87, as in (R4)]) +- Depends on: a5) (A8) and (A14). Kept distinct from (R4): different + hypotheses, different conclusion. + +### (R6) No purity / failure of statistical independence for touching regions (HS17 `thm_split`) + +(a) The restriction of a locally normal state to a local algebra is never pure. +(b) A pure normal state on a local algebra extends to no larger local algebra +normally. (c) For disjoint A, B with Ā ∩ B̄ ≠ ∅ there is no normal separable +state on 𝔄(O_A) ∨ 𝔄(O_B); in particular the pair is not statistically +independent (hence not split). + +- Source: [HS17] `thm_split`, source.txt 1202–1210 · tier (a) for (a), (c); + (b) inherits (c) · (a), (c) proved in source; (b) cited elsewhere +- Depends on: [ext: Fewster–Verch, *The necessity of the Hadamard condition* — + its corollary 3.3 (locator as HS17 cites it): a pure normal state on a local + algebra cannot be extended to a normal state on any larger local algebra. + tier (c), not retrieved]; setting of (R5); hypotheses (A10), (A14). +- Independent grounding (refutation fetch): [dB74] Ch. II conclusion asserts + the same failure for the free field — + > one runs into contradictions if one postulates the existence of normal product states for such regions + (tier (b), mineru-unchecked). + +### (R7) Canonical split: implementing unitary, canonical 𝔑, natural-cone uniqueness + +For a semi-standard split W*-inclusion, there is a standard-implementation +unitary U_Λ: ℋ_Λ → ℋ₁⊗ℋ₂ with U_Λ ab′U_Λ\* = a_e⊗b′_f and +U_Λ P^♮_Ω(A′∧B) = P^♮_{Ω⊗Ω}; the canonical interpolating type I factor is +N_Λ = U_Λ\*(𝔅(ℋ₁)⊗1)U_Λ, unique per standard vector by unicity of the standard +implementation. When the vector is cyclic for both algebras (HS17's hypotheses) +this is exactly (D3)'s W: ℋ → ℋ⊗ℋ. + +- Source: [DL84] Thm 2.1, Def. 2.2, Cor. 2.4 (pp. 1–14 of the conversion) · + tier (b), mineru-unchecked · proved in source (promoted from (c) by the + refutation fetch); [HS17] source.txt 995–1005 asserts it · tier (a) +- Precisions: DL84 normalises via the natural cone of the **relative + commutant** A′∧B (equivalent to HS17's phrasing under the identification by + W); Cor. 2.4 shows every interpolating type I factor with properly infinite + relative commutants is vN_Λv\* for a unitary v ∈ A′∧B — uniqueness is + strictly *per vector*. +- Depends on: (D6); standardness layer; [ext: DL84's ref. [12] for the + quasi-split equivalences. tier (c), not retrieved]. + +### (R8) Entanglement-measure dominance on intermediate type I subfactors + +E(ω) ≥ E_D(ω|_𝔑) for entanglement measures with (e2), (e4), (e5) and the +normalisation, 𝔑 = 𝔑_A ⊗ 𝔑_B an intermediate type I subfactor pair. + +- Source: [HS17] `Thm:dominance`, source.txt 2292–2307 · tier (a) statement · + cited elsewhere + sketched (finite-dimensional case in [ext: Donald– + Horodecki–Rudolph — entanglement measures with the stated properties dominate + distillable entanglement in finite-dimensional type I algebras. tier (c), not + retrieved]; approximation sketch in source) +- Depends on: (R9); (D5) gap; measure axioms (out of this object's scope). + +### (R9) Split ⇒ many intermediate type I subfactors "exhausting" the pair + +- Source: [HS17] remark after `Thm:dominance` · tier (a) for the assertion · + **asserted, no proof, no citation in HS17** +- Verbatim: + > The existence of many such intermediate type I subfactors exhausting $\A$ is guaranteed by the split property. +- Refutation status: half-grounded. [DL84]'s introduction states + > the interpolation by a chain of type I factors $N_{d}$ , $d$ a diadic rational + (Th. 8.3; that section not converted) — "many" in a precise sense, tier (b), + mineru-unchecked. "Exhausting 𝔄" remains undefined in every fetched text; + this row must not be cited as a theorem shape until it is pinned. + +### (R10) Split ⇒ the decoupled state is well-defined; lower bounds on E_I, E_R (HS17 `corI`) + +For dist(A,B) > 0 and ω faithful normal on 𝔄_A ∨ 𝔄_B, the decoupled state +ω′(ab) = ω(a)ω(b) is well-defined by the split property, and E_I, E_R admit the +lower bounds of HS17 corI. + +- Source: [HS17] `corI` and preceding paragraph, source.txt 4648–4676 · + tier (a) · proved in source +- Depends on: split property for the pair ((R2) route); statistical + independence (split ⇒ quasi-split, [DL84] §1, tier (b)); hypotheses (A7), + (A11). Consequence noted in source: E_R diverges as the corridor shrinks. + +### (R11) E_R(ω) > 0 across a corridor (HS17 `cor1`) + +- Source: [HS17] `cor1`, source.txt 4347–4386 · tier (a) · proved in source + (split-chosen type I "Cbit" subalgebras + near-maximal Bell violation + + Fell's theorem + Reeh–Schlieder) +- Depends on: (R10); split property; Reeh–Schlieder (A5, proved in HS17); + [ext: Fell's theorem — normal states of a representation approximate any + state weakly; HS17 points at Haag's book. tier (c)/(d), not retrieved]; + technique attributed to [ext: Narnhofer; Summers–Werner — maximal Bell + violation is generic in QFT. tier (c), not retrieved]. + +### (R12) Quantum Noether theorem: split ⇒ local implementers via universal localisation maps + +- Source: [KOE03] source.txt 9751–9773 (detailed summary), 1724–1726 · + tier (c) · cited elsewhere +- Depends on: (R1); [ext: Buchholz–Doplicher–Longo (BDL86) — under the split + property, spacetime symmetries admit local implementers built from universal + localisation maps: for Ī ⊂ J a norm-one *-homomorphism onto the algebra of J + acting trivially on the algebra of I carries global symmetry unitaries to + locally supported implementers. tier (c), no locator, not retrieved]; + (D4)/[dB74] supplies the product state; local normality of the embedding. + +### (R13) Localisation maps → identity as regions exhaust spacetime + +- Source: attested in [KOE03] source.txt 9812–9818 · tier (c) · cited elsewhere +- Depends on: (R12); [ext: D'Antoni–Doplicher–Fredenhagen–Longo (ADF87) — for + suitable enlarged regions the universal localisation maps converge pointwise + strongly to the identity, given irreducibility of the quasi-local algebra. + tier (c), no locator, not retrieved]; irreducibility hypothesis. + +### (R14) Trace-class estimate on e^{−βL₀} ⇒ nuclearity ⇒ split for the U(1)-current derivative models + +- Source: [KOE03] source.txt 9174–9278, estimate `eq:nuclcond` · tier (a) for + the estimate, proved in source; the final split step inherits (c) (FG93's + own lemma 2.12, locator as KOE03 cites it) +- Depends on: (R2); [ext: FG93 as in (R2)]; [ext: Schoeneberg III.§3 — Dedekind + η transformation law, locator as KOE03 cites it. tier (c), not retrieved]; + trace-class hypothesis (A8 witnesses). + +### (R15) The chiral nets LSU(n)_k are split, hence completely rational + +- Source: attested in [KOE03] source.txt 4175–4180 · tier (c) · cited elsewhere +- Depends on: [ext: FG93 — split property for chiral current algebra models. + tier (c), not retrieved]; [ext: Loke thesis — strong additivity. tier (c), + not retrieved]; [ext: Xu — μ-index computation. tier (c), not retrieved]; + [ext: Kawahigashi–Longo–Müger — complete rationality (split + strong + additivity + finite μ-index) implies finitely many sectors of finite + statistical dimension. tier (c), not retrieved]. Split is a defining + constituent of complete rationality (KOE03 source.txt 7913–7920). + +### (R16) Joint cyclic-separating vectors — corrected statement + +**As quoted by KOE03 (source.txt 6666–6669) the sentence is refuted** — see +(X9) in the rejected/refuted table. Corrected statement, now read in the +fetched DL84: under the hypotheses of [DL84] Prop. 1.2 (properly infinite +algebras *acting standardly* / with properly infinite commutants, separable +predual), each of A, B, A′∧B admits a dense G_δ set of cyclic separating +vectors, hence standard vectors for (A, B) form a dense set. + +- Source: [DL84] Prop. 1.2 · tier (b), mineru-unchecked · proved in source, + via [ext: Dixmier–Maréchal — the cyclic separating vectors of a von Neumann + algebra with separable predual and properly infinite commutant form a dense + G_δ. tier (c), not retrieved] +- KOE03's *application* (type III subfactor inclusions on the vacuum space) is + sound; only its freestanding sentence drops the hypotheses. + +### (R17) Finite-dimensional statistical independence — refuted as stated + +HS17 asserts (source.txt 991, tier (a)): + +> When $\A_A$ and $\A_B$ are finite dimensional and $\A_A\cap\A_B=\bC 1$, then the algebras are always statistically independent. + +**Refuted as literally stated** — see (X10) in the rejected/refuted table. It +holds for commuting finite-dimensional *factors* (then the join is naturally +the tensor product); the corpus's uses of the remark are unaffected because +they concern factors. + +### (R18) Diffeomorphism covariance ⇒ split for chiral nets + +- Source: attested in [HS17] footnote, source.txt 1493 · tier (c) · cited + elsewhere ([ext: Morinelli–Tanimoto–Weiner, *Conformal covariance and the + split property* — a chiral net containing the Virasoro subnet automatically + satisfies the split property. tier (c), no locator, not retrieved]) + +### (R19) Model inputs: free fields satisfy BW-nuclearity + +- Source: attested in [HS17] source.txt 2375, 1220 · tier (c) · cited elsewhere +- Depends on: [ext: BW86 — nuclearity for the free scalar field. tier (c), not + retrieved]; [ext: D'Antoni–Hollands — nuclearity and split for free Dirac + fields, also in curved spacetime. tier (c), not retrieved]. These supply the + nonvacuous instances of the split property in the corpus. + +## Hypotheses + +| (A#) | Statement | Class | Evidence | Witness | Scope | Tier | Used by | +|---|---|---|---|---|---|---|---| +| (A1) | ℋ separable | open | explicit in both sources (KOE03 source.txt 956; HS17 conventions); **no fetched result visibly uses it**; for *standard* split inclusions separability is a theorem ([DL84] Prop. 1.6) | — | standing | a/b | none exhibited | +| (A2) | chiral-net axiom bundle (isotony, locality, covariance, spectrum, unique cyclic vacuum) | — (definitional bundle) | KOE03 def:chcotheo; HS17 a1)–a4) | — | standing | a | (A5), (R1)–(R6) | +| (A3) | subnet conformal covariance | model-dependent | KOE03 source.txt 1006–1020, 1484–1496 | fails: light-ray inclusion of the U(1)-current derivatives in their dual net (KOE03 names it, GLW98 leg tier (c)); holds: coset/current subalgebras | standing | b/c | (A15), (R1) | +| (A4) | uniqueness of the vacuum | — (axiom) | KOE03 source.txt 1221–1223; HS17 a4) | — | standing | a/c | type III₁ factoriality | +| (A5) | vacuum cyclic and separating for local algebras (Reeh–Schlieder) | provable | HS17 proves in-source, source.txt 1141–1167; KOE03 attests RS61 et al. | — | standing (derived) | b | (A11), (A12), (R1), (R11) | +| (A6) | weak additivity | provable (chiral) / open (general nets) | KOE03 derives for chiral nets (LRT78/FJ96 legs (c)); HS17 assumes it as Araki's axiom | — | standing | a/c | (A5) | +| (A7) | corridor dist(A,B) > 0 | model-dependent | HS17 source.txt 451, 1199, 2345, 4649 | fails: free Klein–Gordon net with touching bases ((R6)(c); fewster_2 leg (c); split ⇒ statistical independence now (b) via dB74/DL84); holds: same net with corridor | local | a/c | (R2), (R10), (R11) | +| (A8) | BW-nuclearity a5) | open | sufficient for split (attested); no converse claimed; no net satisfying a1)–a4) but failing a5) named in any fetched source | satisfiers named: free KG, free spin-½, U(1)-current derivative and stress-energy models (KOE03 proves the chiral estimate in-source) | local | a/c | (R2), (R5), (R14), (R19) | +| (A9) | modular nuclearity a5′) | open | a5′) ⇒ a5) attested (tier (c)); satisfiers: integrable models with factorizing S-matrix | — | local | a/c | (R3) | +| (A10) | local normality of ω | model-dependent | HS17 source.txt 1201 | fails: pure state on 𝔄(O_A) Hahn–Banach-extended (argument written out in extraction; non-constructive step flagged); holds: vacuum and density-matrix states | local | a/b | (R6) | +| (A11) | ω faithful + normal on 𝔄_A ∨ 𝔄_B | provable for the vacuum (corridor + Reeh–Schlieder argument written out; faithfulness *consumes* the corridor); model-dependent for general normal states | HS17 source.txt 4649 | fails (general case): normal state with support projection p < 1; holds: vacuum | local | a/b | (R10), (R11) | +| (A12) | vector Ψ cyclic for 𝔄_A, 𝔄_B, separating for the join | provable for the vacuum (discharges HS17's "typically"); open beyond it | HS17 source.txt 995 | — | local | a/b | (R7), (D3) | +| (A13) | ambient net 𝔅 has the split property | open | satisfiers: LSU(n)_k, U(1)-current models; **no non-split net named in the fetched pages** — [DL84] announces non-split field theories in its §9–10, not converted | — | local | a | (R1), (R12), complete rationality | +| (A14) | asymptotic scale invariance at small scales | open | undefined in fetched text; grounding lives in BDF87 (unfetched) | — | local | a/c | (R5), (R6) | +| (A15) | modular covariance of subnet inclusions | provable | derived from (A3) + geometric modular action; KOE03 source.txt 1508–1523 (Takesaki/Jones legs (c)) | — | standing (derived) | b/c | (R1) | +| (A16) | faithful normal product state on 𝔄(I₁)e_𝔄 ∨ 𝔄(I₂′)e_𝔄 | provable given (A13) + (A15) | proof written out in KOE03 prop:subsplit; criterion now read in dB74 (tier (b), mineru-unchecked) | — | local | b | (R1), (R12) | + +## Degeneracies and boundary cases + +| Case | Effect on the adopted form | Tier | +|---|---|---| +| intended case is nonvacuous | named instances exist in the corpus, at attestation level only: the (A8) satisfiers (free KG, free spin-½, U(1)-current derivative and stress-energy models) and (R15)'s LSU(n)_k — every leg rests on tier (c) attestations ((R2)'s BW86/FG93 route); the type III row below records where the bare definition is non-vacuous | c | +| zero object / scalars | Λ(1) = ℂ1: always split (ℂ1 is a type I factor). Either endpoint a type I factor (incl. Λ(2) = 𝔅(ℋ)): trivially split — the definition has no non-triviality clause, matching [DL84] (its Cor. 2.3(d) handles N = ℂ1 and N = 𝔅(ℋ) explicitly) | b | +| identity inclusion Λ(1) = Λ(2) = 𝔐 | split iff 𝔐 is a type I factor; fails for the hyperfinite III₁ factor (existence attested via KOE03/BDF87, (c)) | a/c | +| finite-dimensional | **not trivial**: split ⇒ Λ(1) ∩ Λ(2)′ = ℂ1 (one-line proof), but not conversely — 5-dimensional witness (ℋ = ℂ⁵, Λ(2) = M₂⊕M₃, Λ(1) = {p, 1−p}″, p = diag(1,0)⊕diag(1,1,0)): trivial relative intersection, statistically independent, yet no interpolating type I factor (unital subfactor of M₂⊕M₃ forces r ∣ 2 and r ∣ 3 ⇒ r = 1). Minimal witness: ℂ⊕ℂ ⊆ ℂ⊕ℂ, now formalized as `VonNeumannAlgebra.not_isSplitInclusion_diagonalAlgebra` (Prior art) | — (verified computation) | +| commutative | Λ(1) commutative harmless; Λ(2) commutative ⇒ split iff Λ(1) = ℂ1 (only commutative factor is ℂ1). Witnesses: ℂ⊕ℂ ⊆ ℂ⊕ℂ (formalized, see Prior art); L∞[0,1] ⊆ L∞[0,1] | — | +| non-separable / non-σ-finite | no effect on the bare form (ℂ1 ⊆ 𝔅(ℋ) splits on any ℋ); separability enters only with the standardness refinement, where it becomes a **theorem** ([DL84] Prop. 1.6) | b | +| type III | intended case; the definition is non-vacuous exactly when neither endpoint is type I | a | +| non-unital / degenerate representation | dissolves: 1 ∈ Λ(1) ⊆ 𝔑 forces unit-sharing — a derived fact, not a hypothesis (refutation hole H2); no fetched source entertains a non-unital variant | — | +| universally orthogonal index element | net level: touching pairs are excluded by the definition's typography (Ī₁ ⊂ I₂), and the exclusion is essential ((R6)(c)); empty pair-index ⇒ vacuously split, no effect | a | +| quantifier swap: ∀ pairs ∃ 𝔑 ↦ ∃ 𝔑 ∀ pairs | contradictory in any net with factorial local algebras: 𝔐 ⊆ 𝔅(I₂) for all I₂ plus locality forces 𝔐 ⊆ Z(𝔅(I₂)) = ℂ1, then 𝔅(I₁) ⊆ ℂ1 — see (X8) | a | +| hypothesis dropped: "type I" | strictly weaker — (X1) | a/c | +| hypothesis dropped: "factor" | strictly weaker — (X2) | — | +| hypothesis dropped: Λ(1) ⊆ 𝔑 | vacuous — (X3) | — | + +## Rejected formulations and refuted claims + +**Append-only.** + +| id | Candidate or claim | Disposition | Discriminator | Tier | Date | +|---|---|---|---|---|---| +| (X1) | interpolating *factor* of arbitrary type | rejected | **(X1) separating object** — identity inclusion of the hyperfinite type III₁ factor: interpolates itself, split fails (identity-inclusion row) | a/c | 2026-08-14 | +| (X2) | interpolating type I *algebra* instead of factor | rejected | **(X1) separating object** — ℂ⊕ℂ ⊆ ℂ⊕ℂ on ℂ²: the only interpolating algebra is ℂ⊕ℂ, type I but not a factor | — | 2026-08-14 | +| (X3) | "Λ(1)′ ∩ Λ(2) contains a type I factor" | rejected | **(X2) degeneracy/vacuity** — ℂ1 always qualifies; satisfied by every unital inclusion, incl. the non-split (X2) witness | — | 2026-08-14 | +| (X4) | statistical independence of (Λ(1), Λ(2)′) as the definition (≡ quasi-split, (D7)) | rejected | **(X1) separating object** — the 5-dimensional witness (degeneracy table): quasi-split and W*-independent yet not split; it has no semi-standard vector, exactly threading [DL84]'s gap. **(X5) conditional equivalence** — split ⇔ quasi-split under a semi-standard state ([DL84] §1, tier (b)); the standard-position sub-question is thereby settled affirmatively. Under HS17's spatial gloss of ≅ ((C7)) the candidate becomes (X7) and is equivalent | b | 2026-08-14 | +| (X5) | uniqueness of the interpolating 𝔑 required | rejected | **(X1) separating object** — ℂ1 ⊆ M₂(ℂ): both ℂ1 and M₂ interpolate. [DL84] Cor. 2.4 confirms structurally: uniqueness only per standard vector | a/b | 2026-08-14 | +| (X6) | strict intermediacy (𝔑 ∉ {Λ(1), Λ(2)}) | rejected | **(X1) separating object** — ℂ1 ⊆ M₂(ℂ) is split, but the only unital subfactors of M₂ are the endpoints | — | 2026-08-14 | +| (X7) | tensor/unitary form: ∃ W: ℋ → ℋ_A ⊗ ℋ_B with WΛ(1)W* ⊆ 𝔅(ℋ_A)⊗1, WΛ(2)′W* ⊆ 1⊗𝔅(ℋ_B) | equivalent | — ((⇐) is HS17's construction, tier (a); (⇒) via the type I structure theorem, used verbatim in [DL84] Prop. 1.5, tier (b), mineru-unchecked — promoted from (d) by the refutation fetch). HS17's literal ℋ⊗ℋ form is conditionally equivalent (needs the cyclicity hypotheses making both legs ℋ) | b | 2026-08-14 | +| (X8) | net-level ∃ 𝔑 ∀ pairs | rejected | **(X2) degeneracy** — forces 𝔐 = ℂ1 in any net with factorial local algebras (corpus-only argument via locality + factoriality, no irreducibility needed); named case: free scalar field / any III₁ net | a | 2026-08-14 | +| (X9) | *claim* [KOE03 source.txt 6666–6669]: properly infinite von Neumann algebras on a separable ℋ admit joint cyclic-separating vectors | refuted | counterexample 𝔑 = 𝔐 = 𝔅(ℓ²): properly infinite, separable, **no separating vector at all**. Corrected statement = [DL84] Prop. 1.2 (needs standard action / properly infinite commutants); KOE03's application is sound, its freestanding sentence is not | b | 2026-08-14 | +| (X10) | *claim* [HS17 source.txt 991]: finite-dimensional commuting pair with trivial intersection is always statistically independent | refuted | counterexample: 𝔄_A = {1, p}″, 𝔄_B = {1, q}″ with p, q nonzero orthogonal projections, p + q < 1 (e.g. on ℂ³): commuting, 𝔄_A ∩ 𝔄_B = ℂ1, but 𝔄_A ∨ 𝔄_B ≅ ℂ³ ≇ ℂ⁴ ≅ 𝔄_A ⊗ 𝔄_B, and the product state with φ(p) = ψ(q) = 1 admits no extension (ω(1−p−q) = −1). True for commuting finite-dimensional *factors* | — (written-out argument) | 2026-08-14 | + +## Prior art + +| System | Found | Relation to variants | How searched | Measured at | +|---|---|---|---|---| +| this repository | `VonNeumannAlgebra.IsSplitInclusion` (`QuantumSystem/Algebra/VonNeumannAlgebra/SplitInclusion.lean`) — interpolating type I factor, containment derived; monotonicity, sandwich and self constructors; `IsSplitInclusion.exists_tensor_decomposition` (spatial split of the interpolating factor and its commutant) | same as (D6)/adopted form; the tensor decomposition is the (X7)(⇒) direction | find/grep over QuantumSystem/ | working tree, 2026-08-15 | +| this repository | `VonNeumannAlgebra.not_isSplitInclusion_diagonalAlgebra` (`QuantumSystem/Algebra/LocalNet/Examples.lean`) — identity inclusion of `diagonalAlgebra := commutantSet {diagonalProjection}` on `EuclideanSpace ℂ (Fin 2)` (concretely ℂ⊕ℂ, the diagonal operators) is **not** split, via `not_isTypeIFactor_diagonalAlgebra`/`not_isFactor_diagonalAlgebra` and `IsSplitInclusion.isTypeIFactor_of_self`; axiom-checked (`#print axioms`), rests only on `propext`, `Classical.choice`, `Quot.sound` | **negative witness** — realizes the degeneracy table's minimal witness ℂ⊕ℂ ⊆ ℂ⊕ℂ (also the object underlying (X2)'s discriminator); distinct in kind from the positive rows above (`IsSplitInclusion` itself, `exists_tensor_decomposition`, `VonNeumannNet.SplitProperty`), which inhabit the predicate rather than refute it | `lean_local_search`, `lean_declaration_file`, axiom check via `#print axioms` | working tree, 2026-08-15 | +| this repository | `LocalNet.SplitProperty` (`QuantumSystem/Algebra/LocalNet/SplitProperty.lean`) — nested form over `ProperContainment` pairs, stated as `VonNeumannNet.SplitProperty` at the representation instance | same as (D1) at net level (nested form, as adopted) | same | working tree, 2026-08-15 | +| this repository | type classification substrate: `IsFactor`, `IsTypeI`, `IsTypeIFactor`, `IsTypeIInfinite`, Murray–von Neumann equivalence, `IsTypeIFactor.exists_starAlgEquiv`, type I structure theorem, `vnTensorLeft/Right` commutant theorems, double commutant theorem (both halves) | supports the adopted form; (X7)(⇒)'s external is proved here | same | working tree, 2026-08-14 | +| this repository | could not find: statistical independence (D2), split unitary W (D3), product-state form (D4), standard split inclusion, quasi-split (D7), W*-independence, funnel property, hyperfinite III₁, normal states | — | grep for product state / independence / standard split / funnel / hyperfinite / cyclic | working tree, 2026-08-14 | +| Mathlib | `VonNeumannAlgebra`, `WStarAlgebra`, `commutant`, `commutant_commutant`, WOT files — substrate only | can phrase an inclusion and commutants; nothing more | grep over `.lake/packages/mathlib`, `lean_leansearch` | mathlib rev `5450b53e5ddc75d46418fabb605edbf36bd0beb6` | +| Mathlib | could not find: split inclusion, type I factor, factor (vN sense), MvN equivalence, hyperfinite, normal state, statistical independence, vN double commutant theorem (the structure's field is an axiom, not the theorem) | no Mathlib declaration can state any variant | grep sweeps + `lean_leansearch` | mathlib rev `5450b53e5ddc75d46418fabb605edbf36bd0beb6` | +| Lean ecosystem | vN double commutant TFAE is a Lean AI leaderboard benchmark (solved by AI systems, May–July 2026) — corroborates absence from Mathlib | substrate | leaderboard page fetched | 2026-08-14 | +| Isabelle AFP | substrate only (Complex_Bounded_Operators, Hilbert tensor products, Kraus Maps, GNS 2026, Registers); no vN algebra structure, factors, or split found | Hilbert tensor product is substrate (D2) would need | topic index + entry pages; **search.isa-afp.org unreachable (TLS)** | 2026-08-14 | +| Coq/Rocq (CoqQ/mathcomp) | finite-dimensional only; no vN algebra structure | trivialised setting for every variant | web searches, paper summaries | 2026-08-14 | +| Lean Zulip | could not find indexed threads, having searched site-scoped and archive-scoped web queries — a statement about the searches run, not about absence | — | web searches | 2026-08-14 | +| any system, AQFT level | could not find any other formalization of Haag–Kastler nets or the net-level split property | this repository's `LocalNet.SplitProperty` is the only one located | web searches | 2026-08-14 | + +## Open questions + +- A concrete non-split net, named at a checkable tier: [DL84] announces + > In particular we give examples of field theories which do not fulfill the split property. + (§9–10, pages not converted). Converting DL84 pp. 15–44 would likely move (A13) from `open`. +- "Exhausting 𝔄" and "intermediate" in (D5)/(R9): undefined in every fetched text. +- (A14) asymptotic scale invariance: formulation lives in BDF87 (unfetched). +- (R4) vs (R5): which hypothesis-set BDF87 actually uses — needs the paper. +- Whether the free KG field satisfies (A14) (needed to run (A7)'s witness fully inside HS17's own hypotheses). +- KOE03's stated open problem (source.txt 2750–2752): a split-based triviality argument for certain coset representations is "out of reach to date". +- (A1): does any result in this circle actually need separability at the bare-form layer? (For standard split inclusions it is a theorem; no fetched result visibly consumes the standing assumption.) + +## Sources + +**Append-only.** + +| Key | Work | Status | Cache | Version | Tier reached | Retrieved | +|---|---|---|---|---|---|---| +| KOE03 | S. Köster, *Structure of Coset Models*, dissertation, arXiv math-ph/0308031 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-math-ph-0308031/` | arXiv v1 | a | 2026-08-14 | +| HS17 | S. Hollands, K. Sanders, *Entanglement measures and their properties in quantum field theory*, arXiv 1702.04924 | retrieved (arXiv LaTeX, verbatim) | `references/arxiv-1702.04924/` | arXiv | a | 2026-08-14 | +| dB74 | D. Buchholz, *Product states for local algebras*, Comm. Math. Phys. 36 (1974) | retrieved **partial** — pp. 1–8 of 18, Project Euclid PDF via MinerU hybrid-engine | `references/buchholz-1974-product-states/` | published | b (mineru-unchecked) | 2026-08-14 | +| DL84 | S. Doplicher, R. Longo, *Standard and split inclusions of von Neumann algebras*, Invent. Math. 75 (1984) 493–536 | retrieved **partial** — pp. 1–14 of 44 (§0–§4), GDZ digitization via MinerU hybrid-engine | `references/doplicher-longo-1984-standard-split/` | published | b (mineru-unchecked) | 2026-08-14 | +| FG93 | Gabbiani, Fröhlich, *Operator algebras and conformal field theory* | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| BDF87 | Buchholz, D'Antoni, Fredenhagen, *The universal structure of local algebras*, CMP 111 (1987) | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| BW86 | Buchholz, Wichmann, *Causal independence and the energy-level density of states…* | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| BDL86 | Buchholz, Doplicher, Longo, *On Noether's theorem in quantum field theory* | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| ADF87 | D'Antoni, Doplicher, Fredenhagen, Longo, *Convergence of local charges…* | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| FV13 | Fewster, Verch, *The necessity of the Hadamard condition* (HS17's fewster_2) | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| DHR02 | Donald, Horodecki, Rudolph (HS17's donald_2) | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| MTW | Morinelli, Tanimoto, Weiner, *Conformal covariance and the split property* | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| SS90 | Summers, independence-notions survey (KOE03's sS90) | not retrieved — not attempted this run | — | — | d | 2026-08-14 | +| GLW98 | Guido, Longo, Wiesbrock (KOE03's GLW98) | not retrieved — not attempted this run | — | — | c | 2026-08-14 | +| DM | Dixmier, Maréchal (DL84's ref. [14]) | not retrieved — not attempted this run | — | — | c | 2026-08-14 | + +Further works cited by the corpus and not retrieved (uH87, CC01, KLM01, vL97, +fX00a, florig, narnhofer_1, summers_1/2, haag_2, dantoni, buchholz_3, +buchholz_5, LRT78, FJ96, mT72, vJ83, wD75, RS61, hjB68, bS74): every claim +through them carries a substitution sentence, no locators beyond the attesting +sources' own citations. + +## Not investigated + +- **The [ext] gap.** Lane 5 swept only the formalization landscape; **no lane + checked any of the external mathematical results** lane 2 marked. The + refutation pass fetched exactly two (dB74 pp. 1–8, DL84 pp. 1–14); all other + [ext] edges — BW86, BDF87, FG93, BDL86, ADF87, uH87, fewster_2, donald_2, + MTW/weiner, CC01, KLM01, vL97, fX00a, sS90, florig, GLW98, Dixmier–Maréchal, + narnhofer_1, summers_1/2, haag_2, dantoni, buchholz_3, buchholz_5 — remain + unexamined; (R2), (R4), (R5), (R12), (R13), (R15), (R18), (R19) and the + GLW98/fewster_2 witness legs rest entirely on attestations. +- **Unconverted pages.** dB74 pp. 9–18; DL84 pp. 15–44, including Th. 8.3's + dyadic-chain proof ((R9)), §6 standard-vector structure, and the §9–10 + non-split field theories that would unblock (A13). +- **MinerU output was not compared against page images**: every dB74/DL84 quote + and locator stays (b) with `mineru-unchecked`. +- Degeneracy probes skipped: type II endpoints as separate witnesses; whether + split inclusions of type III algebras force 𝔑 type I_∞; the repaired + candidate "Λ(1)′ ∩ Λ(2) is a type I factor"; σ-finiteness separately from + separability. +- Variants sighted, not pursued: the C*-independence side of the sS90 taxonomy; + HS17's curved-spacetime axiom variants a3′), a4′); the funnel property + (searched only by lane 5 as a keyword). +- AFP full-text search (site unreachable); Lean Zulip content; CoqQ source. +- KOE03's finite-index chapters beyond the grep hits; HS17's Thm_m>0, Thm_KMS, + Thm_ER<EN, Thm_EN<Em and the N-Cbit construction (iterate (R11)'s mechanism). +- **The unexamined base**: the tier (c) rows everything above stands on — (R2), + (R4), (R5) and the external legs of (A3), (A7), (A15), (R6)(b), (R8), (R11) + — plus the mineru-unchecked (b) layer of dB74/DL84. From 2e21b4b671336883e5f36f433e1197f85ba38890 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sat, 15 Aug 2026 20:44:09 +0000 Subject: [PATCH 102/113] docs: record math-review ledger entries for LocalNet/VonNeumannAlgebra MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Six refuted claims from the /math-review pass over the causal-index-set and split-inclusion work: the ProperContainment collar re-adjudication, two citation-drift claims (Naaijkens 2012 vs NAA13, Verch 2025 §1.2), the zeroHom docstring/triviality contradiction, the isSplitInclusion_commutant docstring-contradiction claim, and the Yngvason arXiv:1401.2652 citation (verified against the fetched PDF). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-review/ledger.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.claude/skills/math-review/ledger.md b/.claude/skills/math-review/ledger.md index 1c25dc1..5046e79 100644 --- a/.claude/skills/math-review/ledger.md +++ b/.claude/skills/math-review/ledger.md @@ -55,3 +55,9 @@ re-adjudicated (the new adjudication replaces the old row). | Target | P | Claim | Refutation | Depends on | Commit | Date | |---|---|---|---|---|---|---| <!-- Append below. Newest last. --> +| `QuantumSystem/Algebra/LocalNet/SplitProperty.lean:ProperContainment` | 3 | The causal collar field `exists_orthogonal_of_properlyContained` is a repository invention carried by no literature definition of the split property — **re-adjudicated 2026-08-15 against the strengthened field, which now also demands `¬ O₃ ≤ O₁`**; this row replaces the `4d8a21b` row, voided by expiry when the field changed | KOE03 defines its own `⋐` by "its *causal complement* `I' := S¹ ∖ Ī` is not the empty set" (`references/arxiv-math-ph-0308031/source.txt:925`); with `I₂` open and `Ī₁` closed, `Ī₁ ⊂ I₂` forces a nonempty connected component `J` of `I₂ ∖ Ī₁`, which is a proper interval with `J ≤ I₂` and `I₁ ⟂ J` — the collar, derived from the source's own separation condition. The added `¬ O₃ ≤ O₁` clause is carried by the same derivation one step further: `J` is nonempty and disjoint from `I₁`, so `¬ J ≤ I₁` is free. dB74 states the thickening shape `O + N ⊂ Ô` that `ofThicken` implements (`references/buchholz-1974-product-states/source.txt:15`), and `ofThicken` proves the clause from strictness of `thicken Λ₁ ⊂ Λ₂` | `ProperContainment`, `ProperContainment.ofThicken` | 4ec09ec (field measured in the **working tree**, not yet committed — re-check on the commit that lands it) | 2026-08-15 | +| `QuantumSystem/Algebra/LocalNet/Net.lean:LocalNet` (also `LocalNet.Faithful`, the `Finset` `CausalOrthogonality` instance, `QuasiLocalAlgebra.lean` module doc) | 4 | The docstring citation "Naaijkens 2012" is a mis-dated citation of NAA13 (arXiv 1311.2717, 2013) with section numbers that match neither work | "Naaijkens 2012" is a different work: P. Naaijkens, *Anyons in Infinite Quantum Systems: QFT in d=2+1 and the Toric Code*, PhD dissertation, Radboud Universiteit Nijmegen, 2012 (handle `2066/92737`). The repo expands the cite itself (`QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean:45`: "Naaijkens, *Anyons in Infinite Quantum Systems*, 2012, §3.2"), and all cited sections match the thesis TOC (§1.3 "Inductive limits" — quasi-local algebra; §3.2 "Algebraic quantum field theory" — covariance axiom; §3.4 "Quantum lattice systems" — lattice net over 𝒫_f(L)); against NAA13 the same section numbers are nonsense (§1.3 = "Topics not covered"). The note-locator comparison (NAA13 §1.2/§2.4) was made against the wrong work. Residual: a disambiguation nit (expand the bare short cite), not a drift | `LocalNet`, `LocalNet.Faithful` (docstrings); the full cite at `QuantumSystem/Algebra/CStarAlgebra/Representation/Conjugation.lean` | 4ec09ec (working tree) | 2026-08-15 | +| `QuantumSystem/Algebra/LocalNet/Covariance.lean:LocalNet.Covariance` (module doc) | 4 | "Verch 2025 §1.2" appears in no extraction note's source table and could not be verified — suspected phantom citation | Resolves to R. Verch, *Lecture Notes on Operator Algebras and Quantum Field Theory*, arXiv:2507.00900 (2025-07-01); its subsection 1.2 ("Algebraic QFT on Minkowski Spacetime: Haag-Kastler Nets of Local Algebras") states exactly the cited covariance axiom `α_L(𝒜(O)) = 𝒜(L(O))` (source `York-Notes2025.tex` lines 351–353). The extraction notes index only their own corpora, so absence from their source tables is not drift | `LocalNet.Covariance` (module doc) | 4ec09ec (working tree) | 2026-08-15 | +| `QuantumSystem/Algebra/LocalNet/Examples.lean:zeroHom` | 1 | The `zeroHom`/`zeroRep` docstring ("this still exhibits the property rather than trivialising it away") contradicts the repo's own statements that the zero representation trivialises the split property | "Trivialising it away" means annihilation on the zero *space* (where `IsSplitInclusion` is identically false), not trivial satisfaction: the clause "`𝓡(O)` contains `1` regardless, since a von Neumann algebra is unital" is shared verbatim with `SplitProperty.lean`'s `VonNeumannNet.SplitProperty` module prose, whose next sentence states the nonzero-space/zero-space dichotomy the docstring restates; and `Examples.lean`'s own module header concedes the triviality at length ("stated so it is not mistaken for evidence"). The mathematical residue (collapse to `ℂ1` for *any* representation on `ℂ`, sole witness) survives — only the contradiction reading was refuted | `zeroHom` (docstring), `VonNeumannNet.SplitProperty` (module prose), `Examples.lean` module header | 351f5dd (working tree) | 2026-08-15 | +| `QuantumSystem/Algebra/LocalNet/SplitProperty.lean:VonNeumannNet.SplitProperty.isSplitInclusion_commutant` (and `LocalNet.SplitProperty.isSplitInclusion_commutant`) | 4 | The two `isSplitInclusion_commutant` docstrings contradict each other | The two theorems have the same shape (`O₁ ⋐ O₂`, `O₂ ⟂ O_B` ⊢ `IsSplitInclusion 𝓡(O₁) 𝓡(O_B)′`), the second is a one-line specialisation of the first, and the second docstring's summary of the first (Haag duality for the converse, Buchholz's four-term chain) is accurate; no proposition on which they disagree exists in the current tree. Confirmed by the aggregator reading both docstrings in source | `VonNeumannNet.SplitProperty.isSplitInclusion_commutant`, `LocalNet.SplitProperty.isSplitInclusion_commutant` (both docstrings) | 351f5dd (working tree) | 2026-08-15 | +| `QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean:IsFactor.exists_spatial_tensor_decomposition` (module docs of `StructureTheorem.lean` and `TensorFactor.lean` also cite it) | 4 | Citation "J. Yngvason, arXiv:1401.2652, §5.1, eqs. (38)/(39)" is unverifiable — no `references/` cache exists for it, unlike every other of the nine sources cited in this file set, and neither resolved extraction note lists it in its `## Sources` table | Fetched arXiv:1401.2652 directly (PDF → `pdftotext`): confirmed author J. Yngvason, confirmed §5.1 titled "Causal Independence and Split Property", confirmed eqs. (38)/(39) verbatim-match the docstrings' `𝒜₁ ⊂ 𝒩 ⊂ 𝒜₂′` / tensor-decomposition content, down to which symbol plays which role. The "no cache ⇒ suspicious" inference does not hold — it is a caching-completeness gap (8/9 sources cached), not a correctness signal | `StructureTheorem.lean` module doc + `IsFactor.exists_spatial_tensor_decomposition` docstring, `TensorFactor.lean` module doc | 351f5dd (working tree) | 2026-08-15 | From a2fa4f5f65711f41f48170350a3f61e1206b7fbe Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 14:12:12 +0000 Subject: [PATCH 103/113] feat: state the Gelfand-Naimark theorem and its separable refinement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces gelfand_naimark_theorem with three statements: exists_isometric (isometric, injective, closed-range representation), exists_starAlgEquiv_range (the classical *-isomorphism-onto-a-closed-subalgebra form), and exists_isometric_separable, which puts a separable C*-algebra on a separable Hilbert space. The last needs a countable witness, so PureState gains exists_norm_sq_of_ne_zero — a pure state norming a, not merely detecting it — and GNS/Separable builds the norming family indexed by a dense sequence of the algebra. lp separability over a countable index goes to ForMathlib. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- QuantumSystem.lean | 2 + .../Algebra/CStarAlgebra/GNS/DirectSum.lean | 60 ++++- .../Algebra/CStarAlgebra/GNS/Separable.lean | 244 ++++++++++++++++++ .../Algebra/CStarAlgebra/GelfandNaimark.lean | 132 ++++++++-- .../Algebra/CStarAlgebra/PureState.lean | 130 ++++++---- .../Analysis/Normed/Lp/Separable.lean | 86 ++++++ 6 files changed, 578 insertions(+), 76 deletions(-) create mode 100644 QuantumSystem/Algebra/CStarAlgebra/GNS/Separable.lean create mode 100644 QuantumSystem/ForMathlib/Analysis/Normed/Lp/Separable.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 836e01b..62c5c76 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -5,6 +5,7 @@ public import QuantumSystem.Algebra.CStarAlgebra.GNS.Construction public import QuantumSystem.Algebra.CStarAlgebra.GNS.DirectSum public import QuantumSystem.Algebra.CStarAlgebra.GNS.PureState public import QuantumSystem.Algebra.CStarAlgebra.GNS.Representation +public import QuantumSystem.Algebra.CStarAlgebra.GNS.Separable public import QuantumSystem.Algebra.CStarAlgebra.PureState public import QuantumSystem.Algebra.CStarAlgebra.QuasiState public import QuantumSystem.Algebra.CStarAlgebra.Representation @@ -64,6 +65,7 @@ public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.WeakOperatorTopolo public import QuantumSystem.ForMathlib.Analysis.Matrix.Basic public import QuantumSystem.ForMathlib.Analysis.Matrix.Hermitian public import QuantumSystem.ForMathlib.Analysis.Matrix.Order +public import QuantumSystem.ForMathlib.Analysis.Normed.Lp.Separable public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant public import QuantumSystem.ForMathlib.InformationTheory.KullbackLeibler.KLFun public import QuantumSystem.ForMathlib.LinearAlgebra.Matrix.PartialTrace diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean index 20a40eb..4372566 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean @@ -3,6 +3,7 @@ module public import Mathlib.Analysis.CStarAlgebra.Hom public import Mathlib.Analysis.InnerProductSpace.l2Space public import QuantumSystem.Algebra.CStarAlgebra.GNS.PureState +public import QuantumSystem.Algebra.CStarAlgebra.Representation public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation @[expose] public section @@ -150,8 +151,9 @@ lemma directSumCLM_adjoint (a : A) : rw [ContinuousLinearMap.star_eq_adjoint] /-- The direct sum representation as a non-unital *-algebra homomorphism from `A` -to bounded operators on the direct sum Hilbert space. This is the universal -representation used in the Gelfand-Naimark theorem. -/ +to bounded operators on the direct sum Hilbert space. This is the representation +used in the Gelfand-Naimark theorem; see `rep` for its bundled form, whose docstring +records why it is an atomic rather than a universal representation. -/ noncomputable def directSumAlgHom : A →⋆ₙₐ[ℂ] 𝓑(Hilbert A) where toFun a := directSumCLM a map_mul' a b := by @@ -309,6 +311,60 @@ theorem directSumAlgHom_isometry (a : A) : ‖directSumAlgHom a‖ = ‖a‖ := NonUnitalStarAlgHom.norm_map directSumAlgHom directSumAlgHom_injective a + +/-- The direct sum of the GNS representations of all pure states, bundled as a `CStarRep A`. + +This is the representation that witnesses the Gelfand-Naimark theorem +(`CStarRep.exists_isometric`). Summing over *pure* states — rather than over all states — +makes this a (non-reduced form of the) **atomic representation**: it is not the universal +representation, which is the direct sum over the whole state space. The index type is the +full type `PureState A`, not a set of unitary equivalence classes, so the same equivalence +class is repeated once per pure state realising it. -/ +noncomputable def rep (A : Type*) [NonUnitalCStarAlgebra A] : CStarRep A where + H := Hilbert A + π := directSumAlgHom + + +@[simp] +lemma rep_π : (rep A).π = directSumAlgHom (A := A) := rfl + + +/-- The direct sum representation is isometric, in the bundled form. -/ +theorem rep_isometry : Isometry (rep A).π := + AddMonoidHomClass.isometry_of_norm _ directSumAlgHom_isometry + + +/-- The direct sum representation is faithful, in the bundled form. -/ +theorem rep_injective : Function.Injective (rep A).π := + directSumAlgHom_injective + + +/-- The image of `A` under the direct sum representation is norm closed in `𝓑(H)`. + +Together with `rep_isometry` and `rep_injective` this is what makes the image a +C\*-subalgebra: `NonUnitalStarAlgHom.range` is already a `*`-subalgebra, and closedness +upgrades it to a C\*-subalgebra. It holds because `A` is complete and the representation +is isometric, so it is a closed embedding. -/ +theorem rep_isClosed_range : + IsClosed (NonUnitalStarAlgHom.range (rep A).π : Set 𝓑((rep A).H)) := by + rw [NonUnitalStarAlgHom.coe_range] + exact rep_isometry.isClosedEmbedding.isClosed_range + + +/-- The direct sum representation, corestricted to its image, is a `*`-isomorphism +of `A` onto the C\*-subalgebra `NonUnitalStarAlgHom.range (rep A).π` of `𝓑(H)`. -/ +noncomputable def repRangeEquiv (A : Type*) [NonUnitalCStarAlgebra A] : + A ≃⋆ₐ[ℂ] NonUnitalStarAlgHom.range (rep A).π := + StarAlgEquiv.ofBijective (NonUnitalStarAlgHom.rangeRestrict (rep A).π) + ⟨fun _ _ h => rep_injective (congrArg Subtype.val h), by rintro ⟨_, x, rfl⟩; exact ⟨x, rfl⟩⟩ + + +/-- The `*`-isomorphism of `A` onto the image of the direct sum representation is +isometric: it preserves the norm inherited from `𝓑(H)`. -/ +theorem norm_repRangeEquiv (a : A) : + ‖((repRangeEquiv A a : NonUnitalStarAlgHom.range (rep A).π) : 𝓑((rep A).H))‖ = ‖a‖ := + directSumAlgHom_isometry a + end DirectSum end GNS diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Separable.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Separable.lean new file mode 100644 index 0000000..87e878e --- /dev/null +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Separable.lean @@ -0,0 +1,244 @@ +module + +public import Mathlib.Analysis.CStarAlgebra.Hom +public import QuantumSystem.Algebra.CStarAlgebra.GNS.PureState +public import QuantumSystem.Algebra.CStarAlgebra.Representation.DirectSum +public import QuantumSystem.ForMathlib.Analysis.Normed.Lp.Separable + +/-! +# A countable norming family of pure states, for a separable C\*-algebra + +The Gelfand-Naimark representation built in `CStarAlgebra/GNS/DirectSum.lean` is indexed by +the *whole* pure state space, so its Hilbert space is typically nonseparable even when `A` +is separable. This file builds the countable replacement. + +The idea is to index not by states but by a dense sequence of the algebra: for each nonzero +member `aₙ` of a countable dense sequence, pick a pure state that **norms** `aₙ` +(`IsPureState.exists_norm_sq_of_ne_zero`), and take the ℓ²-direct sum of the corresponding +GNS representations. Norming — rather than merely detecting — is what makes a countable +family enough: for `a ≠ 0` and `aₙ` within `‖a‖ / 2` of `a`, the `n`-th representation +cannot annihilate `a`, because it does not shrink `aₙ`. + +## Main results + +* `GNS.Representation.norm_sq_apply_cyclic` — `‖T.π x T.ξ‖ ^ 2 = (ω (star x * x)).re` for any + GNS triplet. This is what turns a norming *state* into a non-vanishing *operator*. +* `GNS.Representation.separableSpace_H` — the Hilbert space of a GNS triplet over a + separable algebra is separable. +* `GNS.normingFamily` — the countable family of GNS representations described above, and + `GNS.normingFamily_separatesPoints`, `GNS.separableSpace_normingFamily_directSumHilbert`. + +The theorem these serve is `CStarRep.exists_isometric_separable`, in +`CStarAlgebra/GelfandNaimark.lean`. +-/ + +@[expose] public section + +open TopologicalSpace + +open scoped InnerProductSpace Adjoint ComplexHilbertSpace + +universe u + +namespace GNS + +variable {A : Type u} [NonUnitalCStarAlgebra A] + +namespace Representation + +/-- For a GNS triplet, the squared length of the orbit vector `T.π x T.ξ` is the value of +the state at `star x * x`. + +This is the bridge between a *norming state* and a *non-vanishing operator*: a state whose +value at `star x * x` is `‖x‖ ^ 2` yields a representation with `‖T.π x T.ξ‖ = ‖x‖`. -/ +lemma norm_sq_apply_cyclic {ω : State ℂ A} (T : Representation ω) (x : A) : + ‖T.π x T.ξ‖ ^ 2 = (ω (star x * x)).re := by + have hstar : T.π (star x) = (T.π x)† := by + rw [map_star, ContinuousLinearMap.star_eq_adjoint] + have hval : T.π (star x * x) T.ξ = (T.π x)† (T.π x T.ξ) := by + rw [map_mul, hstar] + rfl + rw [T.gns_condition (star x * x), hval, ContinuousLinearMap.adjoint_inner_right, + inner_self_eq_norm_sq_to_K] + simp [← Complex.ofReal_pow] + +/-- A norming state gives an orbit vector of full length: if `ω (star x * x) = ‖x‖ ^ 2` +then `‖T.π x T.ξ‖ = ‖x‖`. -/ +lemma norm_apply_cyclic_of_norming {ω : State ℂ A} (T : Representation ω) {x : A} + (hx : ω (star x * x) = ((‖x‖ ^ 2 : ℝ) : ℂ)) : + ‖T.π x T.ξ‖ = ‖x‖ := by + have h := T.norm_sq_apply_cyclic x + rw [hx] at h + have h' : ‖T.π x T.ξ‖ ^ 2 = ‖x‖ ^ 2 := by rw [h, Complex.ofReal_re] + nlinarith [norm_nonneg (T.π x T.ξ), norm_nonneg x, h'] + +/-- The orbit map `a ↦ T.π a T.ξ` is `1`-Lipschitz. + +It is the composition of the contraction `a ↦ T.π a` with evaluation at a unit vector. -/ +lemma lipschitzWith_apply_cyclic {ω : State ℂ A} (T : Representation ω) : + LipschitzWith 1 (fun a : A => T.π a T.ξ) := by + refine LipschitzWith.of_dist_le_mul fun a b => ?_ + have hsub : T.π a T.ξ - T.π b T.ξ = T.π (a - b) T.ξ := by + rw [map_sub] + rfl + have hbound : dist (T.π a T.ξ) (T.π b T.ξ) ≤ ‖a - b‖ := by + calc dist (T.π a T.ξ) (T.π b T.ξ) = ‖T.π (a - b) T.ξ‖ := by rw [dist_eq_norm, hsub] + _ ≤ ‖T.π (a - b)‖ * ‖T.ξ‖ := ContinuousLinearMap.le_opNorm _ _ + _ ≤ ‖a - b‖ * 1 := by + gcongr + · exact NonUnitalStarAlgHom.norm_apply_le _ _ + · exact le_of_eq T.unit_norm + _ = ‖a - b‖ := mul_one _ + simpa [dist_eq_norm] using hbound + +/-- The Hilbert space of a GNS triplet over a **separable** C\*-algebra is separable. + +The orbit of the cyclic vector is a continuous image of `A`, hence separable; its span is +separable, and the span is dense by cyclicity. -/ +theorem separableSpace_H [SeparableSpace A] {ω : State ℂ A} (T : Representation ω) : + SeparableSpace T.H := by + have hrange : IsSeparable (Set.range fun a : A => T.π a T.ξ) := + isSeparable_range T.lipschitzWith_apply_cyclic.continuous + have hspan : IsSeparable + ((Submodule.span ℂ {x | ∃ a : A, T.π a T.ξ = x} : Submodule ℂ T.H) : Set T.H) := + hrange.span + rw [← isSeparable_univ_iff, ← T.cyclic.closure_eq] + exact hspan.closure + +end Representation + +section Norming + +variable (A) in +/-- The index type of the norming family: the positions of the **nonzero** members of a +fixed dense sequence of `A`. + +Dropping the zero members is what lets every index carry a pure state; the discarded +positions carry no information, since `0` is annihilated by every representation. When +`A = 0` the index type is empty, which is the correct answer there. -/ +noncomputable def NormingIndex [SeparableSpace A] : Type := {n : ℕ // denseSeq A n ≠ 0} + +instance [SeparableSpace A] : Countable (NormingIndex A) := + inferInstanceAs (Countable {n : ℕ // denseSeq A n ≠ 0}) + +/-- The element of the dense sequence sitting at a norming index. -/ +noncomputable def NormingIndex.elem [SeparableSpace A] (i : NormingIndex A) : A := + denseSeq A i.1 + +lemma NormingIndex.elem_ne_zero [SeparableSpace A] (i : NormingIndex A) : i.elem ≠ 0 := i.2 + +/-- A pure state norming the element at a norming index. -/ +noncomputable def normingState [SeparableSpace A] (i : NormingIndex A) : PureState A := + ⟨(IsPureState.exists_norm_sq_of_ne_zero i.elem i.elem_ne_zero).choose, + (IsPureState.exists_norm_sq_of_ne_zero i.elem i.elem_ne_zero).choose_spec.1⟩ + +lemma normingState_spec [SeparableSpace A] (i : NormingIndex A) : + (normingState i : State ℂ A) (star i.elem * i.elem) = ((‖i.elem‖ ^ 2 : ℝ) : ℂ) := + (IsPureState.exists_norm_sq_of_ne_zero i.elem i.elem_ne_zero).choose_spec.2 + +variable (A) in +/-- The **countable norming family**: one GNS representation for each nonzero member of a +dense sequence of `A`, at a pure state norming that member. -/ +noncomputable def normingFamily [SeparableSpace A] : SectorFamily.{u, u, 0} A where + Index := NormingIndex A + rep i := (PureState.gnsRepresentation (normingState i)).toCStarRep + +/-- Each summand of the norming family is separable. -/ +instance [SeparableSpace A] (i : NormingIndex A) : + SeparableSpace ((normingFamily A).rep i).H := + Representation.separableSpace_H _ + +/-- The direct-sum Hilbert space of the norming family is separable: it is an ℓ²-sum of +countably many separable spaces. -/ +instance separableSpace_normingFamily_directSumHilbert [SeparableSpace A] : + SeparableSpace (normingFamily A).directSumHilbert := + inferInstanceAs (SeparableSpace (lp (fun i : NormingIndex A => + ((normingFamily A).rep i).H) 2)) + +variable (A) in +/-- **The norming family separates points.** + +If every member annihilates `a ≠ 0`, take `aₙ` from the dense sequence within `‖a‖ / 2` of +`a`. Then `aₙ ≠ 0`, so it carries an index `i`, and its norming state gives +`‖π_i(aₙ) ξ_i‖ = ‖aₙ‖`. But `π_i(a) = 0` forces +`‖aₙ‖ = ‖π_i(aₙ - a) ξ_i‖ ≤ ‖aₙ - a‖ < ‖a‖ / 2`, contradicting `‖aₙ‖ > ‖a‖ / 2`. -/ +theorem normingFamily_separatesPoints [SeparableSpace A] : + (normingFamily A).SeparatesPoints := by + intro a ha + by_contra hne + have hapos : (0 : ℝ) < ‖a‖ := norm_pos_iff.mpr hne + -- A member of the dense sequence within `‖a‖ / 2` of `a`. + obtain ⟨n, hn⟩ := (denseRange_denseSeq A).exists_dist_lt a (by positivity : (0:ℝ) < ‖a‖ / 2) + have hdist : ‖denseSeq A n - a‖ < ‖a‖ / 2 := by + rw [dist_eq_norm] at hn + rwa [norm_sub_rev] at hn + have hb_lower : ‖a‖ / 2 < ‖denseSeq A n‖ := by + have := norm_sub_norm_le a (denseSeq A n) + rw [← norm_neg (a - denseSeq A n), neg_sub] at this + linarith + have hb_ne : denseSeq A n ≠ 0 := by + intro h + rw [h, norm_zero] at hb_lower + linarith + set i : NormingIndex A := ⟨n, hb_ne⟩ with hi + have helem : i.elem = denseSeq A n := rfl + set T := PureState.gnsRepresentation (normingState i) with hT + -- The representation at `i` norms `i.elem`. + have hnorm : ‖T.π i.elem T.ξ‖ = ‖i.elem‖ := + T.norm_apply_cyclic_of_norming (normingState_spec i) + -- but it kills `a`, so it can only see the difference. + have hzero : T.π a = 0 := ha i + have hsplit : T.π i.elem T.ξ = T.π (i.elem - a) T.ξ := by + rw [map_sub] + simp [hzero] + have hle : ‖T.π i.elem T.ξ‖ ≤ ‖i.elem - a‖ := by + rw [hsplit] + calc ‖T.π (i.elem - a) T.ξ‖ ≤ ‖T.π (i.elem - a)‖ * ‖T.ξ‖ := + ContinuousLinearMap.le_opNorm _ _ + _ ≤ ‖i.elem - a‖ * 1 := by + gcongr + · exact NonUnitalStarAlgHom.norm_apply_le _ _ + · exact le_of_eq T.unit_norm + _ = ‖i.elem - a‖ := mul_one _ + rw [hnorm, helem] at hle + linarith + +variable (A) in +/-- The ℓ²-direct sum of the norming family, bundled as a `CStarRep`. + +This is the separable counterpart of `GNS.DirectSum.rep`: same construction, but indexed by +a dense sequence of the algebra instead of by the whole pure state space. -/ +noncomputable def normingRep [SeparableSpace A] : CStarRep.{u, u} A where + H := (normingFamily A).directSumHilbert + π := (normingFamily A).directSumRep + +@[simp] +lemma normingRep_π [SeparableSpace A] : + (normingRep A).π = (normingFamily A).directSumRep := rfl + +instance [SeparableSpace A] : SeparableSpace (normingRep A).H := + separableSpace_normingFamily_directSumHilbert + +variable (A) in +/-- The norming representation is faithful. -/ +theorem normingRep_injective [SeparableSpace A] : + Function.Injective (normingRep A).π := + (normingFamily A).directSumRep_injective_of (normingFamily_separatesPoints A) + +variable (A) in +/-- The norming representation is isometric, by faithfulness. -/ +theorem normingRep_isometry [SeparableSpace A] : Isometry (normingRep A).π := + AddMonoidHomClass.isometry_of_norm _ fun a => + NonUnitalStarAlgHom.norm_map _ (normingRep_injective A) a + +variable (A) in +/-- The image of the norming representation is norm closed, so it is a C\*-subalgebra of +the bounded operators on a separable Hilbert space. -/ +theorem normingRep_isClosed_range [SeparableSpace A] : + IsClosed (NonUnitalStarAlgHom.range (normingRep A).π : Set 𝓑((normingRep A).H)) := by + rw [NonUnitalStarAlgHom.coe_range] + exact (normingRep_isometry A).isClosedEmbedding.isClosed_range + +end Norming + +end GNS diff --git a/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean b/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean index fc16d4c..4ffa029 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean @@ -1,6 +1,62 @@ module public import QuantumSystem.Algebra.CStarAlgebra.GNS.DirectSum +public import QuantumSystem.Algebra.CStarAlgebra.GNS.Separable + +/-! +# The Gelfand-Naimark theorem + +Every C\*-algebra, not necessarily unital and not necessarily commutative, is isometrically +`*`-isomorphic onto a norm closed `*`-subalgebra of the bounded operators on some complex +Hilbert space. This is the noncommutative Gelfand-Naimark theorem (Gelfand-Naimark 1943; +Murphy, *C\*-algebras and Operator Theory*, Ch. 3 "Ideals and Positive Functionals"; Pedersen, +*C\*-Algebras and Their Automorphism Groups*, Ch. 3 "Functionals and Representations"; +Blackadar, *Operator Algebras*, Ch. II "C\*-Algebras"; Takesaki, *Theory of Operator Algebras +I*, Ch. I "Fundamentals of Banach Algebras and C\*-Algebras" — chapter-level locators only, +since none of these four books was independently opened for this file; see the `math-review` +ledger entry for `GelfandNaimark.lean`), and it is not to be confused with the commutative +Gelfand-Naimark theorem — Gelfand duality — which Mathlib carries as +`gelfandTransform_isometry`. + +## Main results + +* `CStarRep.exists_isometric` — there is a representation `R : CStarRep A` whose `R.π` is + isometric, injective, and has norm closed range. The three conjuncts together say that + `R.π` identifies `A` with a C\*-subalgebra of `𝓑(R.H)`. +* `CStarRep.exists_starAlgEquiv_range` — the same statement in the form the classical + formulation uses: an explicit `*`-isomorphism of `A` onto a norm closed `*`-subalgebra + of `𝓑(R.H)` that preserves the norm. +* `CStarRep.exists_isometric_separable` — the **separable refinement**: when `A` is + separable the Hilbert space may be taken separable as well. + +The witness for the first two is `GNS.DirectSum.rep`, the ℓ²-direct sum of the GNS +representations of all pure states of `A`; faithfulness comes from there being enough pure +states (`IsPureState.exists_pos_re_of_ne_zero`), and isometry from faithfulness by +`NonUnitalStarAlgHom.norm_map`. The separable refinement uses a different witness, +`GNS.normingRep`, indexed by a dense sequence of the algebra instead of by the whole pure +state space. + +## Conventions and scope + +* The Hilbert space is produced in the *same* universe as `A`, which is stronger than the + usual textbook statement. +* Closedness of the range uses completeness of `A`; `NonUnitalStarAlgHom.range` supplies the + `*`-subalgebra structure, so "closed `*`-subalgebra" is exactly "C\*-subalgebra" here. +* Nondegeneracy of the representation is not asserted. It would not strengthen the + statement: corestricting any isometric `*`-representation to the closure of the span of + its image is again isometric and is nondegenerate, so the two existentials are equivalent. + (The witness `GNS.DirectSum.rep` is in fact nondegenerate, being a direct sum of cyclic + representations.) +* The witness of `CStarRep.exists_isometric` is itself never separable beyond the trivial + cases: it is indexed by the whole pure state space, and for `A = C₀(ℝ)` the point + evaluations already form a continuum. The separable refinement therefore does not + strengthen that theorem's witness but replaces it — see + `CStarRep.exists_isometric_separable` and `GNS.normingRep`. +* `CStarRep.exists_isometric_separable` does **not** claim that `H` may be taken to be + `ℓ²(ℕ)`. That is true, by the unitary classification of Hilbert spaces by the cardinality + of an orthonormal basis, but it is extra content and is not stated here. +* There is no unital corollary: nothing here states `R.π 1 = 1` for unital `A`. +-/ @[expose] public section @@ -9,28 +65,56 @@ open scoped ComplexHilbertSpace universe u -/-- -The **Gelfand-Naimark Theorem** (non-unital version): -Every non-unital C*-algebra `A` is isometrically *-isomorphic to a C*-subalgebra of -bounded operators on some Hilbert space `H`. +/-- **Gelfand-Naimark theorem** (noncommutative form, `A` not necessarily unital): +every C\*-algebra admits a faithful isometric `*`-representation whose image is norm closed, +that is, `A` is carried onto a C\*-subalgebra of `𝓑(H)` for some complex Hilbert space `H`. -We prove this by exhibiting: -1. A Hilbert space `H` (the ℓ²-direct sum of GNS Hilbert spaces over all pure states). -2. A non-unital *-homomorphism `φ : A →⋆ₙₐ[ℂ] 𝓑(H)` (the direct sum of GNS representations). -3. A proof that `φ` is injective and isometric (hence an isometric *-isomorphism onto its image). --/ -theorem gelfand_naimark_theorem : - ∀ (A: Type u) [NonUnitalCStarAlgebra A], - ∃ (H : Type u) (_ : ComplexHilbertSpace H), - ∃ (φ : A →⋆ₙₐ[ℂ] 𝓑(H)), Isometry φ := by - intro A _ - -- The Hilbert space is the ℓ²-direct sum of GNS Hilbert spaces over all pure states - let H := GNS.DirectSum.Hilbert A - -- The representation is the direct sum of all GNS representations - let φ := GNS.DirectSum.directSumAlgHom (A := A) - refine ⟨H, inferInstance, φ, ?_⟩ - -- To show φ is an isometry, it suffices to show it preserves norms - -- (since it's already additive as a *-homomorphism) - apply AddMonoidHomClass.isometry_of_norm - intro a - exact GNS.DirectSum.directSumAlgHom_isometry a +The three conjuncts are what make the conclusion an identification rather than a mere bound: +`Isometry R.π` gives `‖R.π a‖ = ‖a‖`, `Function.Injective R.π` makes `R.π` a bijection onto +its image, and `IsClosed` upgrades the `*`-subalgebra `NonUnitalStarAlgHom.range R.π` to a C\*-subalgebra. For +the same statement packaged as an explicit `*`-isomorphism, see +`CStarRep.exists_starAlgEquiv_range`. + +The Hilbert space is obtained in the same universe as `A`. The witness is +`GNS.DirectSum.rep A`, the ℓ²-direct sum of the GNS representations of all pure states. -/ +theorem CStarRep.exists_isometric (A : Type u) [NonUnitalCStarAlgebra A] : + ∃ R : CStarRep.{u, u} A, + Isometry R.π ∧ Function.Injective R.π ∧ IsClosed (NonUnitalStarAlgHom.range R.π : Set 𝓑(R.H)) := + ⟨GNS.DirectSum.rep A, GNS.DirectSum.rep_isometry, GNS.DirectSum.rep_injective, + GNS.DirectSum.rep_isClosed_range⟩ + + +/-- **Gelfand-Naimark theorem**, in the form the classical statement uses: every +C\*-algebra `A`, not necessarily unital, is isometrically `*`-isomorphic onto a norm closed +`*`-subalgebra `S` of `𝓑(H)` for some complex Hilbert space `H`. + +Isometry is stated as `‖(e a : 𝓑(R.H))‖ = ‖a‖` — the norm `S` inherits from `𝓑(R.H)` — +rather than through a norm structure on `S` itself. See `CStarRep.exists_isometric` for the +unbundled form. -/ +theorem CStarRep.exists_starAlgEquiv_range (A : Type u) [NonUnitalCStarAlgebra A] : + ∃ (R : CStarRep.{u, u} A) (S : NonUnitalStarSubalgebra ℂ 𝓑(R.H)) (e : A ≃⋆ₐ[ℂ] S), + IsClosed (S : Set 𝓑(R.H)) ∧ ∀ a : A, ‖((e a : S) : 𝓑(R.H))‖ = ‖a‖ := + ⟨GNS.DirectSum.rep A, NonUnitalStarAlgHom.range (GNS.DirectSum.rep A).π, GNS.DirectSum.repRangeEquiv A, + GNS.DirectSum.rep_isClosed_range, GNS.DirectSum.norm_repRangeEquiv⟩ + + +/-- **Gelfand-Naimark theorem, separable refinement**: a *separable* C\*-algebra, not +necessarily unital, admits a faithful isometric `*`-representation with norm closed image on +a **separable** complex Hilbert space. + +The refinement is genuine extra content over `CStarRep.exists_isometric`, whose witness is +indexed by the whole pure state space and is nonseparable for, say, `A = C₀(ℝ)`. The +witness here is `GNS.normingRep A`: the ℓ²-direct sum of the GNS representations of a +*countable* family of pure states, one norming each nonzero member of a dense sequence of +`A`. Norming rather than merely detecting is what makes a countable family separate the +points of `A` — see `GNS.normingFamily_separatesPoints`. + +Separability of `A` is sufficient and never necessary: `𝓑(ℓ²)` is not norm separable, yet +its identity representation on the separable space `ℓ²` is faithful. -/ +theorem CStarRep.exists_isometric_separable (A : Type u) [NonUnitalCStarAlgebra A] + [TopologicalSpace.SeparableSpace A] : + ∃ R : CStarRep.{u, u} A, TopologicalSpace.SeparableSpace R.H ∧ + Isometry R.π ∧ Function.Injective R.π ∧ + IsClosed (NonUnitalStarAlgHom.range R.π : Set 𝓑(R.H)) := + ⟨GNS.normingRep A, inferInstance, GNS.normingRep_isometry A, GNS.normingRep_injective A, + GNS.normingRep_isClosed_range A⟩ diff --git a/QuantumSystem/Algebra/CStarAlgebra/PureState.lean b/QuantumSystem/Algebra/CStarAlgebra/PureState.lean index cbbd410..84eca5a 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/PureState.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/PureState.lean @@ -131,13 +131,16 @@ lemma isPositive_of_norm_eq_one_map_one /-- For any nonzero positive element `b`, there exists a state on the unitization -whose value on `b` is a strictly positive real number (viewed in `ℂ`). - -We state this by exhibiting `r : ℝ` with `0 < r` and `ψ (Unitization.inr b) = (r : ℂ)`. -This avoids using an order on `ℂ` (which does not exist in Lean). -/ -private lemma exists_unitization_state_pos_re (b : A) (hb : 0 ≤ b) (hb_ne : b ≠ 0) : +whose value on `b` is exactly `‖b‖`, viewed in `ℂ`. + +The value is the norm rather than merely a positive real: the character supplied by Gelfand +duality is evaluated at the spectral radius, and `‖b‖` lies in the spectrum because `b` is +positive. Norming — not just detecting — is what the separable refinement of the +Gelfand-Naimark theorem needs, so the value is carried in the statement instead of being +existentially discarded. Positivity of the value follows from `hb_ne`, since `0 < ‖b‖`. -/ +private lemma exists_unitization_state_norm (b : A) (hb : 0 ≤ b) (hb_ne : b ≠ 0) : ∃ ψ : Unitization ℂ A →L[ℂ] ℂ, ‖ψ‖ = 1 ∧ ψ 1 = 1 ∧ - ∃ r : ℝ, 0 < r ∧ ψ (Unitization.inr b) = (r : ℂ) := by + ψ (Unitization.inr b) = (‖b‖ : ℂ) := by let b' : Unitization ℂ A := Unitization.inr b have hb' : 0 ≤ b' := Unitization.inr_nonneg_iff.mpr hb have hb'_ne : b' ≠ 0 := Unitization.inr_injective.ne hb_ne @@ -176,20 +179,25 @@ private lemma exists_unitization_state_pos_re (b : A) (hb : 0 ≤ b) (hb_ne : b rw [WeakDual.toStrongDual_apply] change φ 1 = 1 rw [map_one φ] - · refine ⟨‖b'‖, norm_pos_iff.mpr hb'_ne, ?_⟩ - have hψb' : ψ b' = (‖b'‖ : ℂ) := by + · have hψb' : ψ b' = (‖b'‖ : ℂ) := by rw [hψ_ext ⟨b', StarAlgebra.elemental.self_mem ℂ b'⟩] change (WeakDual.toStrongDual φ.val) ⟨b', _⟩ = (‖b'‖ : ℂ) rw [WeakDual.toStrongDual_apply] simpa using hφ + have hnorm : ‖b'‖ = ‖b‖ := Unitization.norm_inr b + rw [← hnorm] simpa [b'] using hψb' -private lemma exists_quasiState_pos_re (b : A) (hb : 0 ≤ b) (hb_ne : b ≠ 0) : - ∃ φ ∈ QuasiStateSpace A, ∃ r : ℝ, 0 < r ∧ φ b = (r : ℂ) := by +/-- For any nonzero positive element `b`, some quasi-state takes the value `‖b‖` at `b`. + +This is `exists_unitization_state_norm` pulled back along the isometric embedding of `A` +into its unitization. -/ +private lemma exists_quasiState_norm (b : A) (hb : 0 ≤ b) (hb_ne : b ≠ 0) : + ∃ φ ∈ QuasiStateSpace A, φ b = (‖b‖ : ℂ) := by haveI : Nontrivial A := nontrivial_of_ne b 0 hb_ne - obtain ⟨ψ, hψ_norm_eq, hψ_one, r, hrpos, hψb_eq⟩ := - exists_unitization_state_pos_re b hb hb_ne + obtain ⟨ψ, hψ_norm_eq, hψ_one, hψb_eq⟩ := + exists_unitization_state_norm b hb hb_ne have hψ_pos : IsPositive (Unitization ℂ A) ψ := isPositive_of_norm_eq_one_map_one ψ hψ_norm_eq hψ_one let inrLM : A →ₗ[ℂ] Unitization ℂ A := @@ -221,8 +229,7 @@ private lemma exists_quasiState_pos_re (b : A) (hb : 0 ≤ b) (hb_ne : b ≠ 0) · refine ⟨hφ_pos, ?_⟩ simp only [Set.mem_preimage, Metric.mem_closedBall, dist_zero_right] exact hφ_norm - · refine ⟨r, hrpos, ?_⟩ - simpa [φ, inrCLM, inrIso, LinearIsometry.coe_toContinuousLinearMap, + · simpa [φ, inrCLM, inrIso, LinearIsometry.coe_toContinuousLinearMap, LinearIsometry.coe_mk, inrLM, LinearMap.coe_mk, AddHom.coe_mk] using hψb_eq @@ -372,14 +379,19 @@ noncomputable def toState {φ : WeakDual ℂ A} (h : IsPureState φ) : State ℂ simp [h_opNorm_eq] -/-- For any non-zero element `a`, there exists a pure state `φ` such that -`φ (star a * a)` is a strictly positive real number (viewed in `ℂ`). +/-- For any non-zero element `a`, there exists a pure state `φ` **norming** `a`: +`φ (star a * a) = ‖a‖ ^ 2`, viewed in `ℂ`. -Note: `ℂ` itself is not ordered in Lean, so the correct way to express -“`φ(star a * a) > 0`” is to exhibit a real `r > 0` with -`φ (star a * a) = (r : ℂ)`. -/ -lemma exists_pos_re_of_ne_zero (a : A) (ha : a ≠ 0) : - ∃ φ : WeakDual ℂ A, IsPureState φ ∧ ∃ r : ℝ, 0 < r ∧ φ (star a * a) = (r : ℂ) := by +This is the quantitative form of the existence of pure states. It says that the pure +states do not merely detect `a` but recover its norm, which is what lets a *countable* +family of pure states — one for each member of a dense sequence — separate the points of a +separable C\*-algebra. For the weaker detection statement see +`exists_pos_re_of_ne_zero`, which is a corollary. + +Note: `ℂ` is not ordered in Lean, so the value is stated as an equality with the real +number `‖a‖ ^ 2` coerced into `ℂ`. -/ +lemma exists_norm_sq_of_ne_zero (a : A) (ha : a ≠ 0) : + ∃ φ : WeakDual ℂ A, IsPureState φ ∧ φ (star a * a) = ((‖a‖ ^ 2 : ℝ) : ℂ) := by let b := star a * a have hb_ne_zero : b ≠ 0 := by rw [ne_eq, CStarRing.star_mul_self_eq_zero_iff] @@ -388,7 +400,10 @@ lemma exists_pos_re_of_ne_zero (a : A) (ha : a ≠ 0) : apply StarOrderedRing.nonneg_iff.mpr apply AddSubmonoid.subset_closure use a - obtain ⟨ω, hω_mem, r, hrpos, hω_eq⟩ := exists_quasiState_pos_re b hb_pos hb_ne_zero + have hb_norm : ‖b‖ = ‖a‖ ^ 2 := by + simpa [b, sq] using CStarRing.norm_star_mul_self (x := a) + have hb_norm_pos : (0 : ℝ) < ‖b‖ := norm_pos_iff.mpr hb_ne_zero + obtain ⟨ω, hω_mem, hω_eq⟩ := exists_quasiState_norm b hb_pos hb_ne_zero let l : WeakDual ℂ A →L[ℝ] ℝ := { toFun := fun φ => (φ b).re map_add' := fun φ ψ => by @@ -409,15 +424,28 @@ lemma exists_pos_re_of_ne_zero (a : A) (ha : a ≠ 0) : let f : WeakDual ℂ A → ℝ := l let M := sSup (f '' QuasiStateSpace A) have hf : ContinuousOn f (QuasiStateSpace A) := Continuous.continuousOn l.continuous |>.mono (Set.subset_univ _) - have h_M_pos : M > 0 := by - have hω_re : (ω b).re = r := by - have := congrArg Complex.re hω_eq - simpa using this - apply lt_of_lt_of_le hrpos + have hω_re : (ω b).re = ‖b‖ := by + have := congrArg Complex.re hω_eq + simpa using this + -- `M` is bounded below by `‖b‖`, because `ω` attains it. + have h_M_ge : ‖b‖ ≤ M := by rw [← hω_re] apply le_csSup · exact ((QuasiStateSpace.compact A).image_of_continuousOn hf).bddAbove · exact Set.mem_image_of_mem f hω_mem + -- and above by `‖b‖`, because every quasi-state has norm at most one. + have h_M_le : M ≤ ‖b‖ := by + apply csSup_le + · exact ⟨f ω, Set.mem_image_of_mem f hω_mem⟩ + rintro x ⟨φ, hφ_mem, rfl⟩ + have hφ_norm : ‖WeakDual.toStrongDual φ‖ ≤ 1 := by + simpa [QuasiStateSpace] using hφ_mem.2 + calc f φ ≤ ‖φ b‖ := Complex.re_le_norm _ + _ ≤ ‖WeakDual.toStrongDual φ‖ * ‖b‖ := (WeakDual.toStrongDual φ).le_opNorm b + _ ≤ 1 * ‖b‖ := by gcongr + _ = ‖b‖ := one_mul _ + have h_M_eq : M = ‖b‖ := le_antisymm h_M_le h_M_ge + have h_M_pos : M > 0 := by rw [h_M_eq]; exact hb_norm_pos -- Find a maximizer of f on the QuasiStateSpace obtain ⟨φ, hφ_mem, hφ_max⟩ := IsCompact.exists_isMaxOn (QuasiStateSpace.compact A) ⟨ω, hω_mem⟩ hf have hφ_val : f φ = M := by @@ -486,31 +514,33 @@ lemma exists_pos_re_of_ne_zero (a : A) (ha : a ≠ 0) : · intro r ⟨z, hz, hr⟩ rw [← hr] exact hψ_mem_F.2 z hz - have hψ_re_pos : (ψ b).re > 0 := by - -- `l ψ` is definitionally `(ψ b).re`. - have : l ψ > 0 := by - rw [hψ_l_eq_M] - exact h_M_pos - -- Avoid `simp at` (flagged by linter.flexible) - have : (ψ b).re > 0 := by - -- unfold the linear functional `l` on this specific argument - have h' := this - dsimp [l, ContinuousLinearMap.comp_apply, Complex.reCLM] at h' - exact h' - exact this - -- Then use positivity (membership in `QuasiStateSpace`) to see the value is real. + -- `l ψ` is definitionally `(ψ b).re`, and the maximum is `‖b‖`. + have hψ_re_eq : (ψ b).re = ‖b‖ := by + have h' : l ψ = ‖b‖ := by rw [hψ_l_eq_M, h_M_eq] + dsimp [l, ContinuousLinearMap.comp_apply, Complex.reCLM] at h' + exact h' + -- Membership in `QuasiStateSpace` makes the value real, so its real part determines it. have hψ_mem_S : ψ ∈ QuasiStateSpace A := hψ_mem_F.1 obtain ⟨r₀, hr₀⟩ := hψ_mem_S.1 a - -- `hr₀` is exactly the real-valuedness statement for `ψ (star a * a)`. - have hr₀_re : (ψ b).re = (r₀ : ℝ) := by - have h : ψ b = (r₀ : ℂ) := by - simpa [b] using hr₀ - have := congrArg Complex.re h - simpa using this - have hrpos : (0 : ℝ) < (r₀ : ℝ) := by - simpa [hr₀_re] using hψ_re_pos - refine ⟨(r₀ : ℝ), hrpos, ?_⟩ - simpa [b] using hr₀ + have hr₀' : ψ b = ((r₀ : ℝ) : ℂ) := by simpa [b] using hr₀ + change ψ b = ((‖a‖ ^ 2 : ℝ) : ℂ) + rw [← hb_norm, ← hψ_re_eq, hr₀'] + simp + + +/-- For any non-zero element `a`, there exists a pure state `φ` such that +`φ (star a * a)` is a strictly positive real number (viewed in `ℂ`). + +Note: `ℂ` itself is not ordered in Lean, so the correct way to express +“`φ(star a * a) > 0`” is to exhibit a real `r > 0` with +`φ (star a * a) = (r : ℂ)`. + +This is the detection form of `exists_norm_sq_of_ne_zero`; the witness it discards is the +norm itself. -/ +lemma exists_pos_re_of_ne_zero (a : A) (ha : a ≠ 0) : + ∃ φ : WeakDual ℂ A, IsPureState φ ∧ ∃ r : ℝ, 0 < r ∧ φ (star a * a) = (r : ℂ) := by + obtain ⟨φ, hφ_pure, hφ_eq⟩ := exists_norm_sq_of_ne_zero a ha + exact ⟨φ, hφ_pure, ‖a‖ ^ 2, pow_pos (norm_pos_iff.mpr ha) 2, hφ_eq⟩ end IsPureState diff --git a/QuantumSystem/ForMathlib/Analysis/Normed/Lp/Separable.lean b/QuantumSystem/ForMathlib/Analysis/Normed/Lp/Separable.lean new file mode 100644 index 0000000..647e1ed --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/Normed/Lp/Separable.lean @@ -0,0 +1,86 @@ +module + +public import Mathlib.Analysis.Normed.Lp.lpSpace +public import Mathlib.Topology.Algebra.Module.Basic + +/-! +# Separability of `lp` over a countable index + +An `lp` space over a **countable** index type, whose summands are separable, is separable — +provided `p ≠ ⊤`. The exponent restriction is essential: `lp G ⊤` is the space of bounded +families, which is not separable over an infinite index even when every summand is `ℂ`. + +The proof is the standard one: the singles span a dense subspace, because +`lp.hasSum_single` expands every element as the sum of its coordinates, and a countable +union of continuous images of separable spaces spans a separable submodule. + +Mathlib has `PiLp.secondCountableTopology` for the finite-product form and +`WithLp.secondCountableTopology` for the binary one, but nothing for the `lp` subtype; this +file supplies it. + +## Main results + +* `lp.separableSpace_of_ne_top` — the statement above, for an arbitrary exponent `p ≠ ⊤`. + The scalar field is an explicit argument, since it appears only in the proof. +* `lp.instSeparableSpaceOfCountable` — the same at `p = 2` over `ℂ`, as an instance; this + is the case the ℓ²-direct sum of complex Hilbert spaces uses. +-/ + +@[expose] public section + +open TopologicalSpace + +open scoped ENNReal + +namespace lp + +variable {ι : Type*} {G : ι → Type*} [∀ i, NormedAddCommGroup (G i)] + +/-- The single-coordinate embedding `G i → lp G p` is continuous. + +It is in fact isometric — `lp.norm_single` — but continuity is all that is needed +downstream. The scalar field is explicit because it occurs only in the proof, which routes +through the linear map `lp.lsingle` to get additivity. -/ +lemma continuous_single (𝕜 : Type*) [NontriviallyNormedField 𝕜] [∀ i, NormedSpace 𝕜 (G i)] + [DecidableEq ι] {p : ℝ≥0∞} [Fact (1 ≤ p)] (i : ι) : + Continuous (fun x : G i => lp.single p i x) := by + have hp0 : (0 : ℝ≥0∞) < p := lt_of_lt_of_le zero_lt_one Fact.out + have h : ∀ x : G i, ‖lp.lsingle (𝕜 := 𝕜) p i x‖ = ‖x‖ := fun x => by + simpa using lp.norm_single hp0 i x + simpa using (AddMonoidHomClass.isometry_of_norm (lp.lsingle (𝕜 := 𝕜) p i) h).continuous + +/-- An `lp` space over a countable index with separable summands is separable, for any +exponent `p ≠ ⊤`. + +The hypothesis `p ≠ ⊤` cannot be dropped: `lp (fun _ : ℕ => ℂ) ⊤` is `ℓ^∞`, which is not +separable. The scalar field `𝕜` is explicit because it does not occur in the conclusion. -/ +theorem separableSpace_of_ne_top (𝕜 : Type*) [NontriviallyNormedField 𝕜] [SeparableSpace 𝕜] + [∀ i, NormedSpace 𝕜 (G i)] [Countable ι] [∀ i, SeparableSpace (G i)] + {p : ℝ≥0∞} [Fact (1 ≤ p)] (hp : p ≠ ⊤) : + SeparableSpace (lp G p) := by + classical + set S : Set (lp G p) := ⋃ i, Set.range (fun x : G i => lp.single p i x) with hSdef + have hS : IsSeparable S := + IsSeparable.iUnion fun i => isSeparable_range (continuous_single 𝕜 i) + have hspan : IsSeparable ((Submodule.span 𝕜 S : Submodule 𝕜 (lp G p)) : Set (lp G p)) := + hS.span + -- The singles span a dense subspace: every element is the sum of its coordinates. + have hdense : Dense ((Submodule.span 𝕜 S : Submodule 𝕜 (lp G p)) : Set (lp G p)) := by + intro f + refine mem_closure_of_tendsto (lp.hasSum_single hp f) ?_ + filter_upwards with s + refine Submodule.sum_mem _ fun i _ => Submodule.subset_span ?_ + exact Set.mem_iUnion.mpr ⟨i, Set.mem_range_self _⟩ + rw [← isSeparable_univ_iff, ← hdense.closure_eq] + exact hspan.closure + +/-- The `p = 2`, `𝕜 = ℂ` case of `lp.separableSpace_of_ne_top`, as an instance. + +Both the exponent and the scalar field are fixed here rather than left as variables: an +instance can carry neither the hypothesis `p ≠ ⊤` nor a scalar field absent from its +conclusion. -/ +instance instSeparableSpaceOfCountable [∀ i, NormedSpace ℂ (G i)] [Countable ι] + [∀ i, SeparableSpace (G i)] : SeparableSpace (lp G 2) := + separableSpace_of_ne_top ℂ (by simp) + +end lp From 89f28ceb4f827bc5670f660f962bf65fc01ac93e Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 14:12:22 +0000 Subject: [PATCH 104/113] docs: add extraction note for the separable faithful representation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /math-extract note for the object formalized above — a faithful representation of a separable C*-algebra on a separable Hilbert space — drawn from BF26, LAN98, SHI12 and VER25. Records that the corpus never proves separability of the GNS Hilbert space (R7) and that BF26 states SepRepThm without a proof, and rejects both the all-states and the pure-state-classes direct sums as routes to it. Back-links the note to CStarRep.exists_isometric_separable and indexes it in docs/math/README.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-extract/sources.md | 5 + docs/math/README.md | 1 + .../math/separable-faithful-representation.md | 538 ++++++++++++++++++ 3 files changed, 544 insertions(+) create mode 100644 docs/math/separable-faithful-representation.md diff --git a/.claude/skills/math-extract/sources.md b/.claude/skills/math-extract/sources.md index ff0cb3f..d88ac41 100644 --- a/.claude/skills/math-extract/sources.md +++ b/.claude/skills/math-extract/sources.md @@ -75,3 +75,8 @@ different object is in the wrong file. | NAA13 | P. Naaijkens, *Quantum spin systems on infinite lattices*, arXiv 1311.2717 | retrieved | `references/arxiv-1311.2717/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; multi-file (`aqft.tex`, `qlattice.tex`, `opalg.tex`, …), macros in `qlattice.tex`. The only corpus source stating `𝒪 = 𝒪″` for double cones, and it states it without proof. Its `𝒫_f(Γ)` **contains `∅`**, with `𝒜(∅) = ℂI` fixed explicitly — so any claim that the lattice index set fails an existence-of-a-⊥-partner condition is false for *this* index set | | BGL93 | R. Brunetti, D. Guido, R. Longo, *Modular structure and duality in conformal quantum field theory*, arXiv funct-an/9302008 | retrieved | `references/arxiv-funct-an-9302008/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `main.tex`. locator Cor. 2.7: discharged by `\proof Immediate, see [\ref(Long1)].` and conditional on Remark 2.6's spectral hypothesis — do not cite it as an unconditional type III₁ result. locator Thm 3.3: its proof cites a **Lemma 3.4 that does not exist**; Lemma 3.2 is meant. Its "distal split property" (§3 assumption (b)) is an **existential over one pair of regions**, not a metric strengthening of the separation relation. Its non-split net `ℬ(𝒪) = 𝒜(π⁻¹𝒪)` is attributed to a **private remark** of Buchholz, so no locator can ever exist for the attribution | | BFV01 | R. Brunetti, K. Fredenhagen, R. Verch, *The generally covariant locality principle*, arXiv math-ph/0112041 | retrieved | `references/arxiv-math-ph-0112041/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim. **The distributed source contains two complete `\begin{document}…\end{document}` bodies** — `source.txt` lines 118–2851 and 2957–4225 (`source.flat.txt` offsets 3687 and 144453). Only the first is the compiled paper; the second is a shorter earlier draft that even defines `\frakA` differently. **Take every locator from the first body**, and expect `grep -F` to return 2 for shared passages — that is not a duplicate-quote defect. Its `𝒦(M,ḡ)` is defined by two conditions only (relatively compact, causally convex), and openness/connectedness/non-emptiness are forced only by the *next* sentence's demand that each region be an object of `𝔐`; the two readings give different index sets. `cf.\ condition $(ii)$` points at orientation-preservation where causal convexity is condition (i), in **both** bodies, so authorial | +| BF26 | B. Blackadar, I. Farah, *Separable C\*-algebras Without the Countable Axiom of Choice*, arXiv:2602.15812 | retrieved | `references/arxiv-2602.15812/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; multi-file, macros in `measpreambleu.tex` (`\cstar`, `\cB`, `\cH`) and `25-Cstar-choice.tex` (`\sfS`). **locator `SepRepThm` is adjudicated: the theorem carries no proof.** `source.txt:589–592` shows `\begin{Theorem}\label{SepRepThm}` … `\end{Theorem}` followed directly by a commented-out paragraph — no `\begin{Proof}` environment anywhere after it. Its only justification is the preceding sentence, which establishes faithfulness and never mentions separability of the Hilbert space. The paper is ZF throughout, so its "separable Hilbert space" must be read topologically, not as "has a countable orthonormal basis" — it says itself that the two come apart without countable choice. Two typos: `L.states`' proof opens `$\varphi(x^*x)=\|x\|$` where ‖x‖² is meant (corrected three lines later in the same proof), and `Corollary~8.4.3` is cited to two different works (`blackadar2023hilbert` and `farah2023choice`). Cites three Blackadar works (*Operator Algebras*, *Real Analysis*, *Hilbert spaces*) that were not obtained; anything through those citations is tier (c) | 2026-08-16 | +| LAN98 | N. P. Landsman, *Lecture Notes on C\*-algebras, Hilbert C\*-modules and Quantum Mechanics*, arXiv math-ph/9807030 | retrieved | `references/arxiv-math-ph-9807030/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; heavy custom macros (`\ca`, `\Hs`, `\rep`, `\om`, `\A`, and a `\renewcommand{\H}`). Inner product conjugate-linear in the **first** argument. Two typos to reproduce in quotes: `non-separable in the nom-topology` (for `norm-`), and Lemma `lots` writes `$\om(A)=a$` where the quantified state is `$\om_a$`. States Krein–Milman **without proof**. Its faithful-state GNS proposition is about the compact operators specifically, not a general C\*-algebra — do not cite it as the general statement | 2026-08-16 | +| SHI12 | V. Shirbisheh, *Lectures on C\*-algebras*, arXiv:1211.3404 | retrieved | `references/arxiv-1211.3404/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; macros by `\def` not `\newcommand` (`\cs`, `\ss` at `raw/main.tex:65–66`). **Contains no GNS construction and no Gelfand–Naimark representation theorem** — it says so itself: `we presented GNS construction fully in the course, but it is not given in these notes.` Defines a separable Hilbert space **basis-theoretically** and sets the equivalence with topological separability as an exercise. Two defects: `cor:Hilbertcardinality`'s proof assumes only a surjection where a bijection is needed, and its corollary that every separable Hilbert space is unitarily ℓ²(ℕ) is false for finite-dimensional H under its own definition. Its equinumerosity proof makes an unflagged simultaneous choice | 2026-08-16 | +| VER25 | R. Verch, *Lecture Notes on Operator Algebras and Quantum Field Theory*, arXiv:2507.00900 | retrieved | `references/arxiv-2507.00900/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim. Subsection 1.2 states the Haag–Kastler covariance axiom `α_L(𝒜(O)) = 𝒜(L(O))` (see the `LocalNet.Covariance` row in this repository's math-review ledger). **`separable`, `Gelfand`, `Naimark`, `Neumark` all occur 0 times** — but do not conclude it is irrelevant to C\*-algebra extractions: it is the only source in the 2026-08-16 corpus that *defines* faithful state and faithful representation, and the only one stating "the GNS representation of a faithful state is faithful" (asserted, no proof, no citation). Unital throughout; inner product conjugate-linear in the first argument | 2026-08-16 | +| MUR90 / PED79 / DIX77 / TAK79 / BLA06 | Murphy, *C\*-algebras and Operator Theory* (1990); Pedersen, *C\*-algebras and their Automorphism Groups* (1979); Dixmier, *C\*-algebras* (1977); Takesaki, *Theory of Operator Algebras I* (1979); Blackadar, *Operator Algebras* (2006) | not retrieved | — | — | 2026-08-16 | The standard C\*-algebra textbooks. Only a web search was attempted; no legitimate free copy was found for any of them, and no pirated copy was pursued. **The widely-repeated attribution of the separable refinement of Gelfand–Naimark to "Murphy Thm 3.4.1" is unverified** — nobody in this repository has opened the book, so no note may carry that locator. Expires 2027-02-16 | 2026-08-16 | diff --git a/docs/math/README.md b/docs/math/README.md index f75affd..1c6cb00 100644 --- a/docs/math/README.md +++ b/docs/math/README.md @@ -29,6 +29,7 @@ the product. |---|---|---| | Causal index set of a Haag–Kastler net | [causal-index-set.md](causal-index-set.md) | `CausalIndexSet` | | Split inclusion of von Neumann algebras | [split-inclusion.md](split-inclusion.md) | `VonNeumannAlgebra.IsSplitInclusion` | +| Faithful representation of a separable C\*-algebra on a separable Hilbert space | [separable-faithful-representation.md](separable-faithful-representation.md) | `CStarRep.exists_isometric_separable` | <!-- One row per note. "Implemented as" is a fact recorded after the object is formalized — the fully-qualified declaration that ended up carrying it, or diff --git a/docs/math/separable-faithful-representation.md b/docs/math/separable-faithful-representation.md new file mode 100644 index 0000000..e118641 --- /dev/null +++ b/docs/math/separable-faithful-representation.md @@ -0,0 +1,538 @@ +--- +object: Faithful representation of a separable C*-algebra on a separable Hilbert space +slug: separable-faithful-representation +status: draft +worst-tier: c +mathlib-rev: 5450b53e5ddc75d46418fabb605edbf36bd0beb6 +implemented-as: CStarRep.exists_isometric_separable +revisions: + - 2026-08-16 · 2e21b4b · initial extraction · sources: BF26, LAN98, SHI12, VER25 +--- + +<!-- +Macros the quotes below need, copied from each source's own preamble: + \cB, \cH BF26, references/arxiv-2602.15812/raw/measpreambleu.tex:63, :79 + \cstar BF26, references/arxiv-2602.15812/raw/measpreambleu.tex:292 + \sfS BF26, references/arxiv-2602.15812/raw/25-Cstar-choice.tex:76 + \ca LAN98, references/arxiv-math-ph-9807030/raw/*.tex:53 + \rep LAN98, :56 + \Hs LAN98, :58 + \om LAN98, :233 + \A LAN98, :238 + \H LAN98, :269 (the source itself uses \renewcommand — KaTeX defines \H) + \cs, \ss SHI12, references/arxiv-1211.3404/raw/main.tex:65, :66 (\def, not \newcommand) +--> + +$$ +\newcommand{\cB}{{\mathcal B}} +\newcommand{\cH}{{\mathcal H}} +\newcommand{\cstar}{$\mathrm{C}^*$} +\newcommand{\sfS}{\mathsf S} +\newcommand{\ca}{$C^*$-algebra} +\newcommand{\rep}{representation} +\newcommand{\Hs}{Hilbert space} +\newcommand{\om}{\omega} +\newcommand{\A}{{\frak A}} +\renewcommand{\H}{{\cal H}} +\def\cs{{$C^{\ast}$}} +\def\ss{{$\ast$}} +$$ + +# Faithful representation of a separable C\*-algebra on a separable Hilbert space + +## What this object is for + +The Gelfand–Naimark theorem places every C\*-algebra inside the bounded operators +on *some* Hilbert space, but the Hilbert space its standard proof produces is +indexed by the whole state space and is enormous. This object is the refinement +that bounds the size of the Hilbert space by the size of the algebra: a +countable dense subset of the algebra buys a countable dense subset of the +Hilbert space. The generality that matters is that nothing beyond separability +is assumed — not unitality, not commutativity, not nuclearity — and that the +bound is one-directional: it is a sufficient condition on the algebra, never a +characterisation. + +## Definition + +### Variants as the sources write them + +| (D#) | Source | What is asserted | "faithful" reads as | "separable H" reads as | unitality | ambient theory | Tier | +|---|---|---|---|---|---|---|---| +| (D1) | [BF26] `SepRepThm` | the object | undefined in the source | undefined in the source | none assumed | ZF | a | +| (D2) | [BF26] `RepCAlg` | *representable*: no separability of H at all | isomorphism onto a **closed** \*-algebra of operators | — (H unrestricted) | none assumed | ZF | a | +| (D3) | [LAN98] `injmor` context | ingredient definition | **injective**; isometry derived | — | — | ZFC | a | +| (D4) | [VER25] Operator Algebra Basics | ingredient definition | **injective** (π(A)=0 ⟹ A=0); faithful *state*: ω(A\*A)=0 ⟹ A=0 | — | unital throughout | ZFC | a | +| (D5) | [SHI12] Approximate units | ingredient: separable **algebra** | — | — | — | ZFC | a | +| (D6) | [SHI12] Hilbert spaces | ingredient: separable **Hilbert space** | — | **countable orthonormal basis** | — | ZFC | a | +| (D7) | [SHI12], [LAN98] `GNSconstruction` | ingredient: H_φ as an explicit completion | — | — | LAN98 unital only | ZFC | a | + +**(D1) [BF26] Theorem `SepRepThm`** — tier (a) + +> `Every separable C*-algebra has a faithful representation as a concrete C*-algebra of operators on a separable Hilbert space.` + +BF26 nowhere defines "faithful representation": the word occurs six times in the +whole paper and never in a definition environment. The meaning has to be +imported, which is what (D3) and (D4) supply. + +**(D2) [BF26] Definition `RepCAlg`** — tier (a) + +> `A \cstar-algebra $A$ is {\em representable} if it is isomorphic to a closed *-algebra of bounded operators on a Hilbert space.` + +`differs from (D1) by:` (D2) demands an isomorphism onto a norm-**closed** +\*-subalgebra and says nothing about the Hilbert space, where (D1) demands a +faithful map and a **separable** Hilbert space. +`sources claim equivalence:` not addressed — BF26 uses both in one subsection +without remarking on the difference. + +**(D3) [LAN98] Lemma `injmor` and its use** — tier (a) + +> `An injective morphism between \ca s is isometric. In particular, its range is closed.` + +used in the sentence "‖π(A)‖ = ‖A‖ + +> `when $\pi$ is faithful by Lemma \ref{injmor}` + +`differs from (D1) by:` fixes faithful = injective and derives the other two +readings. +`sources claim equivalence:` yes — this lemma, together with [SHI12] +`cor:firstiso`, *is* the equivalence; see (R5). + +**(D4) [VER25] §Operator Algebra Basics** — tier (a) + +> `A state on a unital $*$-algebra $\mathbfcal{A}$ is called \textbf{faithful} if, for any $\Att \in \mathbfcal{A}$,` + +followed by the displayed ω(A\*A) = 0 ⟹ A = 0; faithfulness of a representation +is defined in the same passage by π(A) = 0 ⟹ A = 0. + +`differs from (D3) by:` nothing for representations; (D4) additionally defines +the *faithful state*, which (D3) does not and which (D1)'s justification +consumes. +`sources claim equivalence:` not addressed. + +**(D5) [SHI12] §Approximate units** — tier (a) + +> `A \cs-algebra $A$ is called {\bf separable} if it possesses a countable and dense subset.` + +BF26 uses the same notion without a definition environment, speaking throughout +of a countable dense subset and, in `L.states`, of "a countable dense sequence". + +**(D6) [SHI12] §Hilbert spaces** — tier (a) + +> `A Hilbert space is called {\bf separable} if it has a countable orthonormal basis.` + +immediately followed by + +> `\begin{exercise} Let $H$ be a Hilbert space. Show that $H$ is a separable Hilbert space if and only if $H$ is a separable topological space. \end{exercise}` + +`differs from (D5) by:` (D6) is basis-theoretic where (D5) is topological, and +the source relegates their equivalence to an exercise rather than proving it. +`sources claim equivalence:` yes, as an exercise — but see (X3): the two are +**provably inequivalent** in ZF, which is the ambient theory of the source that +states (D1). + +**(D7) [LAN98] Construction `GNSconstruction`, [SHI12] §Hilbert spaces** — tier (a) + +> `The \Hs\ $\H_{\om}$ is the closure of $\A/{\cal N}_{\om}$ in this inner product.` + +SHI12 builds the same object as `The completion of $A/N_\ff$ with respect to the norm defined by $\inner_\ff$`, and VER25 instead postulates the triple abstractly +with a cyclic vector. Only the completion form makes separability of H_ω +visible, which is why the corpus's failure to prove (R7) is a failure to compose +two of its own definitions. + +### Adopted general form + +Let `A` be a C\*-algebra over ℂ — an involutive Banach algebra with +‖x\*x‖ = ‖x‖² — **not** assumed unital and **not** assumed commutative, and +suppose `A` is separable as a metric space, that is, `A` has a countable dense +subset in the norm topology (D5). Then there exist a complex Hilbert space `H` +and a map `π` such that + +1. `H` has a countable dense subset in the norm topology; +2. `π : A → B(H)` is a \*-homomorphism — linear, multiplicative, and + star-preserving — into the bounded linear operators on `H`; +3. `π` is injective. + +Nothing further is assumed of `A`, and nothing further is asserted of `π`: in +particular the adopted form does **not** claim that `π` is nondegenerate, does +**not** claim `π(1) = 1` when `A` is unital, and does **not** claim that `H` may +be taken to be ℓ²(ℕ). The hypotheses carried are (A1) alone. Three consequences +follow from 1–3 with no extra input and are therefore not extra content (R5): +`π` is isometric, its range is norm-closed, and `π` corestricts to a +\*-isomorphism of `A` onto a C\*-subalgebra of `B(H)` — which is what makes the +phrase "concrete C\*-algebra of operators" in (D1) legitimate. + +*Justification.* This is (D1), the only formulation in the corpus that states +the object, with its two undefined phrases fixed. "Faithful" is read as +injective, following (D3) and (D4), the only sources in the corpus that define +the word; (X5) and (X6) record that injective, isometric, and "isomorphic onto a +norm-closed \*-subalgebra" coincide for C\*-algebras, so this reading costs no +generality and (D2) is not a competing variant. "Separable Hilbert space" is +read topologically rather than basis-theoretically, following (X3)'s +**(X5) conditional equivalence**: the two readings agree under the axiom of +countable choice and come apart without it, and BF26 — the source that states +(D1) — works in ZF and says so explicitly, so the topological reading is the +only one available to it. Under ZFC, the ambient theory of every other source in +the corpus, the choice is inert. + +## Notation and conventions + +| (C#) | Axis | This note | Per source | Translation | +|---|---|---|---|---| +| (C1) | what "faithful" means | injective | [LAN98] injective, isometry derived; [VER25] injective; [BF26] undefined, glossed parenthetically as isometric; [SHI12] no notion of faithful representation | the three readings coincide, by (R5) | +| (C2) | unitality | not assumed | every source does its state/GNS work in the unital case and defers the rest to unitisation; [BF26] `RepThm` says "separable (unital)" with the parenthesis, `SepRepThm` says nothing; none of the three writes the unitisation argument | (A2) | +| (C3) | what "separable Hilbert space" means | countable dense subset | [SHI12] countable orthonormal basis, equivalence set as an exercise; [BF26] topological, forced by its ZF setting | equivalent under countable choice only — (X3) | +| (C4) | ℓ²(ℕ) as the canonical space | not used in the statement | [SHI12] is careful — `When $H$ is an infinite dimensional separable Hilbert space, or equivalently $H\simeq \ell^2$`; the ℓ²(ℕ) phrasing appears in BF26 only in commented-out source | a formulation naming ℓ²(ℕ) silently excludes the finite-dimensional case unless ℓ² is read as allowing finite dimension | +| (C5) | conjugate-linearity of the inner product | first argument | [LAN98] `(A,B)_0:=\om(A^* B)`, first argument; [VER25] first argument; [SHI12] not determined | — | +| (C6) | nondegeneracy | not asserted | [LAN98] defines it and uses it elsewhere; 0 occurrences in [BF26] and [VER25]; no source attaches it to this object | (A9) | +| (C7) | ambient set theory | ZFC assumed, ZF tracked | [BF26] ZF throughout; [LAN98] [SHI12] [VER25] ZFC | the ZF/ZFC split is what makes (C3) a live axis and (R5) an edge rather than a triviality | + +## Results and dependencies + +### (R1) The object + +Every separable C\*-algebra has a faithful representation as a concrete +C\*-algebra of operators on a separable Hilbert space. + +- Source: [BF26] Theorem `SepRepThm` · tier (a) · **asserted** +- Depends on: (R2), (R6), (R7), (R5) +- Conventions: (C1), (C3), (C7) +- Verbatim: + > `Every separable C*-algebra has a faithful representation as a concrete C*-algebra of operators on a separable Hilbert space.` + +**No `Proof route:` field, because there is no proof.** There is no proof +environment after the theorem in BF26's source; the entire justification is the +single sentence preceding it: + +> `In fact, using \ref{FaithfulStateThm} we can do better, since the GNS representation from a faithful state is faithful:` + +That sentence supplies (R2) and asserts (R6). It says nothing about separability +of the GNS Hilbert space — the adjective that distinguishes this theorem from +the unrefined Gelfand–Naimark theorem (R8) — and nothing about the image being +norm-closed. Of the four things (R1) needs: one is proved in the stating source, +one is asserted twice and proved nowhere in the corpus, one is absent from the +corpus entirely, and one is proved only in ZFC sources while the stating source +works in ZF. + +### (R2) A separable C\*-algebra has a faithful state + +- Source: [BF26] Proposition `FaithfulStateThm` · tier (a) · **proved in source** +- Depends on: (R3), (R4), (A2), [ext: a countable convex combination of states is a state — used in step 3 and stated nowhere in the corpus] +- Conventions: (C2) +- Proof route: + 1. Reduce to the unital case — asserted, not argued, consuming (A2); + 2. `S(A)` is weak\*-separable — consumes (R3); + 3. take a weak\*-dense sequence (φₙ) in `S(A)` and set φ = Σ 2⁻ⁿ φₙ, a state + because a countable convex combination of states is a state; + 4. for positive `a` of norm 1 there is a state ψ with ψ(a) = 1 — consumes (R4); + 5. approximate ψ by some φₙ, giving φₙ(a) > ½, hence φ(a) ≥ 2⁻ⁿφₙ(a) > 0. +- Verbatim: + > `A separable \cstar-algebra has a faithful state.` + +Note which faithfulness is produced: step 5 yields φ(a) > 0 for positive `a`, +the order-theoretic form, where (D4) defines faithfulness of a state by +ω(A\*A) = 0 ⟹ A = 0. These are interchangeable, but BF26 neither says so nor +defines the term. + +### (R3) The state space of a separable unital C\*-algebra is separable, compact and metrizable in the weak\* topology + +- Source: [BF26] Lemma `L.S(A)` · tier (a) · **proved in source** +- Depends on: (R4), [ext: BF26's own separable Hahn–Banach / Banach–Alaoglu package], [ext: BF26's separable Krein–Milman], [ext: Blackadar, *Real Analysis* — the pure state space of a separable unital C\*-algebra is a G_δ subset of the state space] +- Conventions: (C2), (C7) +- Verbatim: + > `Suppose that $A$ is a separable unital \cstar-algebra. Then the state space $\sfS(A)$ with respect to the weak*-topology is a separable compact metrizable space.` + +Only the weak\*-separability clause is consumed by (R2). The Krein–Milman step +inside this proof supports the pure-state clause, which nothing on the route to +(R1) cites — see (A7). + +### (R4) Every separable C\*-algebra has sufficiently many states + +- Source: [BF26] Lemma `L.states` · tier (a) · **proved in source** +- Depends on: (A2), [ext: BF26's own positivity proposition — `x*x` is a positive element], [ext: BF26's separable Hahn–Banach extension], [ext: BF26's continuous functional calculus], [ext: Blackadar, *Operator Algebras* — a linear functional on a unital C\*-algebra is a state iff it has norm 1 and value 1 at the unit] +- Conventions: (C2), (C7) +- Proof route: + 1. reduce to `A` unital — asserted, consuming (A2); + 2. `x*x` is positive; + 3. ‖λ1 + x\*x‖ = λ + ‖x\*x‖ for λ ≥ 0, by functional calculus — consumes the + functional-calculus edge; + 4. on the two-dimensional span of 1 and `x*x`, the functional sending 1 ↦ 1 + and `x*x` ↦ ‖x‖² has norm 1; + 5. extend by Hahn–Banach for separable Banach spaces, choice-free — consumes + the Hahn–Banach edge; + 6. a norm-1 functional taking value 1 at the unit is a state — consumes the + Blackadar edge. +- Verbatim: + > `Every separable \cstar-algebra, and more generally every \cstar-algebra with a well-ordered dense subset, has sufficiently many states.` + +BF26 defines "sufficiently many states" as: for every `x` there is a state φ +with ‖π_φ(x)‖ = ‖x‖. The proof produces φ(x\*x) = ‖x‖²; the one-line bridge +between the two is **not written down in BF26**. + +### (R5) An injective \*-homomorphism of C\*-algebras is isometric, and its range is norm-closed + +- Source: [LAN98] Lemma `injmor`; [SHI12] Corollary `cor:csinjection` together with Corollary `cor:firstiso` · tier (a) · **proved in source** (SHI12), **sketched** as read by this extraction (LAN98) +- Depends on: [LAN98] its ideal theory +- Conventions: (C1), (C7) — both sources are ZFC +- Verbatim: + > `An injective morphism between \ca s is isometric. In particular, its range is closed.` + + > `Every injective \ss-homomorphism between two \cs-algebras is an isometry.` + +This is one result with two locators, kept as one row. It is what makes (C1) +inert and (D2) not a competing variant. It is also the edge that BF26 uses +parenthetically — `a direct sum of GNS representations is faithful (isometric)` — +without citing any lemma, which in a ZF paper is not free; see `## Open questions`. + +### (R6) The GNS representation of a faithful state is faithful + +- Source: [VER25] §Operator Algebra Basics · tier (a) · **asserted** +- Depends on: [VER25]'s GNS theorem, for the existence of the triple +- Conventions: (C2) — stated for unital algebras +- Verbatim: + > `For a unital $C^*$-algebra, if a state $\omega$ is faithful, then $(\pi_\omega,\mathcal{H}_\omega)$ is faithful.` + +This is exactly the step (R1)'s one-sentence justification consumes. The corpus +states it twice — here and inside BF26's sentence — and proves it zero times. +[LAN98] has the only *proved* proposition in this direction, and it is about the +compact operators specifically, not a general C\*-algebra. + +### (R7) The GNS Hilbert space of a state on a separable C\*-algebra is separable + +**Absent from the corpus.** No source states, proves or cites it. + +- Source: none · tier — · **not in corpus** +- Depends on: (D7) plus the general facts that a continuous image of a separable + space is separable and that the closure of a separable subset is separable +- Conventions: (C3) + +Both ingredients are present, in different sources: [VER25] gives cyclicity of +Ω_ω, and [LAN98]/[SHI12] give H_ω as the closure of a quotient of `A` (D7). +Either yields H_ω as the closure of a continuous image of `A`, hence separable +when `A` is, with no choice used because the dense sequence in H_ω is the +*image* of a fixed dense sequence in `A`. **No source performs the +composition.** This is the entire content of the refinement over (R8), and it is +the one step the literature in this corpus leaves unwritten. + +### (R8) The unrefined Gelfand–Naimark representation theorem + +- Source: [LAN98] Theorem `GNT` · tier (a) · **proved in source**; announced without proof by [SHI12] +- Depends on: [LAN98] `defunivrep`, `gnscor`, `lots`, the C\*-identity, (R5) +- Conventions: (C1) +- Proof route: + 1. take `H` to be the universal representation's space ⊕_{ω∈S(A)} H_ω — + consumes `defunivrep`; + 2. π_u(A) = 0 forces π_ω(A) = 0 for every state — by definition of direct sum; + 3. hence ω(A\*A) = 0 for every state — consumes `gnscor`; + 4. hence ‖A\*A‖ = 0 — consumes `lots`, "there are lots of states"; + 5. hence A = 0 by the C\*-identity; + 6. injective ⟹ isometric — consumes (R5). +- Verbatim: + > `A \ca\ is isomorphic to a subalgebra of $\B(\H)$, for some Hilbert space $\H$.` + +### (R9) The universal Hilbert space is too large, and the pure-state reduction does not fix it + +- Source: [LAN98], the paragraph after the proof of `GNT` · tier (a) · **remark (asserted)**, with a **proved** reduction to pure states +- Depends on: (R8), [LAN98] `lotsp`, [ext: Krein–Milman, which LAN98 states without proof] +- Verbatim: + > `While the universal \rep\ leads to a nice proof of \ref{GNT}, the \Hs\ $\H_{\mbox{\tiny u}}$ is absurdly large; in practical examples a better way of obtaining a faithful \rep\ always exists.` + +This is the corpus's own statement that (R8) does not deliver a separable +Hilbert space. LAN98's remedy is to sum over pure states, and then over one pure +state per unitary-equivalence class — a reduction that for a separable algebra +still leaves an uncountable index set. See (X1) and (X2). + +### (R10) `B(H)` is norm-separable if and only if `H` is finite-dimensional + +- Source: [BF26] Theorem `BHNormSepThm` · tier (a) · **proved in source** (read as a sketch by this extraction) +- Depends on: [BF26] `OrthProjSeqProp`, and its choice-free replacement for the orthonormal-sequence argument +- Verbatim: + > `Let $\cH$ be a Hilbert space. Then $\cB(\cH)$ is norm-separable if and only if $\cH$ is finite-dimensional.` + +No step of (R1) consumes this, so it is not an edge. It is the boundary object: +it shows that "faithful representation on a separable Hilbert space" must not be +confused with "faithful representation into a separable `B(H)`", which would +force finite dimension and trivialise the object. [LAN98] makes the same +observation from the other side: `Another argument against $\BH$ is that it is non-separable in the nom-topology even when $\H$ is separable.` (the typo `nom-` is +in the original). + +### (R11) Every closed subspace of a separable Banach space is separable + +- Source: [BF26] Proposition `ClosedSubspaceProp` · tier (a) · **cited elsewhere** +- Depends on: [ext: Blackadar, *Real Analysis* — every closed subset of a separable metric space is separable] + +Not an edge of (R1). With (R1) it gives that the image π(A) is itself a +separable concrete C\*-algebra. + +### (R12) Two Hilbert spaces are unitarily equivalent iff their orthonormal bases are equinumerous + +- Source: [SHI12] Corollary `cor:Hilbertcardinality` · tier (a) · **proved in source** +- Depends on: [SHI12]'s theorem that any two orthonormal bases are equinumerous +- Conventions: (C3), (C4), (C7) + +This is what would licence replacing "separable Hilbert space" by ℓ²(ℕ) in the +infinite-dimensional case. It is unusable in BF26's ZF setting (C3), and SHI12's +equinumerosity proof makes an unflagged simultaneous choice. + +### (R13) Every separable commutative C\*-algebra is C₀(X) for a locally compact metrizable X + +- Source: [BF26], the separable commutative Gelfand theorem · tier (a) · **proved in source** +- Depends on: (R4), (A7) Krein–Milman, Stone–Weierstrass +- Conventions: (C7) + +Recorded because it gives a second, independent route to (R1) in the commutative +case, and because that route is **strictly more expensive** in ZF than the +general one: it consumes Krein–Milman, which the general route does not (A7). + +## Hypotheses + +| (A#) | Statement | Class | Evidence | Witness | Scope | Tier | Used by | +|---|---|---|---|---|---|---|---| +| (A1) | `A` is norm-separable | antecedent — the hypothesis of the theorem, not a side condition | [BF26] `SepRepThm`; [SHI12] definition | — | standing | a | (R1)–(R4) | +| (A1b) | separability of `A` is **not necessary** for the conclusion | — (a finding: the hypothesis cannot be made an iff) | [BF26] `BHNormSepThm`; [LAN98] | **B(ℓ²)**, non-separable yet faithfully represented on ℓ² by its identity representation; likewise ℓ^∞(ℕ) | — | a | — | +| (A2) | `A` is unital | provable — removable by unitisation | [BF26] `L.states`, `FaithfulStateThm` both open "We may assume `A` is unital", unargued; [LAN98] defers to `extstate` | — (non-unital instance C₀(ℝ) is covered) | local | a | (R2), (R4) | +| (A3) | `A` is σ-unital | provable from (A1) | [SHI12] "Every separable C\*-algebra is σ-unital"; [LAN98] `exau` | — | local | a | — (consumed by no step of the adopted route) | +| (A4) | `A` has sufficiently many states / is representable | provable under (A1); **model-dependent** without it | [BF26] `L.states`, `P.Representable`, `P.ExistenceOfStates` | **ℓ^∞(ℕ)/c₀(ℕ)** and the **Calkin algebra**, which have no states at all in ZF models where every set of reals has the Property of Baire | local | a | (R2) | +| (A5) | `A` has a faithful state | provable from (A1) | [BF26] `FaithfulStateThm` | — | local | a | (R1) | +| (A6) | `S(A)` is weak\*-separable | provable from (A1)+(A2); model-dependent without (A1) | [BF26] `L.S(A)`, `P.Russel.example` | the **Russell-set algebra** — concretely representable, unital, commutative, AF, non-separable, with a state space that is not compact and has no extreme points | local | a | (R2) | +| (A7) | Krein–Milman / nonemptiness of the pure state space | **not a hypothesis of this theorem** | [BF26]: the route `SepRepThm ← FaithfulStateThm ← L.S(A)` cites only weak\*-separability, itself from Banach–Alaoglu plus metrizability, both proved outright in ZF | — | — | a | (R13) only | +| (A8) | `H_φ` is separable when `A` is | provable from (A1) — **and no source in the corpus proves it** | the argument is written out at (R7); the corpus supplies only the ingredients | — | local | a | (R1) | +| (A9) | the representation is nondegenerate | provable for `A ≠ 0`; fails at `A = 0` | [LAN98] defines nondegeneracy; the GNS representation of a state on a unital algebra is cyclic, and cyclic ⟹ nondegenerate | `A = 0` | local | a | — (not asserted by the adopted form) | + +Hypotheses searched for and found attached nowhere in this corpus: nuclearity, +exactness, simplicity, stable rank, existence of a tracial state, σ-finiteness, +type classification, amenability. The theorem rests on separability alone. + +## Degeneracies and boundary cases + +| Case | Effect on the adopted form | Tier | +|---|---|---| +| intended case is nonvacuous | **C([0,1])** — separable by Stone–Weierstrass over ℚ+iℚ, infinite-dimensional, and faithfully represented by multiplication operators on the separable space L²([0,1], m); second instance, the compacts 𝒦 = K(ℓ²) with their defining representation | a | +| zero object / scalars | `A = 0` is separable and the unique map into any `B(H)` is injective, so the adopted form holds trivially. It breaks two natural strengthenings: "π is nondegenerate on a nonzero H" and "π is unital" — see (X7) | a | +| finite-dimensional | no effect; conclusion automatic, since a finite-dimensional C\*-algebra is a direct sum of matrix algebras and sits in `B(ℂⁿ)`. By (R10) this is the **only** case where the ambient `B(H)` is itself norm-separable | a | +| commutative | no effect on truth; a second route exists via (R13) and multiplication operators on L²(X,μ), and that route is strictly more expensive in ZF because it consumes Krein–Milman (A7) | a | +| non-separable / non-σ-finite | **conclusion false.** Witness **c₀(ω₁)**: its ℵ₁ many singleton characteristic functions are nonzero mutually orthogonal projections, whose images under a faithful π are nonzero mutually orthogonal projections; the least-index argument BF26 uses for ε-discrete sets then injects ω₁ into ℕ. Non-σ-unital cannot arise at all, by (A3) | a | +| type III | outside the scope, provably: no infinite-dimensional von Neumann algebra is norm-separable, by BF26's 2^ℵ⁰-sized 1-discrete family of projections. Witnesses: the hyperfinite II₁ factor, L^∞([0,1]) — both act on separable Hilbert spaces and neither is a separable C\*-algebra | a | +| non-unital / degenerate representation | no effect; (A2) discharges unitality by unitisation and the adopted form asserts no nondegeneracy. Named non-unital separable instance: C₀(ℝ) | a | +| universally orthogonal index element | no effect on the adopted form. In the direct-sum formulations the index set is the state space; its degenerate extreme `A = ℂ` gives a one-dimensional sum, harmless, and its opposite extreme — uncountable state space — is what destroys those formulations (X1) | a | +| quantifier swap: ∀…∃… ↦ ∃…∀… | swapping to "for every `a ≠ 0` there is a representation on a separable H not killing `a`" gives BF26's weaker `RepThm`. Under (A1) the two are **equivalent**, by a route no source states: index by a dense sequence (aₙ) of the algebra, take the state norming each aₙ from (R4), and form the countable direct sum ⊕ₙ π_{ψₙ}. Each summand is separable by (A8), so the countable sum is separable in ZF, and the representation is isometric on a dense set | a | +| quantifier swap: ∃ separable H ↦ ∀ separable H | **false.** `A = M₂(ℂ)`, `H = ℂ`: `B(ℂ) = ℂ` admits no injective \*-homomorphism from M₂(ℂ) | a | +| hypothesis dropped: (A1) | nothing survives — false, witness c₀(ω₁) above | a | +| hypothesis dropped: (A2) | everything survives — discharged by unitisation | a | +| hypothesis dropped: (A5) | everything survives, via the quantifier-swap route above, which avoids the faithful state entirely | a | +| hypothesis dropped: (A7) | everything survives for this theorem; the *commutative* Gelfand theorem (R13) falls | a | +| hypothesis dropped: (A9) | everything survives, except at `A = 0` | a | + +## Rejected formulations and refuted claims + +**Append-only.** + +| id | Candidate or claim | Disposition | Discriminator | Tier | Date | +|---|---|---|---|---|---| +| (X1) | take the direct sum of the GNS representations of **all** states — the universal representation | rejected | **(X1) separating object** — **ℂ²**: the cyclic vectors Ω_ω lie in mutually orthogonal summands and form an orthonormal family of cardinality \|S(A)\|, uncountable for every algebra of dimension ≥ 2, while ℂ² is separable. [LAN98] flags the defect (`absurdly large`) but adopts the construction, so this is not an (X4) | a | 2026-08-16 | +| (X2) | take one pure state from each unitary-equivalence class, and sum over those — [LAN98]'s own refinement | rejected | **(X1) separating object** — **C([0,1])**: its pure states are exactly the point evaluations (`The pure state space of the commutative \ca\ $C_0(X)$ (equipped with the relative $w^*$-topology) is homeomorphic to $X$.`), each with a one-dimensional GNS space and a distinct kernel, so the classes are still continuum many. C₀(ℝ) works identically | a | 2026-08-16 | +| (X3) | read "separable Hilbert space" as "has a countable orthonormal basis" | **(X5) conditional equivalence** | assumption named: the axiom of countable choice. [BF26], in ZF: `an infinite-dimensional Hilbert space need not contain an orthonormal sequence, or even an infinite orthonormal set`, and in the other direction there is a nonseparable Hilbert space carrying a sequence of mutually orthogonal rank-one projections. [SHI12] *adopts* the basis reading, so this is a definitional variant (D6), not a rejection | a | 2026-08-16 | +| (X4) | state the conclusion as "on ℓ²(ℕ)" | equivalent | for `A ≠ 0`, by amplification and (R12); only the *nondegenerate*-on-ℓ² variant dies at `A = 0`. Caveat (C4): the phrasing silently excludes finite dimension unless ℓ² is read loosely | a | 2026-08-16 | +| (X5) | demand "faithful **and** isometric" as two separate conditions | equivalent | (R5) — injective ⟹ isometric for C\*-algebras, so the second demand is empty | a | 2026-08-16 | +| (X6) | state it as "`A` is \*-isomorphic to a norm-closed \*-subalgebra of `B(H)`" rather than as an injective homomorphism | equivalent | (R5) — the image of an injective \*-homomorphism is automatically norm-closed. This is [BF26]'s own (D2) phrasing | a | 2026-08-16 | +| (X7) | strengthen the conclusion by demanding the representation be nondegenerate, or unital when `A` is | rejected | **(X2) degeneracy** — `A = 0`: no nondegenerate representation on a nonzero Hilbert space exists, and no unital \*-homomorphism `0 → B(H)` exists for `H ≠ 0` | a | 2026-08-16 | +| (X8) | strengthen "separable" to a characterisation — "`A` is separable **iff** it has a faithful representation on a separable Hilbert space" | refuted | **B(ℓ²)** is not norm-separable (R10) yet its identity representation on the separable space ℓ² is faithful. The hypothesis is sufficient and never necessary | a | 2026-08-16 | +| (X9) | strengthen the conclusion to "on ℓ² with π(A) containing no nonzero compact operator", or any similar structural normalisation of the image | open — could not separate; searched all three sources for `compact`, `essential`, `Calkin` and read [LAN98]'s compact-operator section | — | c | 2026-08-16 | +| (X10) | weaken "separable" to "has a well-ordered dense subset" in the conclusion as well as the hypothesis | open — could not separate. [BF26] pairs the two hypotheses systematically elsewhere (`Every separable \cstar-algebra, and more generally every \cstar-algebra with a well-ordered dense subset, has sufficiently many states.`) but stops short of the analogue for the representation theorem | — | c | 2026-08-16 | +| (X11) | *claim*: [BF26] proves `SepRepThm` | refuted | there is **no proof environment after the theorem** in BF26's LaTeX source: `\begin{Theorem}\label{SepRepThm}` is followed by the statement, `\end{Theorem}`, a commented-out paragraph, and then the commutative Gelfand theorem. The whole justification is the one preceding sentence, which never mentions separability of the Hilbert space | a | 2026-08-16 | +| (X12) | *claim*: the separable refinement is obtained by trimming the pure-state direct sum to a countable subfamily of pure states | refuted | (X2)'s separating object. The trimming that does work indexes by a dense sequence **of the algebra**, not by states — see the quantifier-swap row in `## Degeneracies` | a | 2026-08-16 | + +## Prior art + +| System | Found | Relation to variants | How searched | Measured at | +|---|---|---|---|---| +| Mathlib | `PositiveLinearMap.PreGNS`, `.GNS` (a `UniformSpace.Completion`), `.gnsNonUnitalStarAlgHom`, `.gnsStarAlgHom` in `Mathlib/Analysis/CStarAlgebra/GelfandNaimarkSegal.lean` | partial — supplies the GNS construction of (D7) for a positive linear functional, with **no** cyclic vector (its own TODO asks for one), no faithfulness, no isometry, no nondegeneracy, no separability | `find` for `*GelfandNaimark*`; full read of the file; `lean_leanfinder "faithful representation of a C*-algebra on a Hilbert space; injective star algebra homomorphism into bounded operators"` | `5450b53e5ddc75d46418fabb605edbf36bd0beb6` | +| Mathlib | `NonUnitalStarAlgHom.norm_map`, `.isometry` in `Mathlib/Analysis/CStarAlgebra/Hom.lean` | same as (R5) — an injective non-unital \*-homomorphism of complex C\*-algebras is isometric, already a theorem | `lean_leansearch "C*-algebra embeds isometrically into bounded operators on a Hilbert space"`; read of the file | `5450b53e…` | +| Mathlib | `gelfandTransform_isometry`, `gelfandTransform_bijective`, `gelfandStarTransform` in `GelfandDuality.lean` | unrelated — the **commutative** Gelfand–Naimark theorem, a different statement under a stronger hypothesis; it shares only the name | file read | `5450b53e…` | +| Mathlib | could not find a **noncommutative** Gelfand–Naimark theorem in any form | — | `grep -rni "gelfand.naimark" Mathlib/ --include=*.lean -l` (one file, the GNS one); `lean_leansearch "C*-algebra embeds isometrically into bounded operators on a Hilbert space"`; GitHub PR search `repo:leanprover-community/mathlib4 Gelfand Naimark is:pr` (one PR, #33116, the GNS construction) | `5450b53e…` | +| Mathlib | could not find a notion of a **state** on a C\*-algebra, nor of a **faithful** state or representation | — the GNS input is `PositiveLinearMap`, with no normalisation and no faithfulness predicate | `grep -rn "faithful" Mathlib/Analysis/CStarAlgebra/ Mathlib/Analysis/InnerProductSpace/ -i`; `grep -rni "\bstate\b" Mathlib/Analysis/CStarAlgebra/*.lean`; `grep -rln "QuasiState\|StateSpace\|IsState\b" Mathlib/` | `5450b53e…` | +| Mathlib | `TopologicalSpace.SeparableSpace` (the `@[mk_iff]` class), `DenseRange.separableSpace`, `SeparableSpace.of_denseRange`, `IsSeparable.image`, `isSeparable_range`, `IsSeparable.span`, countable products, `UniformSpace.separableSpace_completion` | supplies (C3)'s topological reading and, composed, supplies the corpus's missing (R7): the GNS space is a completion of a type synonym of the algebra, so dense-range transfer followed by separability of completions covers it | `grep`/read of `Topology/Bases.lean`, `UniformSpace/{Cauchy,Completion}.lean`, `Topology/Algebra/Module/Basic.lean` | `5450b53e…` | +| Mathlib | `IsHilbertSum`, `IsHilbertSum.linearIsometryEquiv`, `HilbertBasis`, `exists_hilbertBasis` in `InnerProductSpace/l2Space.lean` | partial — "every Hilbert space is unitarily an ℓ²" in unindexed Zorn generality, i.e. (R12) without the cardinality bookkeeping | file read | `5450b53e…` | +| Mathlib | could not find separability of `lp` over a countable index, nor "separable iff countable Hilbert basis", nor "a separable Hilbert space is unitarily ℓ²(ℕ)" | — this is where (C4)/(R12) have no counterpart | `grep -rni "separab" Mathlib/Analysis/InnerProductSpace/ Mathlib/Analysis/Normed/Lp/`; `lean_leansearch "separable Hilbert space has a countable orthonormal basis"`; `lean_leansearch "lp space is separable when the index type is countable"`; `lean_loogle "TopologicalSpace.SeparableSpace (lp _ _)"` (empty) | `5450b53e…` | +| Mathlib | `WeakDual.isCompact_closedBall`, `WeakDual.isCompact_polar`, `WeakDual.exists_countable_separating`, `WeakDual.metrizable_of_isCompact`, sequential Banach–Alaoglu | supplies both halves of (R3)'s analytic input — Banach–Alaoglu and metrizability of weak\*-compact subsets for a separable normed space. Could not find the composed statement that the dual ball is weak\*-separable | `grep -rni "alaoglu"`; `grep -rni "metrizab" Mathlib/Analysis/Normed/Module/WeakDual.lean`; `lean_leansearch "separable normed space dual unit ball weak-star separable"` | `5450b53e…` | +| Mathlib | could not find "`B(H)` is norm-separable iff `H` is finite-dimensional" (R10) | — | `grep -rni "separab" Mathlib/Analysis/Normed/Operator/*.lean Mathlib/Analysis/Normed/Module/Dual.lean`; `grep -rn "SeparableSpace (.*→L\[" Mathlib/ --include=*.lean` | `5450b53e…` | +| Isabelle AFP | `Complex_Bounded_Operators` — complex normed/Banach/Hilbert spaces, `cblinfun`, unitaries, projectors, BLT, adjoints, Loewner order | unrelated — supplies the ambient `B(H)`, not the object. The abstract names no C\*-algebras, no Gelfand–Naimark, no GNS, no separability; only the abstract was read | WebSearch for the AFP entry and for `arXiv:2512.05878`; the AFP search page itself is client-side rendered and returned nothing — an instrument failure, not an absence | 2026-08-16 | +| Coq/Rocq | could not find any formalization of Gelfand–Naimark in either form, or of C\*-algebras as a structure | — | one WebSearch, `Coq mathcomp-analysis Gelfand-Naimark C*-algebra formalization`; a thin measurement | 2026-08-16 | +| Lean Zulip | could not find a thread on the noncommutative theorem or on faithful representations | — the archive indexes poorly, so this is a weak negative. One community artefact found: a blog post on the merged GNS work, with no future-work items | WebSearch restricted to `leanprover.zulipchat.com` | 2026-08-16 | + +## Open questions + +- Whether the equivalence "injective ⟹ isometric ⟹ closed range" (R5), which + [BF26] uses parenthetically, survives in [BF26]'s ambient ZF. Both corpus + proofs of it are ZFC and go through the continuous functional calculus; [BF26] + cites no lemma at that point. This is the fourth of (R1)'s four dependencies + and the only one whose *scope* rather than existence is in doubt. +- (X9) — whether the image can be structurally normalised. +- (X10) — whether the well-ordered-dense-subset generalisation has a matching + conclusion about the Hilbert space. +- Whether the unitisation reduction (A2) preserves faithfulness of the state as + well as of the representation: every source in the corpus asserts the + reduction and none writes it out. +- Whether [SHI12] takes the inner product conjugate-linear in the first or the + second argument (C5) — not determined. + +## Sources + +**Append-only.** + +| Key | Work | Status | Cache | Version | Tier reached | Retrieved | +|---|---|---|---|---|---|---| +| BF26 | B. Blackadar, I. Farah, *Separable C\*-algebras Without the Countable Axiom of Choice*, arXiv:2602.15812 | retrieved | `references/arxiv-2602.15812/` | arXiv | a | 2026-08-16 | +| LAN98 | N. P. Landsman, *Lecture Notes on C\*-algebras, Hilbert C\*-modules and Quantum Mechanics*, arXiv math-ph/9807030 | retrieved | `references/arxiv-math-ph-9807030/` | arXiv | a | 2026-08-16 | +| SHI12 | V. Shirbisheh, *Lectures on C\*-algebras*, arXiv:1211.3404 | retrieved | `references/arxiv-1211.3404/` | arXiv | a | 2026-08-16 | +| VER25 | R. Verch, *Lecture Notes on Operator Algebras and Quantum Field Theory*, arXiv:2507.00900 | retrieved | `references/arxiv-2507.00900/` | arXiv | a | 2026-08-16 | +| MUR90 | G. J. Murphy, *C\*-algebras and Operator Theory*, Academic Press 1990 — reported to state the Gelfand–Naimark theorem together with the refinement that a separable algebra may be represented on a separable Hilbert space; no locator, the work was not opened | not retrieved — no legitimate free copy found; only a web search was attempted | — | — | d | 2026-08-16 | +| PED79 | G. K. Pedersen, *C\*-algebras and their Automorphism Groups*, Academic Press 1979 | not retrieved — same | — | — | d | 2026-08-16 | +| DIX77 | J. Dixmier, *C\*-algebras*, North-Holland 1977 | not retrieved — same | — | — | d | 2026-08-16 | +| BLA06 | B. Blackadar, *Operator Algebras: Theory of C\*-Algebras and von Neumann Algebras*, Springer 2006 — cited by BF26 for the definition of a C\*-algebra and for "norm 1 and φ(1)=1 ⟹ state" | not retrieved | — | — | c (through BF26) | 2026-08-16 | +| BLA-R | B. Blackadar, *Real Analysis* — cited by BF26 for "closed subsets of separable metric spaces are separable" and for the pure state space being G_δ | not retrieved | — | — | c (through BF26) | 2026-08-16 | +| BLA-H | B. Blackadar, *Hilbert spaces* (2023) — cited by BF26 for the ZF pathologies: a Hilbert space with no orthonormal basis, Russell and Cohen-finite sets | not retrieved | — | — | c (through BF26) | 2026-08-16 | +| TAK79 | M. Takesaki, *Theory of Operator Algebras I*, Springer 1979 | not retrieved — same | — | — | d | 2026-08-16 | + +## Not investigated + +- **The `[ext]` gap.** Lane 2 marked five external edges; lane 5 reached none of + them, because all five point into books nobody obtained. They are: Blackadar, + *Operator Algebras* — a linear functional on a unital C\*-algebra is a state + iff it has norm 1 and value 1 at the unit (consumed by (R4)); Blackadar, + *Real Analysis* — closed subsets of separable metric spaces are separable + (consumed by (R11)) and the pure state space of a separable unital + C\*-algebra is G_δ (consumed by the clause of (R3) that nothing on the route + to (R1) uses); Blackadar, *Hilbert spaces* — the ZF pathologies underwriting + (X3); and Krein–Milman as [LAN98] states it, without proof (consumed by (R9), + not by (R1)). **(R4) is on the route to (R1), so the load-bearing chain does + pass through a tier (c) edge** — this is what sets `worst-tier: c`. +- **BF26's own internal edges** were read as statements only, not chased: its + separable Hahn–Banach / Banach–Alaoglu package, its separable Krein–Milman, + its continuous functional calculus, and its positivity proposition. +- **(R7) is absent from the corpus and the argument in this note is the note's + own**, not any source's. Anyone relying on (R1) is relying on a step no source + in this corpus writes down. +- **(R5)'s scope in ZF** is unresolved — see `## Open questions`. Every claim + that BF26's `SepRepThm` delivers a *concrete* C\*-algebra of operators, rather + than merely an injective homomorphism, rests on it. +- **The five textbooks were never opened**, so the attributions that motivated + this extraction — that Murphy, Pedersen, Dixmier, Blackadar and Takesaki each + state the refinement alongside the Gelfand–Naimark theorem — are unverified. + No row in this note carries a locator into any of them. Whether the refinement + sits in the body of a numbered result or in a following remark is therefore + still unknown, and that was one of the questions the extraction set out to + answer. +- **Proof reading depth.** (R5) as LAN98 states it, (R10), and [LAN98]'s + compact-operator proposition were skimmed rather than read through, and are + recorded as sketched. [LAN98]'s `spc`/`spc5` and its ideal theory were not + opened. +- **[VER25] was mis-scoped by the orchestrator** and only partly recovered: it + contains no occurrence of "separable" or "Gelfand", but it is the corpus's + only source for (D4) and (R6). Lanes 3 and 4 accepted the mis-scoping and did + not open it, so its degeneracy and hypothesis content is unmeasured. +- **Not searched**: HOL Light, Metamath, Mizar, and Lean's `Mathlib/Archive`. + The Isabelle AFP entry was measured from its abstract only, and the Coq/Rocq + and Zulip negatives rest on one search each. +- **The unexamined base.** Everything above stands on the tier (c) rows in + `## Sources` — the three Blackadar works reached only through BF26's + citations — and on the two tier (c) `open` rows (X9) and (X10). From 9b1810dfe8ea867adbcde4ff7796eba6bc818c48 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 14:12:39 +0000 Subject: [PATCH 105/113] docs: record the math-review ledger entry for GelfandNaimark One refuted claim from the /math-review pass over the Gelfand-Naimark work: the four textbook locators in the module doc were filed as phantom citations because the extraction note records all five books as never retrieved. The refutation pass fetched chapter listings from OpenLibrary, the Library of Congress via the Wayback Machine, and Crossref, and found every cited chapter is the one the theorem actually sits in. The module doc now cites those chapters by title rather than the section numbers, which stay unconfirmed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-review/ledger.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.claude/skills/math-review/ledger.md b/.claude/skills/math-review/ledger.md index 5046e79..e729e24 100644 --- a/.claude/skills/math-review/ledger.md +++ b/.claude/skills/math-review/ledger.md @@ -60,4 +60,6 @@ re-adjudicated (the new adjudication replaces the old row). | `QuantumSystem/Algebra/LocalNet/Covariance.lean:LocalNet.Covariance` (module doc) | 4 | "Verch 2025 §1.2" appears in no extraction note's source table and could not be verified — suspected phantom citation | Resolves to R. Verch, *Lecture Notes on Operator Algebras and Quantum Field Theory*, arXiv:2507.00900 (2025-07-01); its subsection 1.2 ("Algebraic QFT on Minkowski Spacetime: Haag-Kastler Nets of Local Algebras") states exactly the cited covariance axiom `α_L(𝒜(O)) = 𝒜(L(O))` (source `York-Notes2025.tex` lines 351–353). The extraction notes index only their own corpora, so absence from their source tables is not drift | `LocalNet.Covariance` (module doc) | 4ec09ec (working tree) | 2026-08-15 | | `QuantumSystem/Algebra/LocalNet/Examples.lean:zeroHom` | 1 | The `zeroHom`/`zeroRep` docstring ("this still exhibits the property rather than trivialising it away") contradicts the repo's own statements that the zero representation trivialises the split property | "Trivialising it away" means annihilation on the zero *space* (where `IsSplitInclusion` is identically false), not trivial satisfaction: the clause "`𝓡(O)` contains `1` regardless, since a von Neumann algebra is unital" is shared verbatim with `SplitProperty.lean`'s `VonNeumannNet.SplitProperty` module prose, whose next sentence states the nonzero-space/zero-space dichotomy the docstring restates; and `Examples.lean`'s own module header concedes the triviality at length ("stated so it is not mistaken for evidence"). The mathematical residue (collapse to `ℂ1` for *any* representation on `ℂ`, sole witness) survives — only the contradiction reading was refuted | `zeroHom` (docstring), `VonNeumannNet.SplitProperty` (module prose), `Examples.lean` module header | 351f5dd (working tree) | 2026-08-15 | | `QuantumSystem/Algebra/LocalNet/SplitProperty.lean:VonNeumannNet.SplitProperty.isSplitInclusion_commutant` (and `LocalNet.SplitProperty.isSplitInclusion_commutant`) | 4 | The two `isSplitInclusion_commutant` docstrings contradict each other | The two theorems have the same shape (`O₁ ⋐ O₂`, `O₂ ⟂ O_B` ⊢ `IsSplitInclusion 𝓡(O₁) 𝓡(O_B)′`), the second is a one-line specialisation of the first, and the second docstring's summary of the first (Haag duality for the converse, Buchholz's four-term chain) is accurate; no proposition on which they disagree exists in the current tree. Confirmed by the aggregator reading both docstrings in source | `VonNeumannNet.SplitProperty.isSplitInclusion_commutant`, `LocalNet.SplitProperty.isSplitInclusion_commutant` (both docstrings) | 351f5dd (working tree) | 2026-08-15 | +| `QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean:gelfand_naimark_theorem` | 1/3 | The conclusion omits **nondegeneracy** of the representation, which the standard universal-representation statement of Gelfand–Naimark carries — a scope gap in the formalized statement (filed together with a separability half, which is *not* refuted and survives at (c)) | The two existentials are **equivalent**, so nondegeneracy cannot strengthen the conclusion: given isometric `φ : A →⋆ₙₐ[ℂ] 𝓑(H)`, set `K := closure (span (φ(A) H))`; `φ(A)` is `*`-closed so `Kᗮ = {ξ | ∀ a, φ a ξ = 0}`, hence `‖φ a‖ = ‖(φ a)|_K‖` and the corestriction `A → 𝓑(K)` is an isometric `*`-hom that is nondegenerate by construction. Independently, the witness actually used *is* nondegenerate: `GNS.Representation.cyclic : Dense ↑(Submodule.span ℂ {x | ∃ a, self.π a self.ξ = x})` is a field of the GNS triplet, cyclic ⟹ nondegenerate, and an ℓ²-direct sum of nondegenerate representations is nondegenerate. Note the naive route fails and was *not* used: nondegeneracy is not automatic from `Isometry` for a fixed `φ` (`a ↦ φ a ⊕ 0` on `H ⊕ ℂ` is isometric and degenerate) | `GNS.Representation.cyclic`, `GNS.DirectSum.Hilbert`, `GNS.DirectSum.directSumAlgHom`, `GNS.DirectSum.directSumAlgHom_isometry` | 2e21b4b | 2026-08-15 | | `QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean:IsFactor.exists_spatial_tensor_decomposition` (module docs of `StructureTheorem.lean` and `TensorFactor.lean` also cite it) | 4 | Citation "J. Yngvason, arXiv:1401.2652, §5.1, eqs. (38)/(39)" is unverifiable — no `references/` cache exists for it, unlike every other of the nine sources cited in this file set, and neither resolved extraction note lists it in its `## Sources` table | Fetched arXiv:1401.2652 directly (PDF → `pdftotext`): confirmed author J. Yngvason, confirmed §5.1 titled "Causal Independence and Split Property", confirmed eqs. (38)/(39) verbatim-match the docstrings' `𝒜₁ ⊂ 𝒩 ⊂ 𝒜₂′` / tensor-decomposition content, down to which symbol plays which role. The "no cache ⇒ suspicious" inference does not hold — it is a caching-completeness gap (8/9 sources cached), not a correctness signal | `StructureTheorem.lean` module doc + `IsFactor.exists_spatial_tensor_decomposition` docstring, `TensorFactor.lean` module doc | 351f5dd (working tree) | 2026-08-15 | +| `QuantumSystem/Algebra/CStarAlgebra/GelfandNaimark.lean` (module doc) | 4 | The four textbook locators — Murphy *C\*-algebras and Operator Theory* Thm 3.4.1, Pedersen *C\*-Algebras and Their Automorphism Groups* §3.7, Blackadar *Operator Algebras* II.6.4, Takesaki *Theory of Operator Algebras I* I.9.18 — are unverifiable/phantom citations, since the repo's own same-day extraction note `docs/math/separable-faithful-representation.md` records all five books (plus Dixmier) as **not retrieved**, with no `references/` cache and its own `## Not investigated` calling the attribution "unverified" | Independently-fetched bibliographic data (OpenLibrary + a 2007 Library-of-Congress TOC snapshot via the Wayback Machine, for Murphy; Crossref chapter listings for Pedersen/Blackadar/Takesaki) confirms each cited chapter is *exactly* the chapter where the noncommutative Gelfand–Naimark theorem belongs in that book's published structure — Murphy ch. 3 "Ideals and Positive Functionals"; Pedersen ch. 3 "Functionals and Representations"; Blackadar ch. II "C\*-Algebras"; Takesaki ch. I "Fundamentals of Banach Algebras and C\*-Algebras" — not a mismatch to an unrelated topic. This refutes the "phantom citation" reading (chapter-level, tier b). The exact section/theorem digit within each chapter (3.4.1 / §3.7 / II.6.4 / I.9.18) could not be independently pinned down by any source reachable in this sandbox and remains open at tier (c) — reported separately, not as a blocker | module doc of `GelfandNaimark.lean` (no Lean declaration dependency; refutation rests on external bibliographic sources, not on repo code) | a2fa4f5 | 2026-08-16 | From 71a5efb234715973d79046b916904e906542ead8 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 19:02:49 +0000 Subject: [PATCH 106/113] feat: state the bicommutant theorem as a three-way TFAE and derive its corollaries Package the WOT/SOT double-commutant halves proved in SOTClosedSubAlgebra.lean and WOTClosedSubAlgebra.lean into von Neumann's bicommutant theorem, for a possibly non-unital *-subalgebra acting non-degenerately: A = A'' iff A is WOT-closed iff A is SOT-closed. - InvariantSubspace.lean: add ActsNondegenerately, the non-unital hypothesis the equivalence needs (strictly weaker than 1 in A). - FiniteRank.lean (new): the finite-rank operators F(H), the witness that the non-unital generality is inhabited (negatively, on infinite-dimensional H). - TFAE.lean (new): DoubleCommutant.bicommutant_tfae and its unital/image corollaries, one_mem_of_isSOTClosed, the F(H) witness theorems, and VonNeumannAlgebra.ofIsWOTClosed/ofIsSOTClosed constructors. - StructureTheorem.lean: update OrthEquivFam.mem_sotClosure_adjoin for the renamed mem_sotClosure_of_mem_doubleCommutant_starSubalgebra. - QuantumSystem.lean: register the two new modules. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- QuantumSystem.lean | 2 + .../DoubleCommutant/SOTClosedSubAlgebra.lean | 199 +++++++++-- .../Algebra/Star/DoubleCommutant/TFAE.lean | 309 ++++++++++++++++++ .../DoubleCommutant/WOTClosedSubAlgebra.lean | 160 +++++++-- .../VonNeumannAlgebra/StructureTheorem.lean | 4 +- .../InnerProductSpace/FiniteRank.lean | 150 +++++++++ .../InnerProductSpace/InvariantSubspace.lean | 28 ++ .../Analysis/InnerProductSpace/RankOne.lean | 23 +- .../LocallyConvex/StrongOperatorTopology.lean | 219 ++++--------- .../LocallyConvex/WeakOperatorTopology.lean | 22 ++ 10 files changed, 882 insertions(+), 234 deletions(-) create mode 100644 QuantumSystem/Algebra/Star/DoubleCommutant/TFAE.lean create mode 100644 QuantumSystem/ForMathlib/Analysis/InnerProductSpace/FiniteRank.lean diff --git a/QuantumSystem.lean b/QuantumSystem.lean index 62c5c76..94b6104 100644 --- a/QuantumSystem.lean +++ b/QuantumSystem.lean @@ -24,6 +24,7 @@ public import QuantumSystem.Algebra.LocalNet.Net public import QuantumSystem.Algebra.LocalNet.QuasiLocalAlgebra public import QuantumSystem.Algebra.LocalNet.SplitProperty public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra +public import QuantumSystem.Algebra.Star.DoubleCommutant.TFAE public import QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra public import QuantumSystem.Algebra.VonNeumannAlgebra.Basic public import QuantumSystem.Algebra.VonNeumannAlgebra.SpatialDecomposition @@ -56,6 +57,7 @@ public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.Unital public import QuantumSystem.ForMathlib.Analysis.CStarAlgebra.WeakDual public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.AdjointNotation public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.DiagonalAmplification +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.FiniteRank public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.InvariantSubspace public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.RankOne public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.TensorProduct diff --git a/QuantumSystem/Algebra/Star/DoubleCommutant/SOTClosedSubAlgebra.lean b/QuantumSystem/Algebra/Star/DoubleCommutant/SOTClosedSubAlgebra.lean index 6e8a99e..8e3c171 100644 --- a/QuantumSystem/Algebra/Star/DoubleCommutant/SOTClosedSubAlgebra.lean +++ b/QuantumSystem/Algebra/Star/DoubleCommutant/SOTClosedSubAlgebra.lean @@ -8,13 +8,24 @@ public import QuantumSystem.ForMathlib.Analysis.LocallyConvex.StrongOperatorTopo This file proves the SOT version of the double commutant theorem by reducing to the WOT version. +Throughout, `A` is a possibly non-unital `*`-subalgebra (`NonUnitalStarSubalgebra`) acting +non-degenerately (`InnerProductSpace.ActsNondegenerately`); each result also carries a +`_starSubalgebra` corollary for the unital special case, where non-degeneracy is automatic. + ## Main results * `mem_sotClosure_of_mem_doubleCommutant`: any `T ∈ A''` lies in the SOT-closure of `A`. This is the key technical result, using diagonal amplification and the cyclic subspace argument. -* `isWOTClosed_of_isSOTClosed_starSubalgebra`: a SOT-closed *-subalgebra is WOT-closed. -* `doubleCommutant_eq_of_isSOTClosed`: if a *-subalgebra is SOT-closed, it equals its double - commutant (the "hard half" of the SOT double commutant theorem). +* `sotClosure_eq_doubleCommutant`, `wotClosure_eq_doubleCommutant`: the **density form** of the + theorem — for every non-degenerate `*`-subalgebra, with no closedness hypothesis whatsoever, + `A'' = closure_SOT A = closure_WOT A`. This is the strongest statement the argument below + establishes; everything after it is a corollary. +* `StrongOperatorTopology.isSOTClosed_of_isWOTClosed` (with `continuous_sotToWOT`): SOT is finer + than WOT, so every WOT-closed set is SOT-closed — no hypothesis on the set. Stated here, not in + the `ForMathlib` topology files, because those import Mathlib only. +* `isWOTClosed_of_isSOTClosed`: a SOT-closed non-degenerate *-subalgebra is WOT-closed. +* `doubleCommutant_eq_of_isSOTClosed`: if a non-degenerate *-subalgebra is SOT-closed, it equals + its double commutant (the "hard half" of the SOT double commutant theorem). ## Strategy @@ -31,11 +42,57 @@ The proof proceeds in two main steps: hence `A = A''`. Since double commutants are WOT-closed, `A` is WOT-closed. The final theorem `doubleCommutant_eq_of_isSOTClosed` then reduces to the WOT version via -`isWOTClosed_of_isSOTClosed_starSubalgebra`. +`isWOTClosed_of_isSOTClosed`. -/ @[expose] public section +/-! +## SOT is finer than WOT + +The comparison of the two type copies lives here rather than in either `ForMathlib` topology +file, because `ForMathlib` files import Mathlib only and the comparison needs both copies. +-/ + +namespace StrongOperatorTopology + +open WeakOperatorTopology + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] + +local notation "B" => (H →L[ℂ] H) +local notation "BSOT" => (H →SLₚₜ[RingHom.id ℂ] H) +local notation "BWOT" => (H →WOT[ℂ] H) + +/-- The identity map on operators, read as a map from the SOT type-copy to the WOT type-copy. -/ +noncomputable def sotToWOT (T : BSOT) : BWOT := + toWOTEquiv (H := H) ((toSOTEquiv (H := H)).symm T) + +@[simp] lemma sotToWOT_apply (T : BSOT) (x : H) : (sotToWOT (H := H) T) x = T x := rfl + +/-- **SOT is finer than WOT.** The identity map from the SOT type-copy to the WOT type-copy is +continuous: a net converging pointwise in norm converges in every matrix coefficient. -/ +lemma continuous_sotToWOT : Continuous (sotToWOT (H := H)) := by + refine ContinuousLinearMapWOT.continuous_of_dual_apply_continuous ?_ + intro x y + have hval : ∀ T : BSOT, y ((sotToWOT (H := H) T) x) = y (T x) := fun _ => rfl + simp only [hval] + exact y.continuous.comp ((continuous_apply x).comp + (PointwiseConvergenceCLM.isEmbedding_coeFn (RingHom.id ℂ) H H).continuous) + +/-- The SOT view of a set is the preimage of its WOT view under `sotToWOT`. -/ +lemma Set.toSOT_eq_preimage_toWOT (S : Set B) : + Set.toSOT (H := H) S = sotToWOT (H := H) ⁻¹' Set.toWOT (H := H) S := rfl + +/-- A WOT-closed set is SOT-closed. No hypothesis on `S` is needed: this is nothing but SOT being +the finer topology. The converse needs convexity and is not proved here. -/ +theorem isSOTClosed_of_isWOTClosed {S : Set B} (hS : IsWOTClosed (H := H) S) : + IsSOTClosed (H := H) S := by + rw [IsSOTClosed, Set.toSOT_eq_preimage_toWOT] + exact hS.preimage continuous_sotToWOT + +end StrongOperatorTopology + namespace SOTClosedSubalgebra open InnerProductSpace StrongOperatorTopology WeakOperatorTopology @@ -43,21 +100,25 @@ open InnerProductSpace StrongOperatorTopology WeakOperatorTopology variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] local notation "B" => (H →L[ℂ] H) -local notation "BSOT" => ContinuousLinearMapSOT H +local notation "BSOT" => (H →SLₚₜ[RingHom.id ℂ] H) local notation "BWOT" => (H →WOT[ℂ] H) -/-- Any element of the double commutant of a *-subalgebra lies in the SOT-closure of the algebra. +/-- Any element of the double commutant of a (possibly non-unital) *-subalgebra acting +non-degenerately lies in the SOT-closure of the algebra. This is the key technical result: we show that for any `T ∈ A''` and any finite set of points `x₁, ..., xₙ ∈ H`, the tuple `(Tx₁, ..., Txₙ)` lies in the closure of `{(Sx₁, ..., Sxₙ) | S ∈ A}`. -This uses diagonal amplification and the cyclic subspace argument. +This uses diagonal amplification and the cyclic subspace argument. For the unital special case +see `mem_sotClosure_of_mem_doubleCommutant_starSubalgebra`. -/ -lemma mem_sotClosure_of_mem_doubleCommutant (A : StarSubalgebra ℂ B) (T : B) +lemma mem_sotClosure_of_mem_doubleCommutant (A : NonUnitalStarSubalgebra ℂ B) (T : B) + (hnd : ActsNondegenerately (A : Set B)) (hT : T ∈ Set.centralizer (Set.centralizer (A : Set B))) : - (⟨T⟩ : BSOT) ∈ closure (Set.toSOT (H := H) (A : Set B)) := by - -- The SOT is induced by inducingFn : BSOT → (H → H). - -- Use the criterion: T ∈ closure(S) iff inducingFn T ∈ closure(inducingFn '' S) in product topology - rw [ContinuousLinearMapSOT.isInducing_inducingFn.closure_eq_preimage_closure_image] + (toSOTEquiv T : BSOT) ∈ closure (Set.toSOT (H := H) (A : Set B)) := by + -- The SOT is induced by the coercion `BSOT → (H → H)`. + -- Use the criterion: T ∈ closure(S) iff `↑T ∈ closure (↑'' S)` in the product topology. + rw [(PointwiseConvergenceCLM.isEmbedding_coeFn (RingHom.id ℂ) H + H).isInducing.closure_eq_preimage_closure_image] simp only [Set.mem_preimage] -- Need to show T (as a function H → H) is in the closure of {S : H → H | S ∈ A} -- in the product topology on H → H. @@ -92,8 +153,14 @@ lemma mem_sotClosure_of_mem_doubleCommutant (A : StarSubalgebra ℂ B) (T : B) let e : Fin n ≃ I_fin := Fintype.equivOfCardEq (by simp [n]) let xVec : Fin n → H := fun i => (e i).val let x_amp : Hn (H := H) n := (WithLp.equiv _ _).symm xVec - let Aamp : StarSubalgebra ℂ (Hn (H := H) n →L[ℂ] Hn (H := H) n) := + let Aamp : NonUnitalStarSubalgebra ℂ (Hn (H := H) n →L[ℂ] Hn (H := H) n) := A.map (diagonalStarAlgHom (H := H) n) + have hndAmp : ActsNondegenerately (Aamp : Set (Hn (H := H) n →L[ℂ] Hn (H := H) n)) := by + have hcoe : (Aamp : Set (Hn (H := H) n →L[ℂ] Hn (H := H) n)) = + diagonal (H := H) (n := n) '' (A : Set B) := by + simp [Aamp, diagonalStarAlgHom] + rw [hcoe] + exact WOTClosedSubalgebra.actsNondegenerately_image_diagonal (H := H) hnd n -- Choose a uniform ε let ε := I_fin.attach.inf' hI_fin_ne.attach (fun x => (heps' x).choose) have hε_pos' : ε > 0 := by @@ -110,7 +177,7 @@ lemma mem_sotClosure_of_mem_doubleCommutant (A : StarSubalgebra ℂ B) (T : B) have hTn : diagonal (H := H) (n := n) T ∈ Set.centralizer (Set.centralizer (Aamp : Set _)) := by have hdiag := diagonal_mem_double_commutant (H := H) (n := n) (A := (A : Set _)) (T := T) hT - simp only [StarSubalgebra.coe_map, Aamp, diagonalStarAlgHom] + simp only [NonUnitalStarSubalgebra.coe_map, Aamp, diagonalStarAlgHom] simpa using hdiag -- T^(n) preserves reducing subspaces of A^(n) have hPres : WOTClosedSubalgebra.PreservesReducingSubspaces (H := Hn (H := H) n) @@ -121,7 +188,7 @@ lemma mem_sotClosure_of_mem_doubleCommutant (A : StarSubalgebra ℂ B) (T : B) have hxmem : diagonal (H := H) (n := n) T x_amp ∈ WOTClosedSubalgebra.cyclicSubspace (H := Hn (H := H) n) Aamp x_amp := WOTClosedSubalgebra.mem_cyclicSubspace_of_preservesReducingSubspaces - (H := Hn (H := H) n) Aamp hPres x_amp + (H := Hn (H := H) n) Aamp hndAmp hPres x_amp -- The set {a x | a ∈ Aamp} equals {diagonal S x | S ∈ A} have hAamp_orbit : Set.range (fun a : Aamp => (a : Hn (H := H) n →L[ℂ] Hn (H := H) n) x_amp) = {y | ∃ S ∈ (A : Set _), y = diagonal (H := H) (n := n) S x_amp} := by @@ -129,13 +196,13 @@ lemma mem_sotClosure_of_mem_doubleCommutant (A : StarSubalgebra ℂ B) (T : B) simp only [Set.mem_range, Set.mem_setOf_eq] constructor · rintro ⟨⟨a, ha⟩, rfl⟩ - simp only [Aamp, StarSubalgebra.mem_map, diagonalStarAlgHom, StarAlgHom.coe_mk', + simp only [Aamp, NonUnitalStarSubalgebra.mem_map, diagonalStarAlgHom, StarAlgHom.coe_mk', AlgHom.coe_mk, RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk] at ha rcases ha with ⟨S, hS, rfl⟩ exact ⟨S, hS, rfl⟩ · rintro ⟨S, hS, rfl⟩ refine ⟨⟨diagonal (H := H) (n := n) S, ?_⟩, rfl⟩ - simp only [Aamp, StarSubalgebra.mem_map, diagonalStarAlgHom, StarAlgHom.coe_mk', + simp only [Aamp, NonUnitalStarSubalgebra.mem_map, diagonalStarAlgHom, StarAlgHom.coe_mk', AlgHom.coe_mk, RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk] exact ⟨S, hS, rfl⟩ -- The map S ↦ diagonal S x_amp is linear, so the orbit is a submodule @@ -202,19 +269,72 @@ lemma mem_sotClosure_of_mem_doubleCommutant (A : StarSubalgebra ℂ B) (T : B) calc ‖S z - T z‖ _ ≤ dist (diagonal (H := H) (n := n) T x_amp) (diagonal (H := H) (n := n) S x_amp) := hnorm_ineq _ < ε := hdist - · -- Show S ∈ inducingFn '' Set.toSOT A + · -- Show S, as a function, lies in the image of `Set.toSOT A`. simp only [Set.mem_image] - exact ⟨⟨S⟩, Set.mem_toSOT_iff.mpr hS, rfl⟩ - · -- I is empty, so the pi set is the whole space + exact ⟨toSOTEquiv S, Set.mem_toSOT_iff.mpr hS, rfl⟩ + · -- I is empty, so the pi set is the whole space; any element of `A` works, e.g. `0`. simp only [Set.not_nonempty_iff_eq_empty] at hI_nonempty - use (1 : H →L[ℂ] H) + use (0 : H →L[ℂ] H) constructor · apply htU rw [hI_nonempty, Set.empty_pi] exact Set.mem_univ _ - · exact ⟨⟨1⟩, Set.mem_toSOT_iff.mpr A.one_mem, rfl⟩ + · exact ⟨toSOTEquiv 0, Set.mem_toSOT_iff.mpr A.zero_mem, rfl⟩ -theorem isWOTClosed_of_isSOTClosed_starSubalgebra (A : StarSubalgebra ℂ B) +/-- Unital special case of `mem_sotClosure_of_mem_doubleCommutant`: since `1 ∈ A`, the algebra +acts non-degenerately and the general lemma applies. -/ +lemma mem_sotClosure_of_mem_doubleCommutant_starSubalgebra (A : StarSubalgebra ℂ B) (T : B) + (hT : T ∈ Set.centralizer (Set.centralizer (A : Set B))) : + (toSOTEquiv T : BSOT) ∈ closure (Set.toSOT (H := H) (A : Set B)) := + mem_sotClosure_of_mem_doubleCommutant A.toNonUnitalStarSubalgebra T + (actsNondegenerately_of_one_mem A.one_mem) hT + +/-- **The density form of the bicommutant theorem, SOT half.** For *every* non-degenerate +`*`-subalgebra — with no closedness hypothesis at all — the double commutant is exactly the +SOT-closure: + +`A'' = closure_SOT A`. + +This is the statement the proof actually establishes; the three-condition equivalence +(`DoubleCommutant.bicommutant_tfae`) is the corollary obtained by asking when the two sides equal +`A` itself. -/ +theorem sotClosure_eq_doubleCommutant (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) : + closure (Set.toSOT (H := H) (A : Set B)) = + Set.toSOT (H := H) (Set.centralizer (Set.centralizer (A : Set B))) := by + refine Set.eq_of_subset_of_subset ?_ ?_ + · -- The right-hand side is SOT-closed and contains `A`, so it contains the SOT-closure. + refine closure_minimal (fun T hT => ?_) (isSOTClosed_centralizer_centralizer (H := H) _) + exact Set.subset_centralizer_centralizer (S := (A : Set B)) hT + · intro T hT + exact mem_sotClosure_of_mem_doubleCommutant A _ hnd (Set.mem_toSOT_iff.mp hT) + +/-- **The density form of the bicommutant theorem, WOT half.** For every non-degenerate +`*`-subalgebra, with no closedness hypothesis, `A'' = closure_WOT A`. + +Together with `sotClosure_eq_doubleCommutant` this says that the SOT- and WOT-closures of a +non-degenerate `*`-subalgebra coincide, both being `A''`. -/ +theorem wotClosure_eq_doubleCommutant (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) : + closure (Set.toWOT (H := H) (A : Set B)) = + Set.toWOT (H := H) (Set.centralizer (Set.centralizer (A : Set B))) := by + refine Set.eq_of_subset_of_subset ?_ ?_ + · refine closure_minimal (fun T hT => ?_) (isWOTClosed_centralizer_centralizer (H := H) _) + exact Set.subset_centralizer_centralizer (Set.mem_toWOT_iff.mp hT) + · intro T hT + -- Go through the SOT-closure and push it forward along the continuous map `sotToWOT`. + have hSOT : (toSOTEquiv ((toWOTEquiv (H := H)).symm T) : BSOT) ∈ + closure (Set.toSOT (H := H) (A : Set B)) := + mem_sotClosure_of_mem_doubleCommutant A _ hnd (Set.mem_toWOT_iff.mp hT) + have hsub : closure (Set.toSOT (H := H) (A : Set B)) ⊆ + sotToWOT (H := H) ⁻¹' closure (Set.toWOT (H := H) (A : Set B)) := + closure_minimal (fun S hS => subset_closure (Set.mem_toSOT_iff.mp hS)) + (isClosed_closure.preimage continuous_sotToWOT) + simpa using hsub hSOT + +/-- A SOT-closed (possibly non-unital) *-subalgebra acting non-degenerately is WOT-closed. -/ +theorem isWOTClosed_of_isSOTClosed (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) (hSOT : IsSOTClosed (H := H) (A : Set B)) : IsWOTClosed (H := H) (A : Set B) := by -- Strategy: Show A = A'', then use that A'' is WOT-closed. @@ -223,21 +343,40 @@ theorem isWOTClosed_of_isSOTClosed_starSubalgebra (A : StarSubalgebra ℂ B) apply Set.eq_of_subset_of_subset Set.subset_centralizer_centralizer intro T hT -- T ∈ A'' → T ∈ SOT-closure(A) → T ∈ A (since A is SOT-closed) - have hT_in_SOT := mem_sotClosure_of_mem_doubleCommutant A T hT - simp only [Set.toSOT] at hT_in_SOT - rwa [IsClosed.closure_eq hSOT, Set.mem_setOf_eq] at hT_in_SOT + have hT_in_SOT := mem_sotClosure_of_mem_doubleCommutant A T hnd hT + rw [IsClosed.closure_eq hSOT] at hT_in_SOT + simpa [Set.mem_toSOT_iff] using hT_in_SOT rw [hA_eq_Acc] exact isWOTClosed_centralizer_centralizer (H := H) (A : Set B) +/-- Unital special case of `isWOTClosed_of_isSOTClosed`: a SOT-closed unital *-subalgebra is +WOT-closed. -/ +theorem isWOTClosed_of_isSOTClosed_starSubalgebra (A : StarSubalgebra ℂ B) + (hSOT : IsSOTClosed (H := H) (A : Set B)) : + IsWOTClosed (H := H) (A : Set B) := + isWOTClosed_of_isSOTClosed A.toNonUnitalStarSubalgebra + (actsNondegenerately_of_one_mem A.one_mem) hSOT + /-- The double commutant theorem (hard half) for SOT-closed *-subalgebras. -A SOT-closed *-subalgebra equals its double commutant. +A SOT-closed (possibly non-unital) *-subalgebra acting non-degenerately equals its double +commutant. For the unital special case see `doubleCommutant_eq_of_isSOTClosed_starSubalgebra`. -/ -theorem doubleCommutant_eq_of_isSOTClosed (A : StarSubalgebra ℂ B) +theorem doubleCommutant_eq_of_isSOTClosed (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) (hSOT : IsSOTClosed (H := H) (A : Set B)) : Set.centralizer (Set.centralizer (A : Set B)) = (A : Set B) := by -- Reduce to the WOT version. - have hWOT : IsWOTClosed (H := H) (A : Set B) := isWOTClosed_of_isSOTClosed_starSubalgebra A hSOT - exact WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed (H := H) A hWOT + have hWOT : IsWOTClosed (H := H) (A : Set B) := isWOTClosed_of_isSOTClosed A hnd hSOT + exact WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed (H := H) A hnd hWOT + +/-- Unital special case of `doubleCommutant_eq_of_isSOTClosed`: a SOT-closed unital +*-subalgebra equals its double commutant. Since `1 ∈ A`, the algebra acts non-degenerately +and the general theorem applies. -/ +theorem doubleCommutant_eq_of_isSOTClosed_starSubalgebra (A : StarSubalgebra ℂ B) + (hSOT : IsSOTClosed (H := H) (A : Set B)) : + Set.centralizer (Set.centralizer (A : Set B)) = (A : Set B) := + doubleCommutant_eq_of_isSOTClosed A.toNonUnitalStarSubalgebra + (actsNondegenerately_of_one_mem A.one_mem) hSOT end SOTClosedSubalgebra diff --git a/QuantumSystem/Algebra/Star/DoubleCommutant/TFAE.lean b/QuantumSystem/Algebra/Star/DoubleCommutant/TFAE.lean new file mode 100644 index 0000000..95481b2 --- /dev/null +++ b/QuantumSystem/Algebra/Star/DoubleCommutant/TFAE.lean @@ -0,0 +1,309 @@ +module + +public import QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.FiniteRank +public import QuantumSystem.ForMathlib.Analysis.InnerProductSpace.RankOne +public import QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant +public import Mathlib.Tactic.TFAE + +@[expose] public section + +/-! +# The bicommutant theorem as a list of equivalent conditions + +This file packages the two halves proved in +`QuantumSystem.Algebra.Star.DoubleCommutant.WOTClosedSubAlgebra` and +`QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra` into the three-condition form of +von Neumann's bicommutant theorem: for a `*`-subalgebra `A ⊆ B(H)` acting non-degenerately, + +1. `A` equals its own double commutant, +2. `A` is closed in the weak operator topology, +3. `A` is closed in the strong operator topology + +are equivalent. + +## Main results + +* `DoubleCommutant.bicommutant_tfae`: the equivalence for a possibly non-unital `*`-subalgebra + acting non-degenerately. +* `DoubleCommutant.bicommutant_tfae_starSubalgebra`: the unital special case, where non-degeneracy + is automatic. This is the form in which the theorem is usually quoted. +* `DoubleCommutant.bicommutant_tfae_image` (and its unital special case + `DoubleCommutant.bicommutant_tfae_image_starSubalgebra`): the two closedness conditions spelled + out as closedness of the image of `A` in the corresponding Mathlib type-copy. +* `DoubleCommutant.one_mem_of_isSOTClosed` (and `WOTClosedSubalgebra.one_mem_of_isWOTClosed`): a + non-degenerate `*`-subalgebra satisfying any of the three conditions contains `1`. This is what + the non-unital form adds over the unital one, and it is also what makes the extra scope purely + negative. +* `DoubleCommutant.bicommutant_tfae_finiteRankOperators`: the witness that the non-unital + generality is inhabited — on an infinite-dimensional `H` the theorem applies to `F(H)`, which + does not contain `1`. That it is inhabited only *negatively* is + `DoubleCommutant.not_isWOTClosed_finiteRankOperators`, + `DoubleCommutant.not_isSOTClosed_finiteRankOperators` and + `DoubleCommutant.centralizer_centralizer_ne_finiteRankOperators`. +* `VonNeumannAlgebra.ofIsWOTClosed`, `VonNeumannAlgebra.ofIsSOTClosed`: the payoff — a WOT-closed + (resp. SOT-closed) unital `*`-subalgebra *is* a von Neumann algebra, which is what makes the + topological definition of a von Neumann algebra usable against Mathlib's algebraic one. + +## Which form is standard + +The literature overwhelmingly quotes the **unital** three-condition form +(`bicommutant_tfae_starSubalgebra`); the non-degenerate form of `bicommutant_tfae` is the more +general one, adopted here because it also covers algebras that do not contain `1` — the compact +operators `K(H)` and the finite-rank operators `F(H)` on an infinite-dimensional `H` are +non-degenerate and non-unital, and the unital form says nothing about them. Norm-closedness, which +some sources additionally assume, is deliberately *not* assumed: no step of the proof consumes it +and each of the three conditions implies it. + +The extra scope so gained is inhabited only by algebras for which all three conditions *fail*: +by `one_mem_of_isSOTClosed`, a non-degenerate algebra satisfying any one of them contains `1` and +is therefore already covered by the unital form. That is not a defect — it is what the general +form is for, since the unital form cannot so much as state that `F(H)` is not WOT-closed. + +## Note on non-degeneracy + +Non-degeneracy is not a technical convenience: without it the equivalence is false. For a +decomposition `H = H₁ ⊕ H₂` with `H₂ ≠ 0` the algebra `B(H₁) ⊕ 0` is WOT-closed but is strictly +smaller than its double commutant, which is `B(H₁) ⊕ ℂ1`. (For `H₂ = 0` there is nothing to +separate and the algebra is all of `B(H)`.) Containing `1` is the standard sufficient condition, +which is why the unital corollaries carry no extra hypothesis; conversely, non-degeneracy plus any +one of the three conditions *implies* `1 ∈ A` (`WOTClosedSubalgebra.one_mem_of_isWOTClosed`, +`one_mem_of_isSOTClosed`), so the two hypothesis packages differ exactly on the algebras where the +equivalence holds negatively. + +Non-degeneracy is consumed **only** by the implication 3 → 1. The other two implications are +hypothesis-free: 1 → 2 because every double commutant is WOT-closed, and 2 → 3 because the SOT is +finer than the WOT (`StrongOperatorTopology.isSOTClosed_of_isWOTClosed`). The proof below is +routed as the cycle 1 → 2 → 3 → 1 precisely so that `hnd` is used at that one point and nowhere +else. +-/ + +/-! +## `F(H)` against the rest of the development + +The finite-rank operators are defined in +`QuantumSystem.ForMathlib.Analysis.InnerProductSpace.FiniteRank`, which imports Mathlib only. The +facts below combine them with declarations from *other* `ForMathlib` files +(`InnerProductSpace.ActsNondegenerately`, +`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`), so they live here. +-/ + +/-- `S′` denotes the commutant `Set.centralizer S` of a set of operators, the prime notation of the +operator-algebra literature (see `docs/math/bicommutant-theorem.md`, convention (C8)). Local to this +file: the file never opens the `VonNeumannAlgebra` scope, so this does not collide with +`VonNeumannAlgebra.commutant`'s own `′` (`QuantumSystem.ForMathlib.Analysis.VonNeumannAlgebra.Commutant`), +which is the same notation one level up, for a `VonNeumannAlgebra` rather than a bare `Set`. -/ +local postfix:max "′" => Set.centralizer + +namespace InnerProductSpace + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- **`F(H)` acts non-degenerately**, on every Hilbert space: the rank-one operator +`|x⟩⟨x| : z ↦ ⟪x, z⟫ • x` does not annihilate `x` unless `x = 0`. -/ +theorem actsNondegenerately_finiteRankOperators : + ActsNondegenerately (finiteRankOperators (H := H) : Set (H →L[ℂ] H)) := by + intro x hx + have h := hx (rankOne ℂ x x) (rankOne_mem_finiteRankOperators x x) + have h' : (inner ℂ x x : ℂ) • x = 0 := by simpa using h + rcases smul_eq_zero.mp h' with h1 | h1 + · exact inner_self_eq_zero.mp h1 + · exact h1 + +/-- **The commutant of `F(H)` is the scalars.** An operator commuting with every finite-rank +operator commutes in particular with every rank-one operator `|x⟩⟨y|`, and that already forces it +to be a multiple of the identity +(`ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm`). -/ +theorem centralizer_finiteRankOperators : + (finiteRankOperators (H := H) : Set (H →L[ℂ] H))′ + = Set.range fun c : ℂ => c • (1 : H →L[ℂ] H) := by + refine Set.Subset.antisymm (fun S hS => ?_) ?_ + · have hcomm : ∀ x y : H, S ∘L rankOne ℂ x y = rankOne ℂ x y ∘L S := by + intro x y + have h := hS _ (rankOne_mem_finiteRankOperators x y) + simpa [ContinuousLinearMap.mul_def] using h.symm + obtain ⟨c, hc⟩ := ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm hcomm + exact ⟨c, hc.symm⟩ + · rintro _ ⟨c, rfl⟩ + exact Set.center_subset_centralizer _ (Set.smul_mem_center c Set.one_mem_center) + +/-- **`F(H)'' = B(H)`.** The double commutant of the finite-rank operators is everything, because +their commutant is the scalars (`centralizer_finiteRankOperators`) and the scalars are central. + +On an infinite-dimensional `H` this is strictly larger than `F(H)`, which is why all three +conditions of the bicommutant theorem fail for `F(H)`; on a finite-dimensional `H` it is an +equality, `F(H)` being all of `B(H)` there. -/ +theorem centralizer_centralizer_finiteRankOperators : + (finiteRankOperators (H := H) : Set (H →L[ℂ] H))′′ = Set.univ := by + rw [centralizer_finiteRankOperators, Set.centralizer_eq_top_iff_subset] + rintro _ ⟨c, rfl⟩ + exact Set.smul_mem_center c Set.one_mem_center + +end InnerProductSpace + +namespace DoubleCommutant + +open InnerProductSpace StrongOperatorTopology WeakOperatorTopology + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +local notation "B" => (H →L[ℂ] H) + +/-- **The bicommutant theorem.** For a possibly non-unital `*`-subalgebra of `B(H)` acting +non-degenerately, equalling its own double commutant, being WOT-closed, and being SOT-closed are +all equivalent. + +Only the implication 3 → 1 consumes the non-degeneracy hypothesis; see the module docstring. -/ +theorem bicommutant_tfae (A : NonUnitalStarSubalgebra ℂ B) (hnd : ActsNondegenerately (A : Set B)) : + List.TFAE [ + (A : Set B)′′ = (A : Set B), + IsWOTClosed (H := H) (A : Set B), + IsSOTClosed (H := H) (A : Set B)] := by + tfae_have 1 → 2 := by + intro h + rw [← h] + exact isWOTClosed_centralizer_centralizer (H := H) (A : Set B) + tfae_have 2 → 3 := isSOTClosed_of_isWOTClosed (H := H) + tfae_have 3 → 1 := SOTClosedSubalgebra.doubleCommutant_eq_of_isSOTClosed A hnd + tfae_finish + +/-- Unital special case of `DoubleCommutant.bicommutant_tfae`, and the form in which the theorem is +usually quoted: since `1 ∈ A`, the algebra acts non-degenerately and no extra hypothesis is +needed. -/ +theorem bicommutant_tfae_starSubalgebra (A : StarSubalgebra ℂ B) : + List.TFAE [ + (A : Set B)′′ = (A : Set B), + IsWOTClosed (H := H) (A : Set B), + IsSOTClosed (H := H) (A : Set B)] := + bicommutant_tfae A.toNonUnitalStarSubalgebra (actsNondegenerately_of_one_mem A.one_mem) + +/-- `DoubleCommutant.bicommutant_tfae` with the two closedness conditions spelled out as closedness +of the image of `A` in the WOT resp. pointwise-convergence type-copy of `B(H)`. Stated at the same +generality as `DoubleCommutant.bicommutant_tfae`, since `isWOTClosed_iff_isClosed_image` and +`isSOTClosed_iff_isClosed_image` hold for an arbitrary set of operators. -/ +theorem bicommutant_tfae_image (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) : + List.TFAE [ + (A : Set B)′′ = (A : Set B), + IsClosed (ContinuousLinearMapWOT.ContinuousLinearMap.toWOTCLM + (σ := RingHom.id ℂ) (E := H) (F := H) '' (A : Set B)), + IsClosed (ContinuousLinearMap.toPointwiseConvergenceCLM ℂ (RingHom.id ℂ) H H + '' (A : Set B))] := by + rw [← isWOTClosed_iff_isClosed_image, ← isSOTClosed_iff_isClosed_image] + exact bicommutant_tfae A hnd + +/-- Unital special case of `DoubleCommutant.bicommutant_tfae_image`; equivalently, +`DoubleCommutant.bicommutant_tfae_starSubalgebra` with the two closedness conditions spelled out as +closedness of the image of `A` in the WOT resp. pointwise-convergence type-copy of `B(H)`. -/ +theorem bicommutant_tfae_image_starSubalgebra (A : StarSubalgebra ℂ B) : + List.TFAE [ + (A : Set B)′′ = (A : Set B), + IsClosed (ContinuousLinearMapWOT.ContinuousLinearMap.toWOTCLM + (σ := RingHom.id ℂ) (E := H) (F := H) '' (A : Set B)), + IsClosed (ContinuousLinearMap.toPointwiseConvergenceCLM ℂ (RingHom.id ℂ) H H + '' (A : Set B))] := + bicommutant_tfae_image A.toNonUnitalStarSubalgebra (actsNondegenerately_of_one_mem A.one_mem) + +/-- **A non-degenerate `*`-subalgebra satisfying any one of the three conditions contains `1`.** +Stated for the WOT in `WOTClosedSubalgebra.one_mem_of_isWOTClosed`; this is the SOT companion. + +Together the two say that the extra scope of the non-unital form over the unital one contains only +*negative* instances: a non-degenerate `*`-subalgebra that does not contain `1` fails all three +conditions. -/ +theorem one_mem_of_isSOTClosed (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) (hA : IsSOTClosed (H := H) (A : Set B)) : + (1 : B) ∈ A := + WOTClosedSubalgebra.one_mem_of_isWOTClosed A hnd + (SOTClosedSubalgebra.isWOTClosed_of_isSOTClosed A hnd hA) + +/-- **The non-unital generality is inhabited.** On an infinite-dimensional Hilbert space the +finite-rank operators `F(H)` act non-degenerately and do not contain `1`, so +`DoubleCommutant.bicommutant_tfae` applies to them while +`DoubleCommutant.bicommutant_tfae_starSubalgebra` does not. This is the witness that the +non-degeneracy hypothesis really is weaker than unitality, and not merely formally so. + +It is inhabited only *negatively*, and necessarily so: by `DoubleCommutant.one_mem_of_isSOTClosed` +a non-degenerate `*`-subalgebra satisfying any of the three conditions contains `1`. For `F(H)` all +three therefore fail together, exactly as the equivalence demands — see +`DoubleCommutant.not_isWOTClosed_finiteRankOperators`, +`DoubleCommutant.not_isSOTClosed_finiteRankOperators` and +`DoubleCommutant.centralizer_centralizer_ne_finiteRankOperators`, the last of which sharpens the +failure to `F(H)'' = B(H) ≠ F(H)`. -/ +theorem bicommutant_tfae_finiteRankOperators (h : ¬ FiniteDimensional ℂ H) : + (1 : B) ∉ finiteRankOperators (H := H) ∧ + List.TFAE [ + (finiteRankOperators (H := H) : Set B)′′ = (finiteRankOperators (H := H) : Set B), + IsWOTClosed (H := H) (finiteRankOperators (H := H) : Set B), + IsSOTClosed (H := H) (finiteRankOperators (H := H) : Set B)] := + ⟨one_notMem_finiteRankOperators h, + bicommutant_tfae _ actsNondegenerately_finiteRankOperators⟩ + +/-- On an infinite-dimensional `H` the finite-rank operators are **not** WOT-closed: they act +non-degenerately, so WOT-closedness would force `1 ∈ F(H)`. -/ +theorem not_isWOTClosed_finiteRankOperators (h : ¬ FiniteDimensional ℂ H) : + ¬ IsWOTClosed (H := H) (finiteRankOperators (H := H) : Set B) := fun hA => + one_notMem_finiteRankOperators h + (WOTClosedSubalgebra.one_mem_of_isWOTClosed _ actsNondegenerately_finiteRankOperators hA) + +/-- On an infinite-dimensional `H` the finite-rank operators are **not** SOT-closed. -/ +theorem not_isSOTClosed_finiteRankOperators (h : ¬ FiniteDimensional ℂ H) : + ¬ IsSOTClosed (H := H) (finiteRankOperators (H := H) : Set B) := fun hA => + one_notMem_finiteRankOperators h + (one_mem_of_isSOTClosed _ actsNondegenerately_finiteRankOperators hA) + +/-- On an infinite-dimensional `H` the finite-rank operators are **not** their own double +commutant: `F(H)'' = B(H)` by `InnerProductSpace.centralizer_centralizer_finiteRankOperators`, +while `1 ∉ F(H)`. -/ +theorem centralizer_centralizer_ne_finiteRankOperators (h : ¬ FiniteDimensional ℂ H) : + (finiteRankOperators (H := H) : Set B)′′ ≠ (finiteRankOperators (H := H) : Set B) := by + intro heq + refine one_notMem_finiteRankOperators h ?_ + change (1 : B) ∈ (finiteRankOperators (H := H) : Set B) + rw [← heq, centralizer_centralizer_finiteRankOperators] + trivial + +end DoubleCommutant + +namespace VonNeumannAlgebra + +open InnerProductSpace StrongOperatorTopology WeakOperatorTopology + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteSpace H] + +/-- **A WOT-closed unital `*`-subalgebra is a von Neumann algebra.** This is the reason the +bicommutant theorem is proved: Mathlib defines `VonNeumannAlgebra` by the *algebraic* condition +`A'' = A`, and this constructor supplies that field from the *topological* condition, so that an +algebra produced as a weak limit closure can be used as a von Neumann algebra. -/ +noncomputable def ofIsWOTClosed (A : StarSubalgebra ℂ (H →L[ℂ] H)) + (hA : IsWOTClosed (H := H) (A : Set (H →L[ℂ] H))) : VonNeumannAlgebra H where + toStarSubalgebra := A + centralizer_centralizer' := + WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed_starSubalgebra A hA + +/-- The carrier of `VonNeumannAlgebra.ofIsWOTClosed A hA` is `A` itself: the constructor supplies +only the `centralizer_centralizer'` field and leaves the underlying `*`-subalgebra untouched. -/ +@[simp] lemma coe_ofIsWOTClosed (A : StarSubalgebra ℂ (H →L[ℂ] H)) + (hA : IsWOTClosed (H := H) (A : Set (H →L[ℂ] H))) : + (ofIsWOTClosed A hA : Set (H →L[ℂ] H)) = (A : Set (H →L[ℂ] H)) := rfl + +/-- **An SOT-closed unital `*`-subalgebra is a von Neumann algebra.** The SOT companion of +`VonNeumannAlgebra.ofIsWOTClosed`. -/ +noncomputable def ofIsSOTClosed (A : StarSubalgebra ℂ (H →L[ℂ] H)) + (hA : IsSOTClosed (H := H) (A : Set (H →L[ℂ] H))) : VonNeumannAlgebra H := + ofIsWOTClosed A (SOTClosedSubalgebra.isWOTClosed_of_isSOTClosed_starSubalgebra A hA) + +/-- The carrier of `VonNeumannAlgebra.ofIsSOTClosed A hA` is `A` itself; the SOT companion of +`VonNeumannAlgebra.coe_ofIsWOTClosed`. -/ +@[simp] lemma coe_ofIsSOTClosed (A : StarSubalgebra ℂ (H →L[ℂ] H)) + (hA : IsSOTClosed (H := H) (A : Set (H →L[ℂ] H))) : + (ofIsSOTClosed A hA : Set (H →L[ℂ] H)) = (A : Set (H →L[ℂ] H)) := rfl + +/-- A WOT-closed unital `*`-subalgebra is the von Neumann algebra it generates: the topological +closedness condition and `VonNeumannAlgebra.generated` agree on it. -/ +lemma generated_coe_of_isWOTClosed (A : StarSubalgebra ℂ (H →L[ℂ] H)) + (hA : IsWOTClosed (H := H) (A : Set (H →L[ℂ] H))) : + (generated (A : Set (H →L[ℂ] H)) : Set (H →L[ℂ] H)) = (A : Set (H →L[ℂ] H)) := by + rw [coe_generated_of_star_eq (StarMemClass.star_coe_eq A), + WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed_starSubalgebra A hA] + +end VonNeumannAlgebra diff --git a/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean b/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean index dcb23e6..4693e84 100644 --- a/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean +++ b/QuantumSystem/Algebra/Star/DoubleCommutant/WOTClosedSubAlgebra.lean @@ -15,20 +15,27 @@ This file contains the proof of (a weak-operator-topology form of) von Neumann's Mathlib packages von Neumann algebras using the algebraic characterization: a `StarSubalgebra` is a von Neumann algebra when it equals its double commutant (implemented via `Set.centralizer`). -Classically, for a `*-`subalgebra of bounded operators on a Hilbert space, this algebraic condition -is equivalent to being closed in the weak operator topology (WOT). +Classically, for a possibly non-unital `*-`subalgebra of bounded operators on a Hilbert space +acting *non-degenerately* (no nonzero vector is annihilated by the whole algebra — +`InnerProductSpace.ActsNondegenerately`), this algebraic condition is equivalent to being closed +in the weak operator topology (WOT). Without non-degeneracy the equivalence fails +(e.g. `B(H₁) ⊕ 0` is WOT-closed but not its own double commutant), and containing `1` is the +standard special case: it implies non-degeneracy, and conversely a non-degenerate WOT-closed +`*-`subalgebra automatically contains `1` (`one_mem_of_isWOTClosed`). The "hard half" is the direction -*WOT-closed `*-`subalgebra* ⇒ *equals its double commutant*. +*WOT-closed non-degenerate `*-`subalgebra* ⇒ *equals its double commutant*. We state and prove this as an equality of sets of operators `Set.centralizer (Set.centralizer (A : Set B)) = (A : Set B)`. ## What this file contains -This file provides the main theorem `doubleCommutant_eq_of_isWOTClosed` and the intermediate -infrastructure used in its proof. The key objects are: +This file provides the main theorem `doubleCommutant_eq_of_isWOTClosed` (with unital special case +`doubleCommutant_eq_of_isWOTClosed_starSubalgebra`), its converse-direction corollary +`one_mem_of_isWOTClosed`, and the intermediate infrastructure used in its proof. The key objects +are: * `cyclicSubspace A x`: the closed subspace generated by the orbit `A • x`. It is shown to be *reducing* for `A`. @@ -75,34 +82,56 @@ variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] [CompleteS local notation "B" => (H →L[ℂ] H) local notation "BWOT" => (H →WOT[ℂ] H) +/-! +## Non-degeneracy and diagonal amplification + +Non-degeneracy (`InnerProductSpace.ActsNondegenerately`) is the hypothesis under which the +theorem holds for a possibly non-unital `*`-subalgebra; it passes to the diagonal amplification +componentwise. +-/ + +omit [CompleteSpace H] in +/-- Diagonal amplification preserves non-degeneracy: if `S` acts non-degenerately on `H`, then +`diagonal '' S` acts non-degenerately on `H^n`. -/ +lemma actsNondegenerately_image_diagonal {S : Set (B)} (hS : ActsNondegenerately S) (n : ℕ) : + ActsNondegenerately (diagonal (H := H) (n := n) '' S) := by + intro y hy + have hzero : ∀ i : Fin n, y.ofLp i = 0 := by + intro i + refine hS _ fun T hT => ?_ + have h0 : diagonal (H := H) (n := n) T y = 0 := hy _ ⟨T, hT, rfl⟩ + calc T (y.ofLp i) = (diagonal (H := H) (n := n) T y).ofLp i := (diagonal_apply T y i).symm + _ = 0 := by rw [h0]; rfl + ext i + exact hzero i + /-! ## Cyclic reducing subspaces -For a `StarSubalgebra` `A` and a vector `x`, the closed subspace generated by the orbit `A • x` -is reducing for `A`. Consequently, any operator in `reducingHull A` sends `x` back into this -cyclic reducing subspace. +For a `NonUnitalStarSubalgebra` `A` and a vector `x`, the closed subspace generated by the orbit +`A • x` is reducing for `A`. Consequently, any operator in `reducingHull A` sends `x` back into +this cyclic reducing subspace, provided `A` acts non-degenerately — non-degeneracy is what puts +`x` itself into the cyclic subspace (`mem_cyclicSubspace_of_actsNondegenerately`), replacing the +appeal to `1 ∈ A` of the unital argument. This is the core invariant-subspace ingredient in the classical “projection” approach. -/ -noncomputable def cyclicSubspace (A : StarSubalgebra ℂ B) (x : H) : Submodule ℂ H := +/-- The closed subspace generated by the orbit `A • x` of a vector `x` under a (possibly +non-unital) `*`-subalgebra `A`. -/ +noncomputable def cyclicSubspace (A : NonUnitalStarSubalgebra ℂ B) (x : H) : Submodule ℂ H := (Submodule.span ℂ (Set.range fun a : A => (a : B) x)).topologicalClosure -lemma subset_cyclicSubspace (A : StarSubalgebra ℂ B) (x : H) : +/-- The orbit `A • x` is contained in the cyclic subspace it generates. -/ +lemma subset_cyclicSubspace (A : NonUnitalStarSubalgebra ℂ B) (x : H) : (Set.range fun a : A => (a : B) x) ⊆ cyclicSubspace (H := H) A x := by intro y hy let S : Submodule ℂ H := Submodule.span ℂ (Set.range fun a : A => (a : B) x) have : y ∈ S := Submodule.subset_span hy exact (Submodule.le_topologicalClosure S) this -lemma mem_cyclicSubspace (A : StarSubalgebra ℂ B) (x : H) : x ∈ cyclicSubspace (H := H) A x := by - -- Use `1 ∈ A`. - have hx : (x : H) ∈ Set.range (fun a : A => (a : B) x) := by - refine ⟨(1 : A), ?_⟩ - simp - exact (subset_cyclicSubspace (H := H) A x) hx - -lemma isInvariant_cyclicSubspace_of_mem (A : StarSubalgebra ℂ B) (x : H) (a : B) +/-- The cyclic subspace is invariant under every element of `A`. -/ +lemma isInvariant_cyclicSubspace_of_mem (A : NonUnitalStarSubalgebra ℂ B) (x : H) (a : B) (ha : a ∈ (A : Set B)) : IsInvariant a (cyclicSubspace (H := H) A x) := by -- Work with the dense submodule `span (A • x)`. @@ -122,7 +151,7 @@ lemma isInvariant_cyclicSubspace_of_mem (A : StarSubalgebra ℂ B) (x : H) (a : have hab : a * (b : B) ∈ (A : Set B) := by -- Coerce `b : A` to `B`. -- `ha` provides `a ∈ A` and `A` is a subalgebra. - simpa using (A.mul_mem ha b.property) + simpa using (mul_mem ha b.property) -- Package `a*b` back as an element of `A`. refine Submodule.subset_span ?_ refine ⟨⟨a * (b : B), hab⟩, ?_⟩ @@ -149,7 +178,9 @@ lemma isInvariant_cyclicSubspace_of_mem (A : StarSubalgebra ℂ B) (x : H) (a : (Submodule.mem_map).2 ⟨y, hy, rfl⟩ exact hclosure this -lemma isReducing_cyclicSubspace (A : StarSubalgebra ℂ B) (x : H) : +/-- The cyclic subspace is reducing for `A`: `A` is star-closed, so invariance under adjoints +comes for free. -/ +lemma isReducing_cyclicSubspace (A : NonUnitalStarSubalgebra ℂ B) (x : H) : IsReducing (H := H) (A : Set B) (cyclicSubspace (H := H) A x) := by intro a ha refine ⟨?_, ?_⟩ @@ -157,7 +188,7 @@ lemma isReducing_cyclicSubspace (A : StarSubalgebra ℂ B) (x : H) : · -- Use `A` is star-closed. have ha' : a† ∈ (A : Set B) := by -- `star` on `B` is adjoint. - have : (star a) ∈ (A : Set B) := A.star_mem' ha + have : (star a) ∈ (A : Set B) := star_mem (s := A) ha simpa [ContinuousLinearMap.star_eq_adjoint] using this -- Now apply invariance to `a†`. simpa using @@ -170,7 +201,48 @@ def PreservesReducingSubspaces (S : Set (B)) (T : B) : Prop := ∀ (K : Submodule ℂ H) [K.HasOrthogonalProjection], IsReducing (H := H) S K → IsInvariant T K ∧ IsInvariant T Kᗮ -lemma mem_cyclicSubspace_of_preservesReducingSubspaces (A : StarSubalgebra ℂ B) {T : B} +/-- If `A` acts non-degenerately, then `x` lies in its own cyclic subspace. + +This replaces the appeal to `1 ∈ A` in the unital argument: the orthogonal projection `P` onto +the cyclic subspace lies in `A'`, so every `T ∈ A` kills `x - P x`, and non-degeneracy forces +`x = P x`. -/ +lemma mem_cyclicSubspace_of_actsNondegenerately (A : NonUnitalStarSubalgebra ℂ B) + (hA : ActsNondegenerately (A : Set B)) (x : H) : + x ∈ cyclicSubspace (H := H) A x := by + classical + let K : Submodule ℂ H := cyclicSubspace (H := H) A x + have hKclosed : IsClosed (K : Set H) := by + dsimp [K, cyclicSubspace] + exact + Submodule.isClosed_topologicalClosure + (s := Submodule.span ℂ (Set.range fun a : A => (a : B) x)) + letI : IsClosed (K : Set H) := hKclosed + letI : CompleteSpace K := (show CompleteSpace (↥(K : Set H)) from inferInstance) + letI : K.HasOrthogonalProjection := by infer_instance + have hRed : IsReducing (H := H) (A : Set B) K := isReducing_cyclicSubspace (H := H) A x + have hP : K.starProjection ∈ Set.centralizer (A : Set B) := + starProjection_mem_centralizer_of_isReducing (S := (A : Set B)) (K := K) hRed + -- Every `T ∈ A` annihilates `x - P x`. + have hker : ∀ T ∈ (A : Set B), T (x - K.starProjection x) = 0 := by + intro T hT + have hTx : T x ∈ K := (subset_cyclicSubspace (H := H) A x) ⟨⟨T, hT⟩, rfl⟩ + have hcomm : T * K.starProjection = K.starProjection * T := hP T hT + have h1 : T (K.starProjection x) = K.starProjection (T x) := by + simpa [ContinuousLinearMap.mul_apply] using congrArg (fun f => f x) hcomm + have h2 : K.starProjection (T x) = T x := + (Submodule.starProjection_eq_self_iff (K := K)).2 hTx + simp [map_sub, h1, h2] + -- Non-degeneracy forces `x = P x ∈ K`. + have hx0 : x = K.starProjection x := sub_eq_zero.mp (hA _ hker) + have hPx : K.starProjection x ∈ K := Submodule.starProjection_apply_mem (U := K) x + change x ∈ K + rw [hx0] + exact hPx + +/-- If `A` acts non-degenerately and `T` preserves all `A`-reducing subspaces, then `T` sends +`x` into the cyclic subspace generated by `A • x`. -/ +lemma mem_cyclicSubspace_of_preservesReducingSubspaces (A : NonUnitalStarSubalgebra ℂ B) + (hA : ActsNondegenerately (A : Set B)) {T : B} (hT : PreservesReducingSubspaces (H := H) (A : Set B) T) (x : H) : T x ∈ cyclicSubspace (H := H) A x := by classical @@ -185,7 +257,7 @@ lemma mem_cyclicSubspace_of_preservesReducingSubspaces (A : StarSubalgebra ℂ B letI : IsClosed (K : Set H) := hKclosed letI : CompleteSpace K := (show CompleteSpace (↥(K : Set H)) from inferInstance) letI : K.HasOrthogonalProjection := by infer_instance - have hx : x ∈ K := mem_cyclicSubspace (H := H) A x + have hx : x ∈ K := mem_cyclicSubspace_of_actsNondegenerately (H := H) A hA x have hRed : IsReducing (H := H) (A : Set B) K := isReducing_cyclicSubspace (H := H) A x have hInv : IsInvariant T K := (hT K hRed).1 exact (IsInvariant.iff_forall_mem (T := T) (K := K)).1 hInv x hx @@ -222,11 +294,14 @@ lemma centralizer_centralizer_subset_reducingHull (S : Set (B)) : intro T hT exact preservesReducingSubspaces_of_mem_centralizer_centralizer (H := H) (S := S) hT -/-- Hard direction of the double commutant theorem: a WOT-closed `*-`subalgebra is a double commutant. +/-- Hard direction of the double commutant theorem: a WOT-closed (possibly non-unital) +`*-`subalgebra acting non-degenerately equals its own double commutant. -This is stated as a set equality of commutants. +This is stated as a set equality of commutants. For the unital special case (where +non-degeneracy is automatic) see `doubleCommutant_eq_of_isWOTClosed_starSubalgebra`. -/ -theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) +theorem doubleCommutant_eq_of_isWOTClosed (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) (hA : IsWOTClosed (H := H) (A : Set B)) : Set.centralizer (Set.centralizer (A : Set B)) = (A : Set B) := by classical @@ -273,8 +348,14 @@ theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) (starRingEnd ℂ (coeff (e i))) • (InnerProductSpace.toDual ℂ H).symm ((e i).1.2) let x : Hn (H := H) n := (WithLp.equiv _ _).symm xFun let u : Hn (H := H) n := (WithLp.equiv _ _).symm uFun - let Aamp : StarSubalgebra ℂ (Hn (H := H) n →L[ℂ] Hn (H := H) n) := + let Aamp : NonUnitalStarSubalgebra ℂ (Hn (H := H) n →L[ℂ] Hn (H := H) n) := A.map (diagonalStarAlgHom (H := H) n) + have hndAmp : ActsNondegenerately (Aamp : Set (Hn (H := H) n →L[ℂ] Hn (H := H) n)) := by + have hcoe : (Aamp : Set (Hn (H := H) n →L[ℂ] Hn (H := H) n)) = + diagonal (H := H) (n := n) '' (A : Set B) := by + simp [Aamp, diagonalStarAlgHom] + rw [hcoe] + exact actsNondegenerately_image_diagonal (H := H) hnd n let g : (Hn (H := H) n) →L[ℂ] ℂ := (InnerProductSpace.toDual ℂ (Hn (H := H) n)) u have h_eval (S : B) : @@ -365,7 +446,7 @@ theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) -- The diagonal embedding of `T` lies in the double commutant of `Aamp`. have hdiag_mem : diagonal (H := H) (n := n) T ∈ - Set.centralizer (Set.centralizer ((Aamp : StarSubalgebra ℂ _ ) : Set _)) := by + Set.centralizer (Set.centralizer ((Aamp : NonUnitalStarSubalgebra ℂ _ ) : Set _)) := by have hT' : T ∈ Set.centralizer (Set.centralizer (A : Set B)) := hT have hdiag : diagonal (H := H) (n := n) T ∈ (diagonal (H := H) (n := n) '' (A : Set B)).centralizer.centralizer := @@ -388,6 +469,7 @@ theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) mem_cyclicSubspace_of_preservesReducingSubspaces (H := Hn (H := H) n) (A := Aamp) + hndAmp (T := diagonal (H := H) (n := n) T) hPres x -- Conclude: `f(T) = 0` since `g` vanishes on the cyclic subspace containing `diagonal T x`. @@ -398,4 +480,26 @@ theorem doubleCommutant_eq_of_isWOTClosed (A : StarSubalgebra ℂ B) exact hneq (by simp only [TWOT, f] at this ⊢; exact this) · exact Set.subset_centralizer_centralizer +/-- **A non-degenerate WOT-closed `*`-subalgebra automatically contains `1`.** This is the exact +extra content of the non-degenerate form over the unital one: granted, the non-degenerate form +implies the unital one, and conversely — every commutant contains `1`, so `A = A''` forces +`1 ∈ A`. -/ +theorem one_mem_of_isWOTClosed (A : NonUnitalStarSubalgebra ℂ B) + (hnd : ActsNondegenerately (A : Set B)) + (hA : IsWOTClosed (H := H) (A : Set B)) : + (1 : B) ∈ A := by + have h : (1 : B) ∈ (A : Set B) := by + rw [← doubleCommutant_eq_of_isWOTClosed A hnd hA] + exact Set.one_mem_centralizer + exact h + +/-- Unital special case of `doubleCommutant_eq_of_isWOTClosed`: a WOT-closed unital +`*-`subalgebra equals its own double commutant. Since `1 ∈ A`, the algebra acts +non-degenerately and the general theorem applies. -/ +theorem doubleCommutant_eq_of_isWOTClosed_starSubalgebra (A : StarSubalgebra ℂ B) + (hA : IsWOTClosed (H := H) (A : Set B)) : + Set.centralizer (Set.centralizer (A : Set B)) = (A : Set B) := + doubleCommutant_eq_of_isWOTClosed A.toNonUnitalStarSubalgebra + (actsNondegenerately_of_one_mem A.one_mem) hA + end WOTClosedSubalgebra diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean index ef140f6..9c27382 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean @@ -223,11 +223,11 @@ theorem OrthEquivFam.mem_sotClosure_adjoin (hF : OrthEquivFam N e F) (he : IsMinimalProjection N e) (htop : (Submodule.span ℂ {y | ∃ f ∈ F, ∃ x, f x = y}).topologicalClosure = ⊤) {a : H →L[ℂ] H} (ha : a ∈ N) : - (⟨a⟩ : ContinuousLinearMapSOT H) ∈ closure (Set.toSOT + (StrongOperatorTopology.toSOTEquiv a : H →SLₚₜ[RingHom.id ℂ] H) ∈ closure (Set.toSOT (StarAlgebra.adjoin ℂ (Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2)) : Set (H →L[ℂ] H))) := by set S := Set.range (fun pq : F × F => hF.matrixUnit pq.1 pq.2) with hSdef - apply SOTClosedSubalgebra.mem_sotClosure_of_mem_doubleCommutant (StarAlgebra.adjoin ℂ S) a + apply SOTClosedSubalgebra.mem_sotClosure_of_mem_doubleCommutant_starSubalgebra (StarAlgebra.adjoin ℂ S) a have hunion : S ∪ star S ⊆ (StarAlgebra.adjoin ℂ S : Set (H →L[ℂ] H)) := by refine Set.union_subset (StarAlgebra.subset_adjoin ℂ S) ?_ intro y hy diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/FiniteRank.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/FiniteRank.lean new file mode 100644 index 0000000..8e878fb --- /dev/null +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/FiniteRank.lean @@ -0,0 +1,150 @@ +module + +public import Mathlib.Analysis.InnerProductSpace.Adjoint + +/-! +# Finite-rank operators as a non-unital `*`-subalgebra + +An operator on a Hilbert space has *finite rank* if its range is finite-dimensional. The +finite-rank operators form a `*`-subalgebra `F(H)` of `B(H)` which, on an infinite-dimensional +`H`, does **not** contain `1` and yet acts non-degenerately: it is the standard witness that +non-degeneracy is strictly weaker than unitality, and hence that the non-unital form of the +bicommutant theorem has content the unital form does not reach. + +The only step that is not immediate is closure under the adjoint. It uses that `T†` annihilates +`(ran T)ᗮ` (`ContinuousLinearMap.orthogonal_range`), so that `ran T† = T†(ran T)` is the image of +a finite-dimensional subspace. + +## Main definitions + +* `InnerProductSpace.IsFiniteRank`: the operator has finite-dimensional range. +* `InnerProductSpace.finiteRankOperators`: the finite-rank operators, bundled as a + `NonUnitalStarSubalgebra ℂ (H →L[ℂ] H)`. + +## Main results + +* `InnerProductSpace.rankOne_mem_finiteRankOperators`: every rank-one operator `|x⟩⟨y|` lies in + `F(H)`. +* `InnerProductSpace.one_notMem_finiteRankOperators`: on an infinite-dimensional `H`, `1 ∉ F(H)`. + +The results combining `F(H)` with the rest of the bicommutant development — that it acts +non-degenerately, and that `F(H)' = ℂ1` and hence `F(H)'' = B(H)` — live in +`QuantumSystem.Algebra.Star.DoubleCommutant.TFAE`: they consume declarations from other +`ForMathlib` files, and `ForMathlib` files import Mathlib only. +-/ + +@[expose] public section + +namespace InnerProductSpace + +variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] + +/-- An operator has **finite rank** if its range is finite-dimensional. -/ +def IsFiniteRank (T : H →L[ℂ] H) : Prop := + FiniteDimensional ℂ (LinearMap.range (T : H →ₗ[ℂ] H)) + +lemma isFiniteRank_zero : IsFiniteRank (0 : H →L[ℂ] H) := by + have h : LinearMap.range ((0 : H →L[ℂ] H) : H →ₗ[ℂ] H) = ⊥ := by simp + rw [IsFiniteRank, h] + infer_instance + +lemma IsFiniteRank.add {S T : H →L[ℂ] H} (hS : IsFiniteRank S) (hT : IsFiniteRank T) : + IsFiniteRank (S + T) := by + haveI : FiniteDimensional ℂ (LinearMap.range (S : H →ₗ[ℂ] H)) := hS + haveI : FiniteDimensional ℂ (LinearMap.range (T : H →ₗ[ℂ] H)) := hT + refine Submodule.finiteDimensional_of_le (S₂ := LinearMap.range (S : H →ₗ[ℂ] H) ⊔ + LinearMap.range (T : H →ₗ[ℂ] H)) ?_ + rintro _ ⟨x, rfl⟩ + exact Submodule.add_mem_sup ⟨x, rfl⟩ ⟨x, rfl⟩ + +/-- Multiplying a finite-rank operator on the left keeps the rank finite: the range only shrinks +under the image. -/ +lemma IsFiniteRank.mul_left {T : H →L[ℂ] H} (hT : IsFiniteRank T) (S : H →L[ℂ] H) : + IsFiniteRank (S * T) := by + haveI : FiniteDimensional ℂ (LinearMap.range (T : H →ₗ[ℂ] H)) := hT + refine Submodule.finiteDimensional_of_le + (S₂ := (LinearMap.range (T : H →ₗ[ℂ] H)).map (S : H →ₗ[ℂ] H)) ?_ + rintro _ ⟨x, rfl⟩ + exact ⟨T x, ⟨x, rfl⟩, rfl⟩ + +/-- Multiplying a finite-rank operator on the right keeps the rank finite: the range is unchanged +or smaller. -/ +lemma IsFiniteRank.mul_right {T : H →L[ℂ] H} (hT : IsFiniteRank T) (S : H →L[ℂ] H) : + IsFiniteRank (T * S) := by + haveI : FiniteDimensional ℂ (LinearMap.range (T : H →ₗ[ℂ] H)) := hT + refine Submodule.finiteDimensional_of_le (S₂ := LinearMap.range (T : H →ₗ[ℂ] H)) ?_ + rintro _ ⟨x, rfl⟩ + exact ⟨S x, rfl⟩ + +lemma IsFiniteRank.smul {T : H →L[ℂ] H} (hT : IsFiniteRank T) (c : ℂ) : + IsFiniteRank (c • T) := by + haveI : FiniteDimensional ℂ (LinearMap.range (T : H →ₗ[ℂ] H)) := hT + refine Submodule.finiteDimensional_of_le (S₂ := LinearMap.range (T : H →ₗ[ℂ] H)) ?_ + rintro _ ⟨x, rfl⟩ + exact Submodule.smul_mem _ _ ⟨x, rfl⟩ + +/-- The rank-one operator `|x⟩⟨y| : z ↦ ⟪y, z⟫ • x` has finite rank: its range lies in +`span {x}`. -/ +lemma isFiniteRank_rankOne (x y : H) : IsFiniteRank (rankOne ℂ x y : H →L[ℂ] H) := by + refine Submodule.finiteDimensional_of_le (S₂ := Submodule.span ℂ {x}) ?_ + rintro _ ⟨z, rfl⟩ + simp only [ContinuousLinearMap.coe_coe, rankOne_apply] + exact Submodule.smul_mem _ _ (Submodule.mem_span_singleton_self x) + +variable [CompleteSpace H] + +/-- The adjoint of a finite-rank operator has finite rank. Since `T†` annihilates `(ran T)ᗮ`, its +range is the image of the finite-dimensional subspace `ran T`. -/ +lemma IsFiniteRank.adjoint {T : H →L[ℂ] H} (hT : IsFiniteRank T) : + IsFiniteRank (ContinuousLinearMap.adjoint T) := by + haveI : FiniteDimensional ℂ (LinearMap.range (T : H →ₗ[ℂ] H)) := hT + refine Submodule.finiteDimensional_of_le + (S₂ := (LinearMap.range (T : H →ₗ[ℂ] H)).map + ((ContinuousLinearMap.adjoint T : H →L[ℂ] H) : H →ₗ[ℂ] H)) ?_ + rintro _ ⟨x, rfl⟩ + obtain ⟨p, hp, q, hq, rfl⟩ := + Submodule.exists_add_mem_mem_orthogonal (K := LinearMap.range (T : H →ₗ[ℂ] H)) x + have hq0 : ContinuousLinearMap.adjoint T q = 0 := by + have hmem : q ∈ LinearMap.ker ((ContinuousLinearMap.adjoint T : H →L[ℂ] H) : H →ₗ[ℂ] H) := by + rw [← ContinuousLinearMap.orthogonal_range] + exact hq + simpa using hmem + exact ⟨p, hp, by simp [map_add, hq0]⟩ + +/-- **The finite-rank operators `F(H)`**, as a non-unital `*`-subalgebra of `B(H)`. It is a +two-sided ideal, but only the `*`-subalgebra structure is recorded here — that is what the +bicommutant theorem consumes. -/ +noncomputable def finiteRankOperators : NonUnitalStarSubalgebra ℂ (H →L[ℂ] H) where + carrier := {T | IsFiniteRank T} + add_mem' := IsFiniteRank.add + zero_mem' := isFiniteRank_zero + mul_mem' := fun {S _} _ hT => hT.mul_left S + smul_mem' := fun c _ hT => IsFiniteRank.smul hT c + star_mem' := fun hT => IsFiniteRank.adjoint hT + +@[simp] lemma mem_finiteRankOperators_iff {T : H →L[ℂ] H} : + T ∈ finiteRankOperators (H := H) ↔ IsFiniteRank T := Iff.rfl + +/-- Every rank-one operator `|x⟩⟨y|` lies in `F(H)`. -/ +lemma rankOne_mem_finiteRankOperators (x y : H) : + (rankOne ℂ x y : H →L[ℂ] H) ∈ finiteRankOperators (H := H) := + isFiniteRank_rankOne x y + +/-- **`F(H)` is not unital** when `H` is infinite-dimensional: `1` has range `H`. + +Together with `InnerProductSpace.actsNondegenerately_finiteRankOperators` (proved in +`QuantumSystem.Algebra.Star.DoubleCommutant.TFAE`) this exhibits a `*`-subalgebra to which the +non-unital bicommutant theorem applies and the unital one does not. -/ +theorem one_notMem_finiteRankOperators (h : ¬ FiniteDimensional ℂ H) : + (1 : H →L[ℂ] H) ∉ finiteRankOperators (H := H) := by + intro hmem + refine h ?_ + have hr : LinearMap.range ((1 : H →L[ℂ] H) : H →ₗ[ℂ] H) = ⊤ := by + ext y + simp only [Submodule.mem_top, iff_true, LinearMap.mem_range] + exact ⟨y, rfl⟩ + haveI : FiniteDimensional ℂ (LinearMap.range ((1 : H →L[ℂ] H) : H →ₗ[ℂ] H)) := hmem + rw [hr] at this + exact (Submodule.topEquiv (R := ℂ) (M := H)).finiteDimensional + +end InnerProductSpace diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean index d168418..80ee6f4 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/InvariantSubspace.lean @@ -26,6 +26,8 @@ This file provides a minimal API for invariant / reducing subspaces for a set of `Kᗮ` is invariant under `T`. * `starProjection_mem_centralizer_of_isReducing`: if `K` is reducing for `S`, then `K.starProjection ∈ Set.centralizer S`. +* `ActsNondegenerately S`: no nonzero vector is annihilated by every element of `S`; the + hypothesis of the non-unital double commutant theorem. -/ @[expose] public section @@ -175,4 +177,30 @@ lemma starProjection_mem_centralizer_of_isReducing end WithComplete +section Nondegenerate + +/-- A set of operators `S` *acts non-degenerately* on `H` if the only vector annihilated by +every element of `S` is `0`. + +This is strictly weaker than `1 ∈ S` (see `actsNondegenerately_of_one_mem`): for example the +compact operators act non-degenerately on an infinite-dimensional `H` without containing `1`. +It is the hypothesis under which the double commutant theorem holds for a possibly non-unital +`*`-subalgebra. -/ +def ActsNondegenerately (S : Set (H →L[ℂ] H)) : Prop := + ∀ x : H, (∀ T ∈ S, T x = 0) → x = 0 + +/-- A set of operators containing the identity acts non-degenerately. -/ +lemma actsNondegenerately_of_one_mem {S : Set (H →L[ℂ] H)} + (h : (1 : H →L[ℂ] H) ∈ S) : ActsNondegenerately S := by + intro x hx + simpa using hx 1 h + +/-- Non-degeneracy is monotone: it passes from a set to any superset. -/ +lemma ActsNondegenerately.mono {S S' : Set (H →L[ℂ] H)} (hSS' : S ⊆ S') + (hS : ActsNondegenerately S) : ActsNondegenerately S' := by + intro x hx + exact hS x fun T hT => hx T (hSS' hT) + +end Nondegenerate + end InnerProductSpace diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean index 5580ecb..2bc06b2 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/RankOne.lean @@ -1,7 +1,6 @@ module public import Mathlib.Analysis.InnerProductSpace.LinearMap -public import Mathlib.LinearAlgebra.FiniteDimensional.Basic /-! # Operators commuting with all rank-one operators are scalar @@ -9,9 +8,10 @@ public import Mathlib.LinearAlgebra.FiniteDimensional.Basic A continuous linear operator on an inner product space that commutes with every rank-one operator `|x⟩⟨y|` is a scalar multiple of the identity. This is the elementary computation behind "the centre of `B(H)` is trivial" and, downstream, behind the factor property of the tensor -von Neumann algebras `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)`. We also record that a rank-one operator has -finite- (in fact one-) dimensional range, used to see that a rank-one minimal projection of `B(H)` -has one-dimensional multiplicity space. +von Neumann algebras `B(H₁) ⊗̄ 1` and `1 ⊗̄ B(H₂)`. That a rank-one operator has finite- (in fact +at most one-) dimensional range is recorded as +`InnerProductSpace.isFiniteRank_rankOne` in +`QuantumSystem.ForMathlib.Analysis.InnerProductSpace.FiniteRank`. ## Notation @@ -44,18 +44,3 @@ theorem ContinuousLinearMap.exists_eq_smul_one_of_forall_rankOne_comm calc S x = (inner ℂ y y)⁻¹ • ((inner ℂ y y : ℂ) • S x) := (inv_smul_smul₀ hyy _).symm _ = (inner ℂ y y)⁻¹ • (inner ℂ y (S y) • x) := by rw [h1] _ = (inner ℂ y (S y) / inner ℂ y y) • x := by rw [smul_smul, div_eq_inv_mul] - -/-- The range of a rank-one operator `|u⟩⟨u|` is finite-dimensional (it is contained in the line -`ℂ ∙ u`). For a unit vector this is the one-dimensional multiplicity space of the corresponding -minimal projection of `B(H)`. -/ -theorem finiteDimensional_range_rankOne {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] - (u : H) : - FiniteDimensional ℂ (LinearMap.range ((InnerProductSpace.rankOne ℂ u u : H →L[ℂ] H) - : H →ₗ[ℂ] H)) := by - have hle : LinearMap.range ((InnerProductSpace.rankOne ℂ u u : H →L[ℂ] H) : H →ₗ[ℂ] H) - ≤ Submodule.span ℂ {u} := by - rw [LinearMap.range_le_iff_comap, eq_top_iff] - intro z _ - simp only [Submodule.mem_comap, ContinuousLinearMap.coe_coe, InnerProductSpace.rankOne_apply] - exact Submodule.smul_mem _ _ (Submodule.mem_span_singleton_self u) - exact Submodule.finiteDimensional_of_le hle diff --git a/QuantumSystem/ForMathlib/Analysis/LocallyConvex/StrongOperatorTopology.lean b/QuantumSystem/ForMathlib/Analysis/LocallyConvex/StrongOperatorTopology.lean index 76a94da..9e2e4ee 100644 --- a/QuantumSystem/ForMathlib/Analysis/LocallyConvex/StrongOperatorTopology.lean +++ b/QuantumSystem/ForMathlib/Analysis/LocallyConvex/StrongOperatorTopology.lean @@ -2,39 +2,42 @@ module public import Mathlib.Analysis.Complex.Basic public import Mathlib.Analysis.InnerProductSpace.Defs -public import Mathlib.Analysis.LocallyConvex.WeakOperatorTopology +public import Mathlib.Topology.Algebra.Module.Spaces.PointwiseConvergenceCLM @[expose] public section /-! # Strong operator topology closedness of commutants -This file provides SOT-continuity of left/right multiplication by a fixed bounded operator, -consequently showing that commutants (`Set.centralizer`) and double commutants are SOT-closed. +This file shows that commutants (`Set.centralizer`) and double commutants are closed in the +strong operator topology (SOT). -The strong operator topology (SOT) on `B(H) = H →L[ℂ] H` is the topology of pointwise convergence -in the norm topology: a net `T_α → T` in SOT iff `∀ x, T_α x → T x` in norm. +The strong operator topology on `B(H) = H →L[ℂ] H` is the topology of pointwise convergence +in the norm topology: a net `T_α → T` in SOT iff `∀ x, T_α x → T x` in norm. Mathlib already +provides this topology as `PointwiseConvergenceCLM` (notation `H →SLₚₜ[RingHom.id ℂ] H`), a type +copy of `H →L[ℂ] H` carrying the topology of uniform convergence on finite sets; this file uses +that type copy rather than introducing another one. ## Main definitions -* `ContinuousLinearMapSOT`: type copy of `H →L[ℂ] H` equipped with the SOT. -* `ContinuousLinearMapSOT.inducingFn`: the inducing function for SOT (evaluation at all points). -* `leftMulSOT`, `rightMulSOT`: left/right multiplication on the SOT type-copy. -* `IsSOTClosed`: a predicate for subsets closed in the SOT. +* `toSOTEquiv`: the linear equivalence from `B(H)` to the SOT type-copy. * `Set.toSOT`: view a subset of operators inside the SOT type-copy. +* `IsSOTClosed`: a predicate for subsets closed in the SOT. ## Main results -* `continuous_leftMulSOT`, `continuous_rightMulSOT`: multiplication by a fixed operator is - SOT-continuous. +* `Set.toSOT_eq_image`: `Set.toSOT` is the image of the subset under `toSOTEquiv`. * `isSOTClosed_centralizer`: the commutant of any set is SOT-closed. * `isSOTClosed_centralizer_centralizer`: double commutants are SOT-closed. -## Comparison with WOT +Left and right multiplication by a fixed operator are SOT-continuous; they are Mathlib's +`PointwiseConvergenceCLM.postcomp` and `PointwiseConvergenceCLM.precomp`, which are already +bundled as continuous linear maps, so this file uses them directly. -SOT is finer than WOT: SOT convergence implies WOT convergence. This file does not develop the -SOT→WOT comparison map; it is imported/used elsewhere when relating SOT-closedness to -WOT-closedness for *-subalgebras. +The comparison with the weak operator topology — SOT is finer than WOT, so every WOT-closed set +is SOT-closed (`continuous_sotToWOT`, `isSOTClosed_of_isWOTClosed`) — lives in +`QuantumSystem.Algebra.Star.DoubleCommutant.SOTClosedSubAlgebra`, the first file that may import +both type copies: this file, like every `ForMathlib` file, imports Mathlib only. -/ namespace StrongOperatorTopology @@ -44,161 +47,67 @@ open scoped Topology variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] local notation "B" => (H →L[ℂ] H) +local notation "BSOT" => (H →SLₚₜ[RingHom.id ℂ] H) -/-- Type copy of `H →L[ℂ] H` equipped with the strong operator topology (pointwise norm convergence). -/ -@[ext] -structure ContinuousLinearMapSOT (H : Type*) [NormedAddCommGroup H] [InnerProductSpace ℂ H] where - /-- The underlying continuous linear map. -/ - toCLM : H →L[ℂ] H - -local notation "BSOT" => ContinuousLinearMapSOT H - -namespace ContinuousLinearMapSOT - -variable {H : Type*} [NormedAddCommGroup H] [InnerProductSpace ℂ H] - -/-- Coercion from `BSOT` back to `B`. -/ -instance : Coe (ContinuousLinearMapSOT H) (H →L[ℂ] H) := ⟨toCLM⟩ - -/-- Coercion from `BSOT` to a function `H → H`. -/ -instance : CoeFun (ContinuousLinearMapSOT H) (fun _ => H → H) := ⟨fun T x => T.toCLM x⟩ - -/-- Addition on `BSOT`. -/ -instance : Add (ContinuousLinearMapSOT H) := ⟨fun T S => ⟨T.toCLM + S.toCLM⟩⟩ - -/-- Scalar multiplication on `BSOT`. -/ -instance : SMul ℂ (ContinuousLinearMapSOT H) := ⟨fun c T => ⟨c • T.toCLM⟩⟩ - -/-- Zero element on `BSOT`. -/ -instance : Zero (ContinuousLinearMapSOT H) := ⟨⟨0⟩⟩ - -@[simp] lemma add_toCLM (T S : ContinuousLinearMapSOT H) : (T + S).toCLM = T.toCLM + S.toCLM := rfl -@[simp] lemma smul_toCLM (c : ℂ) (T : ContinuousLinearMapSOT H) : (c • T).toCLM = c • T.toCLM := rfl -@[simp] lemma zero_toCLM : (0 : ContinuousLinearMapSOT H).toCLM = 0 := rfl -@[simp] lemma mk_toCLM (T : H →L[ℂ] H) : (ContinuousLinearMapSOT.mk T).toCLM = T := rfl - -/-- The inducing function for SOT: evaluation at all points. -/ -def inducingFn : ContinuousLinearMapSOT H → (H → H) := fun T x => T x - -/-- The SOT on `BSOT` is the initial topology induced by pointwise evaluation. -/ -instance : TopologicalSpace (ContinuousLinearMapSOT H) := - TopologicalSpace.induced inducingFn Pi.topologicalSpace - -/-- The SOT is induced by `inducingFn`. -/ -lemma isInducing_inducingFn : - Topology.IsInducing (inducingFn (H := H)) := - ⟨rfl⟩ +/-- The linear equivalence from `B(H)` to the SOT type-copy. It is the identity on the underlying +operators; only the topology differs. -/ +noncomputable def toSOTEquiv : B ≃ₗ[ℂ] BSOT := LinearEquiv.refl ℂ (H →L[ℂ] H) -/-- `inducingFn` is injective. -/ -lemma inducingFn_injective : Function.Injective (inducingFn (H := H)) := by - intro T S h - ext x - exact congrFun h x +@[simp] lemma toSOTEquiv_apply (T : B) (x : H) : (toSOTEquiv (H := H) T) x = T x := rfl -/-- The SOT on `B(H)` is T2 (Hausdorff) since it embeds into a product of T2 spaces. -/ -instance : T2Space (ContinuousLinearMapSOT H) := by - have hemb : Topology.IsEmbedding (inducingFn (H := H)) := - ⟨isInducing_inducingFn (H := H), inducingFn_injective (H := H)⟩ - exact hemb.t2Space - -/-- Evaluation at a point `x` is SOT-continuous. -/ -lemma continuous_eval (x : H) : Continuous (fun T : ContinuousLinearMapSOT H => T x) := by - have : (fun T : ContinuousLinearMapSOT H => T x) = (fun f : H → H => f x) ∘ inducingFn := rfl - rw [this] - exact (continuous_apply x).comp (isInducing_inducingFn (H := H)).continuous - -/-- Characterization of SOT-continuity: a map is SOT-continuous iff all pointwise evaluations are. -/ -lemma continuous_of_forall_eval_continuous {g : ContinuousLinearMapSOT H → ContinuousLinearMapSOT H} - (h : ∀ x : H, Continuous (fun T => g T x)) : Continuous g := by - rw [continuous_induced_rng] - exact continuous_pi h - -end ContinuousLinearMapSOT - -open ContinuousLinearMapSOT in -/-- A subset of `B(H)` is SOT-closed if its image in `BSOT` is closed. -/ -def IsSOTClosed (S : Set B) : Prop := - IsClosed {T : BSOT | T.toCLM ∈ S} +@[simp] lemma toSOTEquiv_symm_apply (T : BSOT) (x : H) : + ((toSOTEquiv (H := H)).symm T) x = T x := rfl /-- View a subset of operators inside the SOT type-copy. -/ def Set.toSOT (S : Set B) : Set BSOT := - {T | T.toCLM ∈ S} + {T | (toSOTEquiv (H := H)).symm T ∈ S} lemma Set.mem_toSOT_iff {S : Set B} {T : BSOT} : - T ∈ Set.toSOT (H := H) S ↔ T.toCLM ∈ S := Iff.rfl - -/-- Left multiplication on `BSOT`. -/ -def leftMulSOT (a : B) : BSOT → BSOT := - fun T => ⟨a * T.toCLM⟩ - -/-- Right multiplication on `BSOT`. -/ -def rightMulSOT (a : B) : BSOT → BSOT := - fun T => ⟨T.toCLM * a⟩ - -@[simp] lemma leftMulSOT_apply (a : B) (T : BSOT) (x : H) : - (leftMulSOT (H := H) a T) x = a (T x) := by - simp [leftMulSOT, ContinuousLinearMap.mul_apply] - -@[simp] lemma rightMulSOT_apply (a : B) (T : BSOT) (x : H) : - (rightMulSOT (H := H) a T) x = T (a x) := by - simp [rightMulSOT, ContinuousLinearMap.mul_apply] - -/-- Left multiplication by a fixed operator is SOT-continuous. -/ -lemma continuous_leftMulSOT (a : B) : Continuous (leftMulSOT (H := H) a) := by - refine ContinuousLinearMapSOT.continuous_of_forall_eval_continuous (H := H) ?_ - intro x - have : (fun T : BSOT => (leftMulSOT (H := H) a T) x) = (fun y => a y) ∘ (fun T => T x) := by - ext T - simp - rw [this] - exact a.continuous.comp (ContinuousLinearMapSOT.continuous_eval (H := H) x) - -/-- Right multiplication by a fixed operator is SOT-continuous. -/ -lemma continuous_rightMulSOT (a : B) : Continuous (rightMulSOT (H := H) a) := by - refine ContinuousLinearMapSOT.continuous_of_forall_eval_continuous (H := H) ?_ - intro x - have : (fun T : BSOT => (rightMulSOT (H := H) a T) x) = (fun T => T (a x)) := by - ext T - simp - rw [this] - exact ContinuousLinearMapSOT.continuous_eval (H := H) (a x) - -/-- The set of operators (in BSOT) commuting with a fixed operator `a` is closed. -/ -lemma isClosed_commutesWithSOT (a : B) : - IsClosed {T : BSOT | leftMulSOT (H := H) a T = rightMulSOT (H := H) a T} := - isClosed_eq (continuous_leftMulSOT (H := H) a) (continuous_rightMulSOT (H := H) a) + T ∈ Set.toSOT (H := H) S ↔ (toSOTEquiv (H := H)).symm T ∈ S := + Iff.rfl + +/-- `Set.toSOT` is the image of the subset under `toSOTEquiv`. -/ +lemma Set.toSOT_eq_image (S : Set B) : + Set.toSOT (H := H) S = (toSOTEquiv (H := H)) '' S := by + ext T + constructor + · intro h + exact ⟨_, h, (toSOTEquiv (H := H)).apply_symm_apply T⟩ + · rintro ⟨x, hx, rfl⟩ + simpa [Set.mem_toSOT_iff] using hx + +/-- A subset of `B(H)` is SOT-closed if its image in the SOT type-copy is closed. -/ +def IsSOTClosed (S : Set B) : Prop := + IsClosed (Set.toSOT (H := H) S) +/-- SOT-closedness stated as closedness of the image, the form in which the strong operator +topology is usually phrased. -/ +lemma isSOTClosed_iff_isClosed_image (S : Set B) : + IsSOTClosed (H := H) S ↔ + IsClosed (ContinuousLinearMap.toPointwiseConvergenceCLM ℂ (RingHom.id ℂ) H H '' S) := by + rw [IsSOTClosed, Set.toSOT_eq_image] + rfl /-- The commutant `Set.centralizer S` is SOT-closed. -/ lemma isSOTClosed_centralizer (S : Set B) : IsSOTClosed (H := H) (Set.centralizer S) := by - unfold IsSOTClosed - -- Rewrite the SOT-image of the centralizer as an intersection. - have : {T : BSOT | T.toCLM ∈ Set.centralizer S} = - ⋂ a : B, ⋂ _ : a ∈ S, {T : BSOT | leftMulSOT (H := H) a T = rightMulSOT (H := H) a T} := by + -- Express the commutant as an intersection of commuting constraints, each closed because + -- left and right multiplication are SOT-continuous. + have key : Set.toSOT (H := H) (Set.centralizer S) = + ⋂ a ∈ S, {T : BSOT | PointwiseConvergenceCLM.postcomp H a T + = PointwiseConvergenceCLM.precomp H a T} := by ext T + simp only [Set.mem_toSOT_iff, Set.mem_centralizer_iff, Set.mem_iInter, Set.mem_setOf_eq] constructor - · intro hT - refine Set.mem_iInter.2 ?_ - intro a - refine Set.mem_iInter.2 ?_ - intro ha - have hcomm : a * T.toCLM = T.toCLM * a := Set.mem_centralizer_iff.mp hT a ha - simp only [Set.mem_setOf_eq, leftMulSOT, rightMulSOT] + · intro hT a ha + ext x + simpa [ContinuousLinearMap.mul_apply] using congrArg (fun R => R x) (hT a ha) + · intro hT a ha ext x - simp [ContinuousLinearMap.mul_apply, hcomm] - · intro hT - refine Set.mem_centralizer_iff.mpr ?_ - intro a ha - have h := Set.mem_iInter.1 (Set.mem_iInter.1 hT a) ha - simp only [Set.mem_setOf_eq, leftMulSOT, rightMulSOT] at h - have := congrArg ContinuousLinearMapSOT.toCLM h - simpa using this - rw [this] - refine isClosed_iInter ?_ - intro a - refine isClosed_iInter ?_ - intro _ - exact isClosed_commutesWithSOT (H := H) a + simpa [ContinuousLinearMap.mul_apply] using congrArg (fun R => R x) (hT a ha) + rw [IsSOTClosed, key] + exact isClosed_biInter fun a _ => + isClosed_eq (PointwiseConvergenceCLM.postcomp H a).continuous + (PointwiseConvergenceCLM.precomp H a).continuous /-- Any double commutant is SOT-closed. -/ theorem isSOTClosed_centralizer_centralizer (S : Set B) : diff --git a/QuantumSystem/ForMathlib/Analysis/LocallyConvex/WeakOperatorTopology.lean b/QuantumSystem/ForMathlib/Analysis/LocallyConvex/WeakOperatorTopology.lean index d192bf8..86e8b69 100644 --- a/QuantumSystem/ForMathlib/Analysis/LocallyConvex/WeakOperatorTopology.lean +++ b/QuantumSystem/ForMathlib/Analysis/LocallyConvex/WeakOperatorTopology.lean @@ -28,6 +28,9 @@ consequently showing that commutants (`Set.centralizer`) and double commutants a * `continuous_leftMulWOT`, `continuous_rightMulWOT`: multiplication by a fixed operator is WOT-continuous. * `isClosed_commutesWithWOT`: the set of operators commuting with a fixed operator is WOT-closed. +* `Set.toWOT_eq_image`: `Set.toWOT` is the image of the subset under `toWOTEquiv`. +* `isWOTClosed_iff_isClosed_image`: WOT-closedness as closedness of the image under the canonical + inclusion `ContinuousLinearMap.toWOTCLM`. * `isWOTClosed_centralizer`: the commutant of any set is WOT-closed. * `isWOTClosed_centralizer_centralizer`: double commutants are WOT-closed. * `exists_wotCLM_sep_of_isClosed_submodule`: a finite-coordinate separation lemma for WOT-closed @@ -104,10 +107,29 @@ lemma Set.mem_toWOT_iff {S : Set B} {T : BWOT} : T ∈ Set.toWOT (H := H) S ↔ (toWOTEquiv (H := H)).symm T ∈ S := by rfl +/-- `Set.toWOT` is the image of the subset under `toWOTEquiv`. -/ +lemma Set.toWOT_eq_image (S : Set B) : + Set.toWOT (H := H) S = (toWOTEquiv (H := H)) '' S := by + ext T + constructor + · intro h + exact ⟨_, h, (toWOTEquiv (H := H)).apply_symm_apply T⟩ + · rintro ⟨x, hx, rfl⟩ + simpa [Set.mem_toWOT_iff] using hx + /-- A subset of operators is WOT-closed if its image in the WOT type-copy is closed. -/ def IsWOTClosed (S : Set B) : Prop := IsClosed (Set.toWOT (H := H) S) +/-- WOT-closedness stated as closedness of the image under the canonical inclusion, the form in +which the weak operator topology is usually phrased. -/ +lemma isWOTClosed_iff_isClosed_image (S : Set B) : + IsWOTClosed (H := H) S ↔ + IsClosed (ContinuousLinearMapWOT.ContinuousLinearMap.toWOTCLM + (σ := RingHom.id ℂ) (E := H) (F := H) '' S) := by + rw [IsWOTClosed, Set.toWOT_eq_image] + rfl + /-- The commutant `Set.centralizer S` is WOT-closed. -/ lemma isWOTClosed_centralizer (S : Set B) : IsWOTClosed (H := H) (Set.centralizer S) := by -- Express the commutant as an intersection of commuting constraints. From dd26be4cdf72ef60220c935715ff13ad1322ae6a Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 19:03:05 +0000 Subject: [PATCH 107/113] docs: add extraction note for the von Neumann bicommutant theorem Sources: SHI12, LAN98, HIA20, KOS13, SOR23, VN30, CON00. Records the sources.md retrieval log for this corpus and the docs/math/README.md index row, with the implemented-as back-link to DoubleCommutant.bicommutant_tfae. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .claude/skills/math-extract/sources.md | 11 +- docs/math/README.md | 1 + docs/math/bicommutant-theorem.md | 718 +++++++++++++++++++++++++ 3 files changed, 727 insertions(+), 3 deletions(-) create mode 100644 docs/math/bicommutant-theorem.md diff --git a/.claude/skills/math-extract/sources.md b/.claude/skills/math-extract/sources.md index d88ac41..aaa2d73 100644 --- a/.claude/skills/math-extract/sources.md +++ b/.claude/skills/math-extract/sources.md @@ -70,13 +70,18 @@ different object is in the wrong file. | DL84 | S. Doplicher, R. Longo, *Standard and split inclusions of von Neumann algebras*, Invent. Math. 75 (1984) 493–536 | partial | `references/doplicher-longo-1984-standard-split/` | published | 2026-08-14 | GDZ digitization (volume `PPN356556735_0075`, article div `LOG_0034`, found via the METS file); MinerU `hybrid-engine --effort high`, pp. 1–14 of 44 (§0–§4); mineru-unchecked. locator Prop. 1.2: says joint cyclic-separating vectors exist *under* standard action / properly infinite commutants — citing it for bare "properly infinite on separable ℋ" (as KOE03 does at its source.txt 6666–6669) drops needed hypotheses. §9–10 (the non-split field theories) not converted. Its §0 phrases the split property's separation as `space-like separated by non-zero distance` and cites dB74, whose cached scope (§III, smooth boundaries + positive distance, free neutral massive scalar) is **narrower** than that paraphrase | <!-- Append below. Newest last. --> -| HM06 | H. Halvorson, M. Müger, *Algebraic Quantum Field Theory*, in *Handbook of the Philosophy of Physics*, arXiv math-ph/0602036 | retrieved | `references/arxiv-math-ph-0602036/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `reconstruction.tex`. Leaves "spacelike separated" **undefined** and writes the causal complement `O'` with no formula, so it cannot be cited for either. Its `\begin{fact}` (strictly ⇒ strongly spacelike separated) carries no proof and no citation. Prop. `frees` is stated for *strongly* but its proof's first line says *strictly* — a typo; the proposition as stated is proved | +| HM06 | H. Halvorson, M. Müger, *Algebraic Quantum Field Theory*, in *Handbook of the Philosophy of Physics*, arXiv math-ph/0602036 | retrieved | `references/arxiv-math-ph-0602036/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `reconstruction.tex`. Leaves "spacelike separated" **undefined** and writes the causal complement `O'` with no formula, so it cannot be cited for either. Its `\begin{fact}` (strictly ⇒ strongly spacelike separated) carries no proof and no citation. Prop. `frees` is stated for *strongly* but its proof's first line says *strictly* — a typo; the proposition as stated is proved. **Added 2026-08-16 (bicommutant run)**: it states the double commutant theorem in a **two**-condition form (WOT-closed ⟺ `R''=R`, no SOT) inside a `\begin{fact}`, with no proof and no citation, and elects the algebraic condition as its definition. **One of its facts is false as printed**: `If $S$ is a bounded, convex subset of $\bh$, then the weak, ultraweak, and norm closures of $S$ are the same` — the closed unit ball of `K(H)`, `dim H = ∞`, is norm-closed but weakly dense in the unit ball of `B(H)`. Deleting `norm` makes it true, and the corrected version is what a σ-weak/WOT argument would want, so citing the printed form imports the error. Also: its condition 2 is typed `$\alg(\alg{R}')'=\alg{R}$`, where the one-argument `\alg` swallows the parenthesis; its adjoint clause quantifies `x,y` over the *algebra* instead of the Hilbert space; and its weak/strong/ultraweak "seminorms" are written without absolute values | | GLRV99 | D. Guido, R. Longo, J. E. Roberts, R. Verch, *Charged sectors, spin and statistics in quantum field theory on curved spacetimes*, arXiv math-ph/9906019 | retrieved | `references/arxiv-math-ph-9906019/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `main.tex`. **Notation trap: `𝒪^⊥` denotes both the sieve `{𝒪₁ ∈ 𝒦 : 𝒪₁ ⊥ 𝒪}` (§3.1) and the point set `M ∖ J̄(𝒪)` (§2.1), in one paper.** Cross-reference errata: the Extension Theorem's proof cites "Lemma 3.A.4" where 3A.5 is needed and prints three spellings of one label; Lemma 3.6 says `dimension $\geq 2$` then treats dimension two as the remaining case; §3.5 refers to `hatduality` as a Lemma where the environment is a Proposition. locator §3.1 (`source.txt` 1218–1223): the axiom list for ⊥ is a),b),c) **only**, and the source says the list is a floor (`The necessary properties will be introduced as needed`); a **fourth** condition appears at `source.txt` 1878–1882, before Theorem 3.13 | | NAA13 | P. Naaijkens, *Quantum spin systems on infinite lattices*, arXiv 1311.2717 | retrieved | `references/arxiv-1311.2717/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; multi-file (`aqft.tex`, `qlattice.tex`, `opalg.tex`, …), macros in `qlattice.tex`. The only corpus source stating `𝒪 = 𝒪″` for double cones, and it states it without proof. Its `𝒫_f(Γ)` **contains `∅`**, with `𝒜(∅) = ℂI` fixed explicitly — so any claim that the lattice index set fails an existence-of-a-⊥-partner condition is false for *this* index set | | BGL93 | R. Brunetti, D. Guido, R. Longo, *Modular structure and duality in conformal quantum field theory*, arXiv funct-an/9302008 | retrieved | `references/arxiv-funct-an-9302008/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim; single source file `main.tex`. locator Cor. 2.7: discharged by `\proof Immediate, see [\ref(Long1)].` and conditional on Remark 2.6's spectral hypothesis — do not cite it as an unconditional type III₁ result. locator Thm 3.3: its proof cites a **Lemma 3.4 that does not exist**; Lemma 3.2 is meant. Its "distal split property" (§3 assumption (b)) is an **existential over one pair of regions**, not a metric strengthening of the separation relation. Its non-split net `ℬ(𝒪) = 𝒜(π⁻¹𝒪)` is attributed to a **private remark** of Buchholz, so no locator can ever exist for the attribution | | BFV01 | R. Brunetti, K. Fredenhagen, R. Verch, *The generally covariant locality principle*, arXiv math-ph/0112041 | retrieved | `references/arxiv-math-ph-0112041/` | arXiv | 2026-08-15 | arXiv LaTeX (rung 1), verbatim. **The distributed source contains two complete `\begin{document}…\end{document}` bodies** — `source.txt` lines 118–2851 and 2957–4225 (`source.flat.txt` offsets 3687 and 144453). Only the first is the compiled paper; the second is a shorter earlier draft that even defines `\frakA` differently. **Take every locator from the first body**, and expect `grep -F` to return 2 for shared passages — that is not a duplicate-quote defect. Its `𝒦(M,ḡ)` is defined by two conditions only (relatively compact, causally convex), and openness/connectedness/non-emptiness are forced only by the *next* sentence's demand that each region be an object of `𝔐`; the two readings give different index sets. `cf.\ condition $(ii)$` points at orientation-preservation where causal convexity is condition (i), in **both** bodies, so authorial | | BF26 | B. Blackadar, I. Farah, *Separable C\*-algebras Without the Countable Axiom of Choice*, arXiv:2602.15812 | retrieved | `references/arxiv-2602.15812/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; multi-file, macros in `measpreambleu.tex` (`\cstar`, `\cB`, `\cH`) and `25-Cstar-choice.tex` (`\sfS`). **locator `SepRepThm` is adjudicated: the theorem carries no proof.** `source.txt:589–592` shows `\begin{Theorem}\label{SepRepThm}` … `\end{Theorem}` followed directly by a commented-out paragraph — no `\begin{Proof}` environment anywhere after it. Its only justification is the preceding sentence, which establishes faithfulness and never mentions separability of the Hilbert space. The paper is ZF throughout, so its "separable Hilbert space" must be read topologically, not as "has a countable orthonormal basis" — it says itself that the two come apart without countable choice. Two typos: `L.states`' proof opens `$\varphi(x^*x)=\|x\|$` where ‖x‖² is meant (corrected three lines later in the same proof), and `Corollary~8.4.3` is cited to two different works (`blackadar2023hilbert` and `farah2023choice`). Cites three Blackadar works (*Operator Algebras*, *Real Analysis*, *Hilbert spaces*) that were not obtained; anything through those citations is tier (c) | 2026-08-16 | -| LAN98 | N. P. Landsman, *Lecture Notes on C\*-algebras, Hilbert C\*-modules and Quantum Mechanics*, arXiv math-ph/9807030 | retrieved | `references/arxiv-math-ph-9807030/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; heavy custom macros (`\ca`, `\Hs`, `\rep`, `\om`, `\A`, and a `\renewcommand{\H}`). Inner product conjugate-linear in the **first** argument. Two typos to reproduce in quotes: `non-separable in the nom-topology` (for `norm-`), and Lemma `lots` writes `$\om(A)=a$` where the quantified state is `$\om_a$`. States Krein–Milman **without proof**. Its faithful-state GNS proposition is about the compact operators specifically, not a general C\*-algebra — do not cite it as the general statement | 2026-08-16 | -| SHI12 | V. Shirbisheh, *Lectures on C\*-algebras*, arXiv:1211.3404 | retrieved | `references/arxiv-1211.3404/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; macros by `\def` not `\newcommand` (`\cs`, `\ss` at `raw/main.tex:65–66`). **Contains no GNS construction and no Gelfand–Naimark representation theorem** — it says so itself: `we presented GNS construction fully in the course, but it is not given in these notes.` Defines a separable Hilbert space **basis-theoretically** and sets the equivalence with topological separability as an exercise. Two defects: `cor:Hilbertcardinality`'s proof assumes only a surjection where a bijection is needed, and its corollary that every separable Hilbert space is unitarily ℓ²(ℕ) is false for finite-dimensional H under its own definition. Its equinumerosity proof makes an unflagged simultaneous choice | 2026-08-16 | +| LAN98 | N. P. Landsman, *Lecture Notes on C\*-algebras, Hilbert C\*-modules and Quantum Mechanics*, arXiv math-ph/9807030 | retrieved | `references/arxiv-math-ph-9807030/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; heavy custom macros (`\ca`, `\Hs`, `\rep`, `\om`, `\A`, and a `\renewcommand{\H}`). Inner product conjugate-linear in the **first** argument. Two typos to reproduce in quotes: `non-separable in the nom-topology` (for `norm-`), and Lemma `lots` writes `$\om(A)=a$` where the quantified state is `$\om_a$`. States Krein–Milman **without proof**. Its faithful-state GNS proposition is about the compact operators specifically, not a general C\*-algebra — do not cite it as the general statement. **Added 2026-08-16 (bicommutant run)**: it proves the double commutant theorem in full (Thm `DCT`, unital form) after a finite-dimensional warm-up (`DCT1`), and isolates the projection lemma (`DCTlemma`) that four of its proofs reuse; `DCT`'s general case is written as a *delta* on `DCT1` and is not self-contained without it. It dates the theorem to **1929**, twice. **Internal tension**: it reports von Neumann's original definition as closure meaning *sequential* completeness in WOT, while its own topology definition and `DCT` work with nets, and it never flags the switch. Three typos: the weak neighbourhood basis quantifies over the net member `A_λ` instead of the set variable `B` (as printed the set is all of `B(H)` or empty); `\M^n(\M')` and `\M_n(\M'')` spell one construction two ways inside a single display; and `DCT`'s proof writes `A ∈ \ovl{\M\Ps}` for an operator `A` where `AΨ` is meant | 2026-08-16 | +| SHI12 | V. Shirbisheh, *Lectures on C\*-algebras*, arXiv:1211.3404 | retrieved | `references/arxiv-1211.3404/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; macros by `\def` not `\newcommand` (`\cs`, `\ss` at `raw/main.tex:65–66`). **Contains no GNS construction and no Gelfand–Naimark representation theorem** — it says so itself: `we presented GNS construction fully in the course, but it is not given in these notes.` Defines a separable Hilbert space **basis-theoretically** and sets the equivalence with topological separability as an exercise. Two defects: `cor:Hilbertcardinality`'s proof assumes only a surjection where a bijection is needed, and its corollary that every separable Hilbert space is unitarily ℓ²(ℕ) is false for finite-dimensional H under its own definition. Its equinumerosity proof makes an unflagged simultaneous choice. **Added 2026-08-16 (bicommutant run)**: it *does* contain the von Neumann bicommutant theorem, with a full proof following Pedersen, and is the **only** source in that corpus whose hypothesis is non-degeneracy rather than `1 ∈ M` — and the only one requiring `M` norm-closed. **Notation adjudication: its "strong-`\ss` operator topology" is the strong-⋆ topology** (seminorms `T ↦ ‖Tx‖ + ‖T*x‖`), *not* the σ-strong topology; matching it to KOS13's σ-strong by spelling is an error. Three defects in the material around the theorem: the proof declares `D : B(H) → B(H^n)` and then defines `D(T) := (Tx_1,…,Tx_n)`, a vector (the intended diagonal ampliation is in its Problem `e:5-22`, which itself states a hypothesis about `X` and a conclusion about `M`); the same proof concludes `there is some $T\in B(H)$` where the argument gives `T ∈ M`; and `prop:basiccommutant`(v)'s display has broken delimiters and missing moduli | 2026-08-16 | | VER25 | R. Verch, *Lecture Notes on Operator Algebras and Quantum Field Theory*, arXiv:2507.00900 | retrieved | `references/arxiv-2507.00900/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim. Subsection 1.2 states the Haag–Kastler covariance axiom `α_L(𝒜(O)) = 𝒜(L(O))` (see the `LocalNet.Covariance` row in this repository's math-review ledger). **`separable`, `Gelfand`, `Naimark`, `Neumark` all occur 0 times** — but do not conclude it is irrelevant to C\*-algebra extractions: it is the only source in the 2026-08-16 corpus that *defines* faithful state and faithful representation, and the only one stating "the GNS representation of a faithful state is faithful" (asserted, no proof, no citation). Unital throughout; inner product conjugate-linear in the first argument | 2026-08-16 | +| VN30 | J. von Neumann, *Zur Algebra der Funktionaloperationen und Theorie der normalen Operatoren*, Math. Ann. 102 (1930) 370–427 | not retrieved | — | — | 2026-08-16 | The paper the bicommutant theorem is attributed to. Tried: GDZ `gdz.sub.uni-goettingen.de/id/PPN235181684_0102` (HTTP 200 but a JavaScript-only shell — no article list, no download link) and `…/mets/PPN235181684_0102` (returns the SPA HTML, not METS; `/api/mets/…` is 404); EUDML `doc/159384` (HTTP 403). Springer DOI 10.1007/BF01782352 is paywalled and was not pursued; no PDF was converted. **Date discrepancy, unadjudicated**: LAN98 and HIA20 both date the theorem to **1929**, while KOS13's key and SOR23's citation give the 1930 Math. Ann. volume — and those two cite bibliographically identical data, so only one paper is in play. Whether 1929 is a submission year against a 1930 issue cannot be settled without the original. Expires 2027-02-16 | 2026-08-16 | +| CON00 | J. B. Conway, *A Course in Operator Theory*, American Mathematical Society, 2000 | not retrieved | — | — | 2026-08-16 | SOR23 sends its only proof of the double commutant theorem to `section 21 of \cite{conway2000course}`. **Title adjudication**: this is commonly mis-cited as *A Course in Functional Analysis* (a different Conway book); SOR23's own bibliography entry reads *A course in operator theory*, 2000. No copy was sought beyond noting the pointer, so nothing may be claimed about what section 21 says. Expires 2027-02-16 | 2026-08-16 | +| HIA20 | F. Hiai, *Concise lectures on selected topics of von Neumann algebras*, arXiv:2004.02383 | retrieved | `references/arxiv-2004.02383/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; macros by `\def` (`\cH`, `\<`, `\>`, `\Proj` at `raw/main.tex:32,42,43,62`). A survey: it **states the bicommutant theorem without proof and without a citation to a proof**, and likewise Kaplansky density. Two naming traps in one subsection: it calls the bicommutant theorem *von Neumann's density theorem* (nothing else in the 2026-08-16 corpus does, and it states Kaplansky density separately two paragraphs later), and it uses *commutant theorem* for the **tensor-product** result `(M₁⊗M₂)' = M₁'⊗M₂'`. Its definition says `closed in the weak topology` after introducing both WOT and the σ-weak topology two paragraphs earlier, so which one is meant is not written down. Declares von Neumann algebra ≡ `W*`-algebra, which KOS13 explicitly refuses. Dates the theorem to **1929**. Typo: `\<\xi\otimes\xi_2,\eta_1\otimes\eta_2\>` for `\xi_1` | 2026-08-16 | +| KOS13 | R. P. Kostecki, *W\*-algebras and noncommutative integration*, arXiv:1307.4818 | retrieved | `references/arxiv-1307.4818/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), byte-verbatim — **but its macros cannot be recovered**: `\usepackage{rpk}` and `\usepackage{motta}` at `raw/wstarint-arxiv.tex:35–36` are the author's private packages and are not in the arXiv package, so `\df \comm \N \C \BH \CC \II \zentr \limp` are undefined. A quote from KOS13 survives `grep -F`, but any *mathematical reading* of it is tier **(b)**, not (a). **WOT and SOT never occur anywhere in the document**: it states the double commutant theorem entirely in σ-topologies, and fixes them itself — `these topologies are usually called $\sigma$-strong and $\sigma$-strong-$\star$`. Keeps `W*`-algebra (Sakai predual) and von Neumann algebra as **distinct** notions. Its commutant is relative to an arbitrary ambient algebra. Three defects: it states the commutant's monotonicity **backwards** (`N₁ ⊆ N₂ ⟹ N₁' ⊆ N₂'`, false as printed), it drops the closure from Kreĭn–Milman one sentence after stating it correctly, and `source.txt:3779`/`3799` are a duplicated paragraph | 2026-08-16 | +| SOR23 | J. Sorce, *Notes on the type classification of von Neumann algebras*, arXiv:2302.01958 | retrieved | `references/arxiv-2302.01958/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; macros at `raw/type_classification.tex:26,30,32,38`, `\ket`/`\bra` from the `physics` package. **Convention trap: its definition of "$*$-subalgebra" includes the identity operator.** Its statement of the double commutant theorem therefore looks false when read with the standard non-unital meaning (witnesses `{0}` and `ℂp` for a proper projection) and is true under its own definition — do not quote that statement without the definition. It also contradicts itself on the unit: the front matter requires it, `def:vN-algebra` omits it. `H` separable is a **standing** assumption declared in the front matter, and is unused by its double-commutant statement. Points its only proof at `section 21 of \cite{conway2000course}`, whose bibliography entry reads *A course in operator theory* (2000) — **not** *A Course in Functional Analysis*. Typo: its weak-convergence clause quantifies over `\ket{x}` only, omitting `\ket{y}` | 2026-08-16 | | MUR90 / PED79 / DIX77 / TAK79 / BLA06 | Murphy, *C\*-algebras and Operator Theory* (1990); Pedersen, *C\*-algebras and their Automorphism Groups* (1979); Dixmier, *C\*-algebras* (1977); Takesaki, *Theory of Operator Algebras I* (1979); Blackadar, *Operator Algebras* (2006) | not retrieved | — | — | 2026-08-16 | The standard C\*-algebra textbooks. Only a web search was attempted; no legitimate free copy was found for any of them, and no pirated copy was pursued. **The widely-repeated attribution of the separable refinement of Gelfand–Naimark to "Murphy Thm 3.4.1" is unverified** — nobody in this repository has opened the book, so no note may carry that locator. Expires 2027-02-16 | 2026-08-16 | diff --git a/docs/math/README.md b/docs/math/README.md index 1c6cb00..9cae27c 100644 --- a/docs/math/README.md +++ b/docs/math/README.md @@ -30,6 +30,7 @@ the product. | Causal index set of a Haag–Kastler net | [causal-index-set.md](causal-index-set.md) | `CausalIndexSet` | | Split inclusion of von Neumann algebras | [split-inclusion.md](split-inclusion.md) | `VonNeumannAlgebra.IsSplitInclusion` | | Faithful representation of a separable C\*-algebra on a separable Hilbert space | [separable-faithful-representation.md](separable-faithful-representation.md) | `CStarRep.exists_isometric_separable` | +| Von Neumann bicommutant theorem | [bicommutant-theorem.md](bicommutant-theorem.md) | `DoubleCommutant.bicommutant_tfae` | <!-- One row per note. "Implemented as" is a fact recorded after the object is formalized — the fully-qualified declaration that ended up carrying it, or diff --git a/docs/math/bicommutant-theorem.md b/docs/math/bicommutant-theorem.md new file mode 100644 index 0000000..4fb834e --- /dev/null +++ b/docs/math/bicommutant-theorem.md @@ -0,0 +1,718 @@ +--- +object: Von Neumann bicommutant theorem +slug: bicommutant-theorem +status: draft +worst-tier: b +mathlib-rev: 5450b53e5ddc75d46418fabb605edbf36bd0beb6 +implemented-as: DoubleCommutant.bicommutant_tfae +revisions: + - 2026-08-16 · 9b1810d · initial extraction · sources: SHI12, LAN98, HIA20, KOS13, SOR23, NAA13, HM06 + - 2026-08-16 · (working tree) · back-link set — the adopted general form (non-unital, non-degenerate) is now stated by `SOTClosedSubalgebra.doubleCommutant_eq_of_isSOTClosed` / `WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed` + - 2026-08-16 · (working tree) · back-link moved to `DoubleCommutant.bicommutant_tfae`, which states the adopted general form in full (the three-way equivalence, non-unital and non-degenerate); the density form (R2) is `SOTClosedSubalgebra.sotClosure_eq_doubleCommutant` / `wotClosure_eq_doubleCommutant` + - 2026-08-16 · (working tree) · (A2) — that $1 \in M$ is a conclusion, not a hypothesis — is now `WOTClosedSubalgebra.one_mem_of_isWOTClosed` / `DoubleCommutant.one_mem_of_isSOTClosed`, which is also the sharpened content of (X6); (X4)'s $F(H)' = \mathbb{C}1$ and the $F(H)'' = B(H)$ it yields are `InnerProductSpace.centralizer_finiteRankOperators` / `centralizer_centralizer_finiteRankOperators`, and the negative instance itself is `DoubleCommutant.not_isWOTClosed_finiteRankOperators` / `not_isSOTClosed_finiteRankOperators` / `centralizer_centralizer_ne_finiteRankOperators` +--- + +<!-- +Macros the quotes below need, copied from each source's own preamble: + \ra \c \s \cs \ss \sub \lan \ran \la \ep SHI12, references/arxiv-1211.3404/raw/main.tex:46,52,62,65,66,70,72,73,96,98 + \ll \ca \Hs \sta \vNa \raw \n \BH \dl \ep \lm \Ph \Ps \M \GN \H \CO \C \I \su + LAN98, references/arxiv-math-ph-9807030/raw/main.tex:34,53,58,62,66,78,86,113,211,213,221,228,232,246,247,269,276,288,291,28 + \cH \cA \Proj HIA20, references/arxiv-2004.02383/raw/main.tex:32,51,62 + \comps \A \H \B SOR23, references/arxiv-2302.01958/raw/type_classification.tex:26,30,32,38 + \idx \alg \mc NAA13, references/arxiv-1311.2717/raw/qlattice.tex:21,66,73 + \alg \norm \bh \2 \7 \al HM06, references/arxiv-math-ph-0602036/raw/reconstruction.tex:26,27,28,136,138,143 + KOS13's macros (\df \comm \N \C \BH \CC \II \zentr \limp \rpktarget) are defined + in the author's private packages rpk.sty and motta.sty, which are NOT in the + arXiv package (\usepackage lines at raw/wstarint-arxiv.tex:35-36). They cannot + be transcribed, and no KOS13 quote below can be rendered from this note; see + the tier note on (D9)/(D10). + \H and \M are defined by more than one source below; LAN98's and SOR23's \H + agree up to the spelling of the calligraphic alphabet, and only LAN98 uses \M + inside a quote, so a single definition of each is faithful here. + + The bodies below are the sources' own; only the defining primitive is this + note's, and it is forced by the renderer. KaTeX scopes \newcommand to the + expression it appears in, so a preamble written with \newcommand defines + nothing for the rest of the document; \gdef is the form that persists. \gdef + also overwrites silently, which is what \c, \ss, \sub and \H need — KaTeX + predefines all four (cedilla, sharp s, \subset, Hungarian umlaut) and rejects + \newcommand on them outright, aborting the whole block and leaving every + later macro undefined. That was the parse error this preamble first produced. +--> + +$$ +\gdef\ra{{\rightarrow}} +\gdef\c{{\mathbb{C}}} +\gdef\s{{^{\ast}}} +\gdef\cs{{C^{\ast}\text{-}}} +\gdef\ss{{\ast}} +\gdef\sub{{\subseteq }} +\gdef\lan{{\langle}} +\gdef\ran{{\rangle}} +\gdef\la{{\lambda}} +\gdef\ep{{\varepsilon}} +\gdef\sta{{\ast\text{-algebra}}} +\gdef\ca{{C^{\ast}\text{-algebra}}} +\gdef\Hs{{\text{Hilbert space}}} +\gdef\vNa{{\text{von Neumann algebra}}} +\gdef\raw{\rightarrow} +\gdef\BH{{\frak B}({\cal H})} +\gdef\dl{\delta} +\gdef\lm{\lambda} +\gdef\Ph{\Phi} +\gdef\Ps{\Psi} +\gdef\M{{\frak M}} +\gdef\GN{{\frak N}} +\gdef\H{{\cal H}} +\gdef\C{{\Bbb C}} +\gdef\I{{\Bbb I}} +\gdef\cH{\mathcal{H}} +\gdef\A{\mathcal{A}} +\gdef\B{\mathcal{B}} +\gdef\cA{\mathcal{A}} +\gdef\alg#1{\mathfrak{#1}} +\gdef\mc#1{\mathcal{#1}} +\gdef\bh{\mathfrak{B}(\mathcal{H})} +\gdef\2#1{{\mathcal #1}} +$$ + +# Von Neumann bicommutant theorem + +## What this object is for + +The bicommutant theorem identifies a purely algebraic condition on an operator +algebra $M \subseteq B(H)$ — that it is its own bicommutant — with a purely +topological one — that it is closed in the weak (equivalently strong) operator +topology. It is what makes the theory of von Neumann algebras possible at all: +it lets a definition be given algebraically and then used topologically, so that +weak limits, spectral projections and polar decompositions of elements of $M$ +stay inside $M$. Its generality matters in exactly one direction: the algebra is +required to act non-degenerately (a condition strictly weaker than containing +$1$), and nothing about separability, σ-finiteness, type, or commutativity +enters anywhere. + +## Definition + +### Variants as the sources write them + +Axes along which the corpus genuinely splits. The grid is a derived index and +carries no tier; where it disagrees with a block below, the grid is wrong. + +| (D#) | Source | Assumption on $M$ | Norm-closed? | Closure conditions listed | Which side is the definition | +|---|---|---|---|---|---| +| (D1) | SHI12 | none (unitality derived) | — | $M = M''$ | algebraic | +| (D2) | SHI12 | acts non-degenerately | **yes** ($C^{*}$-subalgebra) | $M=M''$ / WOT / SOT | theorem, both sides | +| (D3) | LAN98 | $1 \in M$ | no | $M''=M$ / WOT / SOT | theorem, both sides | +| (D4) | LAN98 (reporting von Neumann) | none | no | **sequential** WOT-completeness | topological | +| (D5) | HIA20 | $1 \in M$ | no | WOT / SOT / $M''=M$ | topological | +| (D6) | HM06 | $1 \in M$ | no | WOT / $R''=R$ — **no SOT** | algebraic, by election | +| (D7) | NAA13 | unital | no | WOT — **no SOT** | algebraic ($M = A''$) | +| (D8) | SOR23 | folded into "$*$-subalgebra" | no | WOT $\Rightarrow$ vN algebra (one direction) | algebraic | +| (D9) | KOS13 | unital | no | $N=N''$ / σ-weak / σ-strong / σ-strong-⋆ — **no WOT, no SOT** | algebraic | +| (D10) | KOS13 | — ($W^*$-algebra, abstract) | — | possession of a predual | Hilbert-space-free | +| (D11) | all | — | — | the six sources' own topology definitions | — | + +**(D1) [SHI12] — von Neumann algebra as $M = M''$, unitality derived** — tier (a) + +> `Let $H$ be a Hilbert space. An involutive subalgebra $M$ of $B(H)$ is called a {\bf von Neumann algebra on $H$} if $M=M''$.` + +> `One notes that every von Neumann algebra is necessarily unital.` + +SHI12 also fixes $VN(S) := C^*(S)''$ for the generated von Neumann algebra, and +calls $A''$ the enveloping von Neumann algebra of a $C^{*}$-subalgebra $A$. + +**(D2) [SHI12] — the theorem, non-degeneracy form** — tier (a) + +> `We say a {\bf \cs-subalgebra $A$ of $B(H)$ acts non-degenerately on $H$} if $x\in H$ and $Tx=0$ for all $T\in A$ implies $x=0$.` + +> `\label{thm:bicommutant} [The von Neumann bicommutant theorem] Let $M$ be a \cs-subalgebra of $B(H)$ acting non-degenerately on $H$. Then the following statements are equivalent:` + +with the three equivalents `$M=M^{\prime \prime}$`, `$M$ is weakly closed`, +`$M$ is strongly closed`. + +`differs from (D3) by:` SHI12 hypothesises non-degeneracy where every other +corpus source hypothesises $1 \in M$, and is the only source to require $M$ +norm-closed. +`sources claim equivalence:` not addressed — no corpus source compares the two +hypothesis packages. They are not equivalent; see (X1) and (X6). + +**(D3) [LAN98] — the double commutant theorem, unital $*$-algebra** — tier (a) + +> `Let $\M$ be a \sta\ in $\BH$, containing $\I$. The following are` + +equivalent: `$\M''=\M$`; `$\M$ is closed in the weak operator topology`; +`$\M$ is closed in the strong operator topology`. + +`differs from (D2) by:` unitality in place of non-degeneracy, and no +norm-closedness. +`sources claim equivalence:` not addressed. + +**(D4) [LAN98] — von Neumann's original definition, as LAN98 reports it** — tier (a) + +> `defines a {\bf ring of operators} $\M$ (nowadays called a {\bf von Neumann algebra}) as a $\mbox{}^*$-subalgebra of the algebra $\BH$ of all bounded operators on a \Hs\ $\H$ (i.e, a subalgebra which is closed under the involution $A\raw A^*$) that is closed (i.e., sequentially complete) in the weak operator topology.` + +LAN98 then changes its own definition mid-text: + +> `from now on we add to the definition of a von` + +> `Neumann algebra the condition that $\M$ contains $\I$.` + +`differs from (D3) by:` no unit, and closure phrased **sequentially**. WOT is not +first countable, so this is not a notational difference; see (X7), which +separates the two on a non-separable space. +`sources claim equivalence:` not addressed; LAN98 does not flag its own switch. + +**(D5) [HIA20] — von Neumann algebra defined topologically** — tier (a) + +> `A *-subalgebra of $B(\cH)$ is called a \emph{von Neumann algebra} (also \emph{$W^*$-algebra})` + +> `if it contains the identity operator $1$ and closed in the weak topology.` + +and, for a $*$-subalgebra $M$ with $1 \in M$, the + +> `commutation theorem} or \emph{von Neumann's density theorem} says that the following three conditions are equivalent:` + +namely weakly closed / strongly closed / $M''=M$. + +`differs from (D3) by:` the direction of definition is reversed — the definiens +is topological and $M''=M$ is derived. HIA20 also declares "von Neumann +algebra" and "$W^*$-algebra" synonyms, which (D10) refuses. +`sources claim equivalence:` yes, by its own statement of the theorem. + +**(D6) [HM06] — algebraic condition taken as basic, two conditions only** — tier (a) + +> `The standard definition of a von Neumann algebra involves reference to a topology, and it is then shown (by von Neumann's double commutant theorem) that this topological condition coincides with an algebraic condition (condition 2 in the Definition \ref{vNA}). But for present purposes, it will suffice to take the algebraic condition as basic.` + +> `For a $*$-algebra $\alg{R}$ on $\2H$ that contains $I$, the following are equivalent: (i) $\alg{R}$ is weakly closed; (ii) $\alg{R}''=\alg{R}$. This is von Neumann's double commutant theorem.` + +`differs from (D3) by:` the SOT clause is absent, though HM06 has defined SOT. +HM06 writes the commutant with a commutator, $[B,A]=0$. +`sources claim equivalence:` yes for its own two conditions. + +**(D7) [NAA13] — unital $*$-subalgebra, WOT only** — tier (a) + +> `a unital $*$-subalgebra of $\alg{B}(\mathcal{H})$ is a von Neumann algebra if and only if it is closed in the weak operator topology. This result, which is known as the \emph{bicommutant theorem}, relates the purely algebraic definition of von Neumann algebras given on page~\pageref{p:vna}, to a topological condition.` + +`differs from (D6) by:` NAA13's "purely algebraic definition" is not $M = M''$ +but the construction $M = A''$ from an ambient $*$-algebra $A$. +`sources claim equivalence:` yes, between its own two conditions. + +**(D8) [SOR23] — $A = A''$, with unitality folded into "$*$-subalgebra"** — tier (a) + +> `A subset of $\B(\H)$ is said to be a \textbf{$*$-subalgebra} if it is closed under scalar multiplication, operator multiplication, operator addition, and adjoints, and contains the identity operator.` + +> `A $*$-subalgebra $\A \subseteq \B(\H)$ is a \textbf{von Neumann algebra} if it is equal to its own double commutant, i.e., $\A = \A''.$` + +and the theorem, one-directional and stated inside a proof sketch: + +> `It uses the double commutant theorem, which says that any $*$-subalgebra of $\B(\H)$ that is topologically closed with respect to the ``weak operator topology''\footnote{The weak operator topology is explained in appendix \ref{app:operator-topologies}.} is a von Neumann algebra.` + +`differs from (D6) by:` unitality lives in the ambient notion, so SOR23's +"$*$-subalgebra" is not the standard one. **Read with the standard non-unital +meaning the statement is false**, witnesses $\{0\}$ and $\mathbb{C}p$ for a +proper projection $p$; read with SOR23's own definition it is the standard +unital statement and is true. See (X8). +`sources claim equivalence:` not addressed. + +**(D9) [KOS13] — commutant relative to an ambient algebra, σ-topologies** — tier (b) +(byte-verbatim, but KOS13's macros are unavailable, so the mathematical reading +of the quote is inferred) + +> `The \df{commutant} of a subalgebra $\N$ of any algebra $\C$ is defined as` + +> `\N^\comm:=\{y\in\C\mid xy=yx\;\forall x\in\N\},` + +> `A unital $*$-subalgebra $\N$ of an algebra $\BH$ is called the \df{von Neumann algebra} \cite{vonNeumann:1930:algebra,Murray:vonNeumann:1936} if{}f $\N=\N^\comm{}^\comm$. From von Neumann's double commutant theorem \cite{vonNeumann:1930:algebra} it follows that this is equivalent with any of the conditions: $\N$ is weakly-$\star$ closed, $\N$ is ultrastrongly closed, $\N$ is ultrastrongly-$\star$ closed. In particular, $\BH$ is a von Neumann algebra.` + +`differs from (D3) by:` two independent things. The commutant is taken relative +to an arbitrary ambient algebra, not inside $B(H)$; and the closure conditions +are the σ-topologies, WOT and SOT occurring nowhere in KOS13. That these +topologies are the standard σ-topologies is fixed by KOS13 itself: + +> `When considered in the context of $W^*$-algebras $\N\subseteq\BH$, these topologies are usually called \textit{$\sigma$-strong} and \textit{$\sigma$-strong-$\star$}, respectively.` + +`sources claim equivalence:` KOS13 asserts its four conditions equivalent, citing +von Neumann; **no corpus source bridges its list to the WOT/SOT list**. The note +supplies that bridge itself as (X9), at tier (d). + +**(D10) [KOS13] — $W^*$-algebra as the abstract notion, kept distinct** — tier (b) + +> `If for a given $C^*$-algebra $\C$ there exists a predual $\C_\star$, then it is a unique predual of $\C$, and in such case $\C$ is called a \df{$W^*$-algebra} \cite{Sakai:1956}.` + +> `An image $\pi(\N)$ of any representation $(\H,\pi)$ of a $W^*$-algebra $\N$ is a von Neumann algebra if{}f $\pi$ is normal and nondegenerate.` + +`differs from (D5) by:` KOS13 keeps $W^*$-algebra and von Neumann algebra as two +notions related by a cited theorem, where HIA20 declares them synonyms. This is +a definitional disagreement in the corpus, not a notational one. +`sources claim equivalence:` yes, by citing Sakai — see the external edge in +(R14). + +**(D11) — the operator topologies, per source** — tier (a) + +Filed as a variant because the theorem's content is exactly which topology is +named. SHI12 defines SOT, WOT and strong-⋆ and **no** σ-topology; LAN98 defines +norm, strong and weak by nets; HIA20 names norm/SOT/WOT without defining them and +adds the σ-weak topology as $\sigma(B(\mathcal{H}),\mathcal{C}_1(\mathcal{H}))$; SOR23 defines +norm, strong and weak by seminorms and no σ-topology; HM06 defines uniform, weak, +strong and **ultraweak**, the last concretely via density operators; KOS13 +defines only σ-topologies, on an abstract $W^*$-algebra via its predual. Three +mutually inequivalent ambient frameworks, therefore, and only (X9) connects the +third to the first. + +**Notation trap.** SHI12's "strong-`\ss` operator topology" is defined by the +seminorms $T \mapsto \|Tx\| + \|T^{*}x\|$ — that is the **strong-⋆** topology, +not KOS13's σ-strong. Matching the two by their spelling is a mistake. + +### Adopted general form + +Let $H$ be a complex Hilbert space and let $M \subseteq B(H)$ be a +$*$-subalgebra — a linear subspace closed under products and under the adjoint, +**not assumed norm-closed and not assumed to contain $1$** — which acts +non-degenerately on $H$, meaning: for $x \in H$, if $Tx = 0$ for every +$T \in M$, then $x = 0$. Write $M' = \{S \in B(H) : ST = TS \text{ for all } +T \in M\}$ and $M'' = (M')'$. Then the following three conditions are +equivalent: + +1. $M = M''$; +2. $M$ is closed in the weak operator topology of $B(H)$; +3. $M$ is closed in the strong operator topology of $B(H)$. + +The standing assumptions are (A3) self-adjointness, (A5) the algebra structure +and (A10) that $H$ is a complex Hilbert space; the one local hypothesis is (A1) +non-degeneracy. No separability, σ-finiteness, type or commutativity assumption +is carried, and none is available to be dropped. + +This is (D2) with SHI12's norm-closedness hypothesis deleted. The choice of +(D2) over the unital variants is justified by (X1): $K(H)$ for infinite +-dimensional $H$ acts non-degenerately and is not unital, so (D3), (D5), (D6), +(D7) and (D9) say nothing about it while (D2) does. The deletion of +norm-closedness is justified by (X4): no step of the corpus proof consumes it +and each of the three conditions implies it, so assuming it removes only +instances where all three fail — a class inhabited by the finite-rank operators +$F(H)$. + +### The density form the equivalence hides + +The corpus proof establishes more than the equivalence states, and the stronger +statement is the one a formalization is likely to want as the primary result: +for **every** non-degenerate $*$-subalgebra $M \subseteq B(H)$, with no closure +hypothesis at all, + +$$M'' = \overline{M}^{\,\mathrm{SOT}} = \overline{M}^{\,\mathrm{WOT}}.$$ + +The three-way equivalence is a corollary. See (R2) for the tier. + +## Notation and conventions + +| (C#) | Axis | This note | Per source | Translation | +|---|---|---|---|---| +| (C1) | conjugate-linear argument of the inner product | irrelevant to every statement here, provided the WOT seminorms range over all pairs | SHI12 linear in the first; LAN98 conjugate-linear in the first, explicit; SOR23, HIA20, NAA13 conjugate-linear in the first, implicit (tier b); HM06 and KOS13 unresolved | SHI12's $\langle x,y\rangle$ is LAN98's $(y,x)$ | +| (C2) | status of $1 \in M$ | a conclusion, not a hypothesis | conclusion (SHI12); hypothesis (LAN98, HIA20, HM06, NAA13, KOS13); part of the ambient notion (SOR23); added mid-text (LAN98) | (A2) | +| (C3) | self-adjointness of the set whose commutant is taken | assumed throughout | isolated only by SHI12; stated informally by LAN98 and SOR23; omitted by HIA20, HM06, NAA13, KOS13 | without it $M'$ need not be a $*$-algebra — (X2) | +| (C4) | name of the theorem | bicommutant theorem | bicommutant (SHI12, NAA13, KOS13); double commutant (LAN98, SOR23, HM06, KOS13); double commutation **or** von Neumann's density theorem (HIA20) | HIA20's "density theorem" is a name collision with Kaplansky density, which HIA20 states separately — see (R11), (R12) | +| (C5) | which topologies enter the statement | WOT and SOT | three conditions (SHI12, LAN98, HIA20); two (HM06, NAA13); one direction (SOR23); four σ-conditions (KOS13) | (X9) | +| (C6) | "von Neumann algebra" vs "$W^*$-algebra" | kept distinct | synonyms (HIA20); distinct notions related by a cited theorem (KOS13) | Sakai's theorem, (R14) | +| (C7) | algebraic vs topological primacy | algebraic condition stated first, topological conditions as equivalents | explicit, self-aware disagreement across the corpus — HM06 and NAA13 elect the algebraic side, HIA20 the topological, SHI12 the algebraic with a remark | presentation only, no content | +| (C8) | commutant notation | $M'$, $M''$ | $X'$/$X''$ everywhere; SHI12 continues $X''', X''''$; KOS13 uses a macro, not a prime; HM06 defines it by $[B,A]=0$ | — | +| (C9) | nets vs sequences | nets | LAN98's report of von Neumann's original definition is sequential; HM06, SOR23 and SHI12 all warn that WOT is not first countable | not interchangeable — (X7) | + +## Results and dependencies + +### (R1) The bicommutant theorem, non-degeneracy form + +For $M$ a norm-closed $*$-subalgebra of $B(H)$ acting non-degenerately: +$M = M''$ ⟺ $M$ WOT-closed ⟺ $M$ SOT-closed. + +- Source: [SHI12] Theorem `thm:bicommutant` · tier (a) · **proved in source** +- Depends on: (R3), (R5), (R6), (R7), (R8), (A1), (A3), (A5) +- Conventions: (C2), (C3), (C5) +- Proof route: + 1. (i)⇒(ii) and (ii)⇔(iii) in one line, consuming (R7) [WOT coarser than SOT], + (R5) [every commutant is WOT- and SOT-closed] and (R6) [for a convex set, + SOT-closed ⟺ WOT-closed; $M$ is a subspace, hence convex — (A5)]. + 2. One-vector case: fix $x_0$, put $X = \overline{Mx_0}$, $P = P_X$; then + $PTP = TP$ for $T \in M$ because $MX \subseteq X$ — consumes (A5). + 3. Adjoint trick $TP = (PT^{*}P)^{*} = (T^{*}P)^{*} = PT$, so $P \in M'$ — + consumes (A3), and consumes it **here only**. + 4. $T(1-P)x_0 = (1-P)Tx_0 = 0$ for all $T \in M$, so $(1-P)x_0 = 0$ — + consumes (A1), and consumes it **here only**. + 5. For $S \in M''$: $SP = PS$, so $Sx_0 = PSx_0 \in X$, giving $T \in M$ with + $\|(S-T)x_0\| < \varepsilon_0$. + 6. Amplify to $H^n$ and use $D(M)' = M_n(M')$ to place $D(S)$ in $D(M)''$ — + consumes (R8). + 7. Re-run steps 2–5 on $(H^n, D(M), D(S))$ and estimate + $\|(S-T)x_m\| \le \|(D(S)-D(T))x\| < \varepsilon$, so + $M'' \subseteq \overline{M}^{\,\mathrm{SOT}} = M$. + 8. $M \subseteq M''$ is (R3)(iii) — consumes (R3). +- Note: step 7 re-uses the one-vector argument on $D(M)$ without checking that + $D(M)$ acts non-degenerately on $H^n$. The check is one line and is written + out at (A8); the mathematics is unaffected. +- Verbatim: + > `The implications (i) $\Rightarrow$ (ii) $\Leftrightarrow$ (iii) follow from Proposition \ref{prop:strongweaktop}(i), Remark \ref{rem:continofoperations}(v), and Corollary \ref{cor:weakstrongconvexclosed}.` + + > `Since $M$ acts non-degenerately on $H$, $(1-P)x_0=0$.` + +### (R2) The density form + +For every non-degenerate $*$-subalgebra $M \subseteq B(H)$, with no closure +hypothesis, $M'' = \overline{M}^{\,\mathrm{SOT}} = \overline{M}^{\,\mathrm{WOT}}$. + +- Source: [SHI12] — the same proof, read as establishing more than it states · + tier (b) · **proved in source, but not stated there**: the proof is (R1)'s and + is quoted under it; the statement is this note's reading of that proof, which + is why the row is (b) +- Depends on: (R1) steps 2–7, (R5), (R6), (A1), (A3), (A5) +- Conventions: (C5) +- Nothing in steps 2–7 uses any of (i),(ii),(iii); they are consumed only in + step 1 and in the final identification $\overline{M}^{\,\mathrm{SOT}} = M$. + The corpus does not state this form, which is why the row is (b) and not (a). + +### (R3) Basic properties of the commutant, including $X''' = X'$ + +For subsets $X, X_1, X_2 \subseteq B(H)$: (i) $X_1 \subseteq X_2 \Rightarrow +X_2' \subseteq X_1'$; (ii) $X'$ is a norm-closed unital subalgebra; (iii) +$X \subseteq X'' = X'''' = \cdots$ and $X' = X''' = \cdots$; (iv) $X$ +self-adjoint $\Rightarrow$ $X'$ self-adjoint; (v) $X'' = B(H)$ iff +$X' = \mathbb{C}1$. + +- Source: [SHI12] Proposition `prop:basiccommutant` · tier (a) · **proved in source** +- Depends on: nothing, except (v) which consumes SHI12's Cauchy–Schwarz + equality case +- Conventions: (C3), (C8) +- Verbatim: + > `\item [(ii)] $X'$ is a closed unital subalgebra of $B(H)$.` + + > `\item [(iv)] If $X$ is a self adjoint subset of $B(H)$, then $X'$ is self adjoint, and consequently a unital \cs-subalgebra of $B(H)$.` + +- (ii) is what makes (A2) a theorem rather than a hypothesis: $M = M''$ forces + $1 \in M$. + +### (R4) The projection lemma + +For $M$ a $*$-algebra in $B(H)$ and $\Psi \in H$ non-zero, the orthogonal +projection onto $\overline{M\Psi}$ lies in $M'$. + +- Source: [LAN98] Lemma `DCTlemma` · tier (a) · **proved in source** +- Depends on: LAN98's decomposition of an element into self-adjoint parts +- Proof route: $A \in M$ gives $ApH \subseteq pH$, hence $p^{\perp}Ap = 0$, i.e. + $Ap = pAp$; for $A = A^{*}$ this yields $(Ap)^{*} = pA = pAp = Ap$; extend to + all of $M$ by linearity. +- Verbatim: + > `Let $\M$ be a \sta\ in $\BH$, take a nonzero vector $\Ps\in\H$, and` + + > `let $p$ be the projection onto the closure of $\M\Ps$. Then $p\in\M'$` + +- This is the same content SHI12 inlines as (R1) steps 2–3. LAN98 isolates it and + re-uses it in three further results; SHI12 never names it. + +### (R5) Every commutant is WOT- and SOT-closed + +- Source: [SHI12] Remark `rem:continofoperations`(v) · tier (a) · **asserted** + (SHI12 sets the proof as an exercise); [LAN98] proves the WOT half inline + inside its proof of (R9) · tier (a) · **proved in source** +- Depends on: separate continuity of multiplication +- The corpus therefore does contain a proof of this — in the other source than + the one that states it as a remark. +- Verbatim (LAN98): + > `the commutant $\GN'$ of a \sta\ $\GN$ is always weakly closed` + +### (R6) A convex set is SOT-closed iff WOT-closed + +- Source: [SHI12] Corollary `cor:weakstrongconvexclosed` · tier (a) · **proved in source** +- Depends on: Hahn–Banach separation in a locally convex space, and (R7) +- Conventions: (C5) +- Verbatim: + > `Let $X$ be a convex set in $B(H)$. Then $X$ is strongly closed if and only if it is weakly closed.` + +- This is the whole content of the (ii)⇔(iii) half of (R1); it consumes (A5) + and none of (A1), (A2), (A3). + +### (R7) WOT ⊆ SOT ⊆ norm topology + +- Source: [SHI12] Proposition `prop:strongweaktop` · tier (a) · **proved in source**; + the same two reasons appear unnumbered in [LAN98] +- Depends on: nothing +- This is what makes (A4) redundant: a WOT- or SOT-closed set is norm-closed. + +### (R8) Amplification: $B(H^n) \cong M_n(B(H))$ and $D(M)' = M_n(M')$ + +- Source: [SHI12] Problem `e:5-22` · tier (a) · **asserted** (set as an exercise, + no proof); [LAN98], inside its proof of (R10), proves the commutator half + inline and asserts $M_n(M')' = M_n(M'')$ · tier (a) · **proved in source** (in + part) +- Depends on: nothing +- Verbatim (LAN98): + > `Hence $\dl(\M)'=\M^n(\M')$.` + +- This is the one place where the two full proofs differ in rigour: SHI12 exiles + it to an unproved exercise, LAN98 proves half of it and waves at the rest. + +### (R9) The bicommutant theorem, unital form + +For $M$ a $*$-algebra in $B(H)$ containing $1$: $M'' = M$ ⟺ WOT-closed ⟺ +SOT-closed. + +- Source: [LAN98] Theorem `DCT` · tier (a) · **proved in source** +- Depends on: (R4), (R5), (R7), (R8), (R10), (A2). Self-adjointness (A3) and the + algebra structure (A5) enter this proof only through (R4), not through a step + of its own +- Conventions: (C2), (C5) +- Proof route: + 1. 1⇒2 via (R5), proved inline by the net computation + $(\Phi,[A,B]\Psi) = \lim_\alpha (\Phi,[A_\lambda,B]\Psi) = 0$. + 2. 2⇒3 trivially, WOT being coarser than SOT — consumes (R7). + 3. 3⇒1: $p = [\overline{M\Psi}] \in M'$ by (R4); $1 \in M$ gives + $\Psi = 1\Psi \in M\Psi$, so $p\Psi = \Psi$ and $A\Psi \in + \overline{M\Psi}$ for $A \in M''$ — consumes (A2), **and consumes it + here only**, at exactly the point where (R1) consumes (A1). + 4. Amplify as in (R10), giving $A_\varepsilon \in M$ inside a basic SOT + neighbourhood — consumes (R8). + 5. $M$ SOT-closed gives $M'' \subseteq M$. +- Not self-contained: LAN98 writes step 4 as a delta on the proof of (R10) and + does not re-derive the amplification. +- Verbatim: + > `Let $\M$ be a \sta\ in $\BH$, containing $\I$. The following are` + +### (R10) The finite-dimensional case + +For $M$ a $*$-algebra in $M_n(\mathbb{C})$ containing $1$, $n < \infty$: +$M'' = M$, with **no** topological hypothesis. + +- Source: [LAN98] Proposition `DCT1` · tier (a) · **proved in source** +- Depends on: (R4), (R8), (A2), (A6), (A7) +- Proof route: $M\Psi$ is already closed in finite dimensions, so no closure is + needed; $p = [M\Psi] \in M'$ by (R4); $1 \in M$ gives $p\Psi = \Psi$, hence + $A\Psi = A_0\Psi$ for some $A_0 \in M$; amplify by (R8) and run the argument + on $n$ spanning vectors to get $A = A_0$. +- Verbatim: + > `Let $\M$ be a \sta\ (and hence a \ca) in $\M^n(\C)$ containing $\I$` + +- LAN98 states the sharpness itself: + > `As it stands, Proposition \ref{DCT1} is not valid when $\M^n(\C)$ is replaced by $\BH$, where $\dim(\H)=\infty$.` + +### (R11) The theorem as the four other sources carry it + +- Sources: [HIA20] §1.2 (three conditions), [HM06] its `fact` (two conditions, + no SOT), [NAA13] (two conditions, no SOT), [SOR23] (one direction, inside a + proof sketch) · tier (a) each · **asserted** — none of the four gives a proof +- Depends on: [ext: VN30 — a $*$-subalgebra of the bounded operators on a + Hilbert space that contains the identity equals its own bicommutant if and + only if it is closed in the weak operator topology. tier (c), no locator, not + retrieved]; SOR23 additionally points its proof at a work of Conway, see + (R15) +- Conventions: (C4), (C5) +- Five of the seven corpus sources carry the theorem with no proof at all. + +### (R12) Kaplansky density — stated in the corpus, consumed by nothing in it + +For a $*$-subalgebra $\mathcal{A}$ of $B(H)$ containing $1$, the unit ball of +$\mathcal{A}$ is SOT-dense in the unit ball of $\mathcal{A}''$. + +- Source: [HIA20] §1.2 · tier (a) · **asserted** (no proof, no citation to one) +- Depends on: nothing stated +- Verbatim: + > `$\{a\in\cA:\|a\|\le1\}$ is strongly dense in $\{a\in\cA'':\|a\|\le1\}$.` + +- No result in any of the seven sources cites it. It becomes load-bearing only + in (X7) and (X9), which are this note's own arguments. + +### (R13) $K(H)'' = B(H)$ + +- Source: [SHI12] Proposition `prop:voncompact` · tier (a) · **proved in source** +- Depends on: (R3)(v) +- The corpus's own witness that the bicommutant operation is non-trivial on a + non-unital algebra, and the separating object of (X1). SHI12 also records, as + an exercise, that $K(H)$ is not unital for infinite-dimensional $H$. + +### (R14) Downstream consumers, and one name collision + +- [SHI12]: the Borel functional calculus of a normal $T \in M$ stays inside $M$ · + tier (a) · **asserted** ("an immediate consequence"), reconstructible from + SHI12's own proof that the calculus is WOT-continuous. +- [HIA20]: polar and spectral decompositions are taken inside $M$ · tier (a) · + **asserted**. +- [KOS13]: the projections generate, $\mathrm{Proj}(N)'' = N$; and approximate + finite-dimensionality reads $N = (\bigcup_i N_i)''$ · tier (b) · **asserted** — + the corpus's only use of the theorem in the direction "density ⟹ bicommutant + identity", which is the direction that matters downstream. +- [SOR23]: for any adjoint-closed $\mathcal{A} \subseteq B(H)$, $\mathcal{A}'$ is + a von Neumann algebra · tier (a) · **sketched**. True with no unitality caveat, + since $\mathcal{A}'$ always contains $1$, is a $*$-algebra when + $\mathcal{A} = \mathcal{A}^{*}$, and is WOT-closed by (R5). +- [HIA20]: the **commutant theorem** $(M_1 \otimes M_2)' = M_1' \otimes M_2'$ + for tensor products · tier (a) · **asserted**. **A different theorem** sharing + a similar name; recorded so it is never merged with this one. +- [ext: Sakai — a C\*-algebra is isomorphic to a von Neumann algebra if and only + if it is the dual Banach space of some Banach space, and the predual is then + unique. tier (c), no locator, not retrieved], attested by HIA20 and KOS13; it + is the bridge (D10) uses. + +### (R15) The single-generator theorem + +On a separable Hilbert space, every abelian von Neumann algebra is $\{T\}''$ for +a single Hermitian $T$ in it. + +- Source: [SOR23] · tier (a) for the statement · **cited elsewhere** +- Depends on: [ext: VN30 — on a separable Hilbert space every abelian von + Neumann algebra is the bicommutant of a single self-adjoint operator it + contains. tier (c), no locator, not retrieved]; SOR23 additionally claims the + result appears as an exercise with hints in a work of Dixmier — that locator + is **SOR23's claim**, reported here and not adopted +- Conventions: (A9) +- Carried because it is the only place in the corpus where separability is + load-bearing; (A9) records the witness and (A11) what remains open. + +## Hypotheses + +| (A#) | Statement | Class | Evidence | Witness | Scope | Tier | Used by | +|---|---|---|---|---|---|---|---| +| (A1) | $M$ acts non-degenerately on $H$ | model-dependent | SHI12 states it as the hypothesis of the theorem | fails for $M = B(H_1) \oplus 0 \subseteq B(H_1 \oplus H_2)$, where (ii),(iii) hold and (i) fails; holds for $K(H)$ and $B(H)$ | local | a | (R1) step 4 only, i.e. (iii)⇒(i) only | +| (A2) | $1 \in M$ | provable | from (A1) plus any one of (i),(ii),(iii): (iii)⇒(i) gives $M = M''$, and $M''$ is unital by (R3)(ii). SHI12 records the conclusion in prose | — | local in LAN98/HIA20/HM06/NAA13/KOS13; standing in LAN98 after its mid-text change, and in SOR23 | a | (R9) step 3, (R10) — and nothing else in either proof | +| (A3) | $M$ is self-adjoint | model-dependent | every corpus source imposes it | fails for the upper-triangular $2\times2$ complex matrices: unital, closed in every topology, $M' = \mathbb{C}1$, $M'' = M_2(\mathbb{C}) \supsetneq M$; holds for every von Neumann algebra | local, and standing in SOR23 | a | (R1) step 3, (R4), (R3)(iv) | +| (A4) | $M$ is norm-closed | provable, **and used by no step** | each of (i),(ii),(iii) implies it via (R7); a step-by-step reading of (R1) finds no step consuming it | — | local, SHI12 only | a | nothing | +| (A5) | $M$ is a subalgebra, hence convex | provable (the convexity half is immediate) | a subalgebra is a linear subspace | fails for $V = \operatorname{span}\{1, e_{12}+e_{21}\} \subseteq M_3(\mathbb{C})$: self-adjoint, unital, closed, $\dim V = 2$ but $\dim V'' = 3$ | local, all sources | a | (R1) step 2, (R4), (R6) | +| (A6) | $\dim H < \infty$ | model-dependent | LAN98 imposes it on the finite-dimensional case and states its sharpness itself | fails for $M = K(H) + \mathbb{C}1$ on infinite-dimensional $H$: unital, norm-closed, $M' = \mathbb{C}1$, $M'' = B(H) \supsetneq M$; holds for $M_n(\mathbb{C})$ | local, (R10) only | a | (R10), to know $M\Psi$ is closed — it is what hypothesis (iii) is substituted for | +| (A7) | the vectors in (R10) span | provable | choose an orthonormal basis; nothing else in the argument constrains them | — | local, implicit — LAN98 says "arbitrary" | a | (R10)'s final step | +| (A8) | $D(M)$ acts non-degenerately on $H^n$ | provable, in one line | if $D(T)y = (Ty_1,\dots,Ty_n) = 0$ for all $T \in M$ then each $y_k$ is annihilated by all of $M$, so $y_k = 0$ by (A1) | — | local, implicit — SHI12 never checks it | a | (R1) step 7 | +| (A9) | $H$ separable | model-dependent | SOR23 declares it in its front matter | fails for $\ell^2(I)$, $I$ uncountable; holds for $L^2(\mathbb{R}^n)$ | standing in SOR23 | a | **not** the bicommutant theorem — no step of either full proof and no statement of the theorem uses it; used by (R15) and by the direct-integral decomposition | +| (A10) | $H$ is a complex Hilbert space | provable (it delimits the class rather than constraining members) | completeness is what gives the projection $P_X$ | — | standing | a | (R1) step 2, (R4) | +| (A11) | sharpness of (A9) below $2^{\aleph_0}$ | open | for $\lvert I \rvert > 2^{\aleph_0}$, $\ell^\infty(I)$ on $\ell^2(I)$ has no single Hermitian generator (argument written out in the lane notes); for $\lvert I \rvert \le 2^{\aleph_0}$ an injective $I \to \mathbb{R}$ exists and the obstruction vanishes | — | local | b | (R15) | + +Cleared, after checking: irreducibility and factoriality; cyclic and separating +vectors; faithfulness and normality of representations; σ-finiteness, +hyperfiniteness, proper infiniteness and the type conditions; boundedness. None +is a hypothesis of this theorem in any corpus source. + +## Degeneracies and boundary cases + +| Case | Effect on the adopted form | Tier | +|---|---|---| +| intended case is nonvacuous | $B(H)$ for every $\dim H$ (HM06's type I$_\kappa$ factor); $\{T\}''$ for a single Hermitian $T$ (SOR23); $VN(S) = C^*(S)''$ (SHI12); hyperfinite $(\bigcup_a R_a)''$ (HM06); the type III local algebras of QFT (HM06) | a | +| zero object — $H = \{0\}$ | no effect. $B(\{0\}) = \{0\}$, non-degeneracy is vacuous, the identity is $0$ and lies in $M$, so **both** hypothesis packages hold and all three conditions are true. There is no edge case here | — | +| zero object — $M = \{0\}$, $H \ne \{0\}$ | excluded by every corpus variant. It is the minimal witness for dropping non-degeneracy: $M$ is WOT-closed but $M'' = \mathbb{C}1 \supsetneq M$ | — | +| scalars — $M = \mathbb{C}1$ | no effect; non-vacuous but trivial ($M' = B(H)$, $M'' = M$) | — | +| finite-dimensional | holds, and the topological content evaporates: LAN98 proves this case with no topological hypothesis, and HM06 states that the four topologies coincide iff $H$ is finite-dimensional. In finite dimensions non-degeneracy and unitality coincide for $*$-subalgebras — see (X5) | a | +| commutative | no effect; neither proof mentions commutativity, and the theorem keeps its content ($C[0,1]$ on $L^2[0,1]$ is neither WOT-closed nor its own bicommutant) | a | +| non-separable / non-σ-finite | no effect. Neither full proof assumes separability; $\ell^\infty(X)$ on $\ell^2(X)$ for uncountable $X$ is maximal abelian, hence satisfies the form and is not σ-finite | a | +| type III | no effect; the type classification is downstream of this theorem and never upstream of it | a | +| non-unital | **this is where the variants differ, and the difference is real.** $K(H)$ for infinite-dimensional $H$ is non-degenerate and non-unital, and satisfies the equivalence negatively: all three conditions fail together, since $K(H)'' = B(H)$ | a | +| degenerate representation | the hypothesis bites — see (X1) | — | +| universally orthogonal index element (here: large joint kernel or a reducing subspace) | a reducing subspace alone has no effect ($\mathbb{C}1$ on $\mathbb{C}^2$); a summand on which $M$ acts as zero breaks (i) and only (i). NAA13's failure of Haag duality for infinite regions is **not** a boundary of this theorem — it is the identification of $\pi(A(\Lambda))''$ with another algebra's commutant that fails, not the bicommutant construction | a | +| quantifier swap: non-degeneracy $\forall x \forall T \mapsto \forall T \forall x$ | meaning changes and the swapped form is wrong: it says every element of $M$ is injective, which fails for $M = B(\mathbb{C}^2)$, $T = e_{11}$ — the paradigm von Neumann algebra. See (X10) | — | +| quantifier swap: inside the commutant | degenerate probe. The two universals are separated by an implication and by different sorts; exchanging them is not type-correct. No row | — | +| hypothesis dropped: (A1) non-degeneracy | theorem false; (i)⇒(ii) and (ii)⇔(iii) survive, (iii)⇒(i) dies. See (X1) | — | +| hypothesis dropped: (A3) self-adjointness | theorem false. See (X2) | — | +| hypothesis dropped: (A5) algebra structure | theorem false. See (X3) | — | +| hypothesis dropped: (A4) norm-closedness | **droppable — this is what the adopted form does.** The enlarged class is inhabited by $F(H)$, for which all three conditions fail together. See (X4) | — | +| hypothesis dropped: (A9) separability | already dropped; no effect | a | +| hypothesis dropped: complex scalars | **open** — every corpus source works over $\mathbb{C}$, none states the real case, and neither a proof nor a counterexample was found | — | + +## Rejected formulations and refuted claims + +**Append-only.** + +| id | Candidate or claim | Disposition | Discriminator | Tier | Date | +|---|---|---|---|---|---| +| (X1) | the theorem with (A1) dropped — equivalently, the unital variants (D3),(D5),(D6),(D7),(D9) as a *general* form | rejected | **(X1) separating object** — $M = \mathbb{C}e_{11} \subseteq M_2(\mathbb{C})$ is a closed self-adjoint algebra with $M' = $ the diagonal, so $M'' = \mathbb{C}e_{11} \oplus \mathbb{C}e_{22} \supsetneq M$ while (ii),(iii) hold; in infinite dimensions $B(H_0) \oplus 0$. Against the unital variants the separating object is $K(H)$, $\dim H = \infty$, which they do not cover | a | 2026-08-16 | +| (X2) | the theorem with (A3) dropped | rejected | **(X1) separating object** — the upper-triangular $2\times2$ complex matrices: unital, closed in every topology, $M' = \mathbb{C}1$, $M'' = M_2(\mathbb{C}) \supsetneq M$ | a | 2026-08-16 | +| (X3) | the theorem for a self-adjoint *subspace* rather than an algebra | rejected | **(X1) separating object** — $V = \operatorname{span}_{\mathbb{C}}\{1, e_{12}+e_{21}\} \subseteq M_3(\mathbb{C})$: $\dim V = 2$, and $e_{12}+e_{21}$ has three simple eigenvalues so $V''$ is a $3$-dimensional maximal abelian algebra. In $M_2$ the same construction gives no separation | a | 2026-08-16 | +| (X4) | keeping SHI12's norm-closedness hypothesis | rejected | **(X3) generality loss** — the finite-rank operators $F(H)$ on infinite-dimensional $H$ form a non-degenerate $*$-subalgebra that is not norm-closed, with $F(H)' = \mathbb{C}1$, so all three conditions fail together and the equivalence holds. Keeping the hypothesis drops that class and buys nothing: no proof step consumes it and each condition implies it | a | 2026-08-16 | +| (X5) | the unital form as a *distinct* theorem in finite dimensions | equivalent | — (in finite dimensions $M$ is automatically SOT-closed, so (iii)⇒(i) applies and delivers $M = M''$, which is unital; conditional equivalence with the assumption $\dim H < \infty$ named) | a | 2026-08-16 | +| (X6) | *claim*: the non-degenerate form is strictly more general than the unital form | adopted, sharpened | its entire extra content is the implication "non-degenerate and WOT-closed $\Rightarrow 1 \in M$": granted, it yields the adopted form; conversely the adopted form yields it because $X'$ is always unital. The extra scope contains only negative instances, and $K(H)$ inhabits it | a | 2026-08-16 | +| (X7) | von Neumann's original **sequential** WOT-completeness (D4) as a formulation of closedness | rejected | **(X1) separating object** — on a non-separable $H$ take $S = \{T : \operatorname{ran} T, \operatorname{ran} T^{*} \text{ separable}\}$ and $M = \mathbb{C}1 + S$: a unital $*$-subalgebra, sequentially WOT-closed, with $M' = \mathbb{C}1$ so $M'' = B(H)$, yet $M \ne B(H)$. For **separable** $H$ the two coincide, by Kaplansky density (R12) plus metrizability of SOT on the unit ball | b | 2026-08-16 | +| (X8) | *claim*: SOR23's statement of the theorem is false as written | refuted | SOR23's own definition of "$*$-subalgebra" includes the identity, so its statement is the standard unital one and is true. The witnesses $\{0\}$ and $\mathbb{C}p$ refute it only under the standard non-unital reading — they are a convention discriminator, recorded at (D8), not a defect | a | 2026-08-16 | +| (X9) | KOS13's σ-weak / σ-strong / σ-strong-⋆ form (D9) as a *different* theorem | equivalent | — (for a non-degenerate $*$-subalgebra all six closure conditions coincide; the argument runs SHI12's proof on the infinite ampliation $T \mapsto T \otimes 1$, whose seminorms pull back to the σ-topologies. **No corpus source states this**, and the ampliation identity it consumes is an unretrieved external, so the row is tier (d) as a whole. A bounded-set cross-check grounds the σ-weak and σ-strong branches for *unital* $M$ without that external; the σ-strong-⋆ branch does not survive the cross-check and keeps the (d) input) | d | 2026-08-16 | +| (X10) | non-degeneracy read as "every element of $M$ is injective" | rejected | **(X2) degeneracy** — the reading excludes $M = B(H)$ for $\dim H \ge 2$ (take $T = e_{11}$), i.e. the paradigm case the form must cover | a | 2026-08-16 | +| (X11) | non-degeneracy read as "$MH$ is dense in $H$" | equivalent | — (equivalent given (A3); the two come apart without it, separating object $\operatorname{span}\{e_{11}, e_{12}\} \subseteq M_2(\mathbb{C})$, an algebra with trivial joint kernel whose range is not dense. Conditional equivalence with the assumption $M = M^{*}$ named) | a | 2026-08-16 | +| (X12) | *claim*: HM06's fact that the weak, ultraweak and norm closures of a bounded convex set agree | refuted | the closed unit ball of $K(H)$, $\dim H = \infty$, is bounded and convex; its norm closure is itself and its weak closure is the unit ball of $B(H)$, by (R13) and (R12). Deleting "norm" makes the statement true | a | 2026-08-16 | + +## Prior art + +| System | Found | Relation to variants | How searched | Measured at | +|---|---|---|---|---| +| Mathlib | `VonNeumannAlgebra`, a structure extending `StarSubalgebra ℂ (H →L[ℂ] H)` whose defining field states that the centralizer of the centralizer of the carrier is the carrier | same as (D1)/(D8) — algebraic, and **unital by construction** since `StarSubalgebra` is; non-degeneracy is nowhere mentioned, so relative to (D2) it is stronger on hypotheses and $K(H)$ separates them | `grep -rn "VonNeumannAlgebra"` over `.lake/packages/mathlib`, whole file read; `lean_leansearch`; `lean_loogle` on the centralizer pattern | mathlib rev `5450b53e` | +| Mathlib | `WStarAlgebra`, a separate structure with a single field asserting a predual exists | same as (D10) — Mathlib follows KOS13's separation of the two notions, not HIA20's identification | same sweep | mathlib rev `5450b53e` | +| Mathlib | could not find any declaration equating WOT- or SOT-closedness with the bicommutant condition, having searched `grep -rni "bicommutant\|double.commutant\|doubleCommutant"`, `grep -rni "commutant"`, `lean_leansearch`, `lean_loogle` and `lean_leanfinder`. Mathlib's own module docstring says the equivalence and the theorem remain to be proved, and names a (D6)-shaped target | — | as listed | mathlib rev `5450b53e` | +| Mathlib | `Set.centralizer`, `Set.centralizer_centralizer_centralizer`, `StarSubalgebra.centralizer`, `VonNeumannAlgebra.commutant_commutant` (which holds by definition, not by a topological argument), `StarSubalgebra.topologicalClosure_adjoin_le_centralizer_centralizer` (an inclusion in the **norm** topology) | weaker than every corpus variant | same sweep | mathlib rev `5450b53e` | +| Mathlib | WOT is present (`→WOT[𝕜]`, `toWOT`); SOT is present under the name of the topology of pointwise convergence, with a docstring saying the term "strong operator topology" is deliberately avoided | — | `grep -rn "StrongOperatorTopology"` returned nothing, which prompted `grep -rni "strong operator topology"` | mathlib rev `5450b53e` | +| Mathlib | could not find Kaplansky density, a Borel/measurable functional calculus, spectral measures, direct integrals, σ-weak or σ-strong topologies, or normal states. The spectral theorem is present only in a finite-dimensional diagonalization form; the **continuous** functional calculus is present in full | — | `grep -rni` per term | mathlib rev `5450b53e` | +| This repository | `WOTClosedSubalgebra.doubleCommutant_eq_of_isWOTClosed`, `SOTClosedSubalgebra.doubleCommutant_eq_of_isSOTClosed`, and `SOTClosedSubalgebra.mem_sotClosure_of_mem_doubleCommutant` under `QuantumSystem/Algebra/Star/DoubleCommutant/`, with no `sorry` or `axiom` in that directory | same as (D3)/(D5) — all three take a `StarSubalgebra`, hence **unital**; none is stated for a non-unital or non-degenerate algebra. The third is the density statement (R2) in unital form, carrying no closedness hypothesis. The SOT theorem is derived from the WOT one, so the two are not independent proofs | file read; `grep -rn "sorry\|axiom "`; repo-wide grep for non-degeneracy finds it only in unrelated files. Statement-level measurement only — no `lake build` was run | repo `9b1810d` | +| This repository | could not find any equivalence (`iff`/TFAE) packaging the three conditions, nor any lemma constructing a `VonNeumannAlgebra` from a closed `StarSubalgebra`. Both main theorems are leaves: the WOT one is called only by the SOT one, and the SOT one is called nowhere | — | `grep -rn "TFAE\|IsWOTClosed.*↔\|↔ IsSOTClosed"`, call-site grep | repo `9b1810d` | +| mathlib4 GitHub | PR #35538, "feat(Analysis/VonNeumannAlgebra): double commutant theorem", opened 2026-02-19 and **closed unmerged** 2026-03-09. Its main statement is a two-condition WOT form for a unital `StarSubalgebra`, by the same diagonal-amplification route. Closed over a review disagreement; no mathematical obstruction appears in the thread | same as (D6) | unauthenticated GitHub REST search, then the PR, comments and files endpoints | 2026-08-16 | +| Lean AI leaderboard | the three-condition unital form is listed as a benchmark problem and is **solved**, first on 2026-05-09 and seven times since | same as (D3)/(D5) | fetched the problem page | 2026-08-16 | +| Isabelle AFP | `Complex_Bounded_Operators` provides complex Hilbert spaces, bounded operators, adjoints and projections; its abstract mentions no von Neumann algebra, commutant or operator topology | unrelated — substrate only | two web searches plus the entry abstract; the AFP search page returned only site chrome, so this negative rests on a weak instrument | 2026-08-16 | +| Coq / Rocq / mathcomp | could not find a von Neumann algebra or commutant development, having run **one** query. This is a single-query result, not an absence | — | one web search | 2026-08-16 | +| Lean Zulip | no archive page was retrieved by any of four searches; the archive appears poorly indexed and the Zulip API was not queried | — | four web searches | 2026-08-16 | + +## Open questions + +- Does the adopted form hold over a **real** Hilbert space? No corpus source + treats it, and neither a proof nor a counterexample was found. +- (A11): for which density characters between $\aleph_1$ and $2^{\aleph_0}$ does + (R15) fail? The argument on file settles only $> 2^{\aleph_0}$. +- (X9) is tier (d) as a whole because its σ-strong-⋆ branch consumes an + unretrieved external (the infinite-ampliation commutant identity). Grounding + it needs either that identity or a self-adjoint form of Kaplansky density, + which HIA20 does not state. +- Whether von Neumann's paper is dated 1929 or 1930 cannot be settled here: the + corpus's two dates attach to bibliographically identical data, so there is one + paper in play, and only the original could say whether 1929 is a submission + year against a 1930 issue. + +## Sources + +**Append-only.** + +| Key | Work | Status | Cache | Version | Tier reached | Retrieved | +|---|---|---|---|---|---|---| +| SHI12 | V. Shirbisheh, *Lectures on C\*-algebras*, arXiv:1211.3404 | retrieved | `references/arxiv-1211.3404/` | arXiv | a | 2026-08-16 | +| LAN98 | N. P. Landsman, *Lecture Notes on C\*-algebras, Hilbert C\*-modules and Quantum Mechanics*, arXiv math-ph/9807030 | retrieved | `references/arxiv-math-ph-9807030/` | arXiv | a | 2026-08-16 | +| HIA20 | F. Hiai, *Concise lectures on selected topics of von Neumann algebras*, arXiv:2004.02383 | retrieved | `references/arxiv-2004.02383/` | arXiv | a | 2026-08-16 | +| KOS13 | R. P. Kostecki, *W\*-algebras and noncommutative integration*, arXiv:1307.4818 | retrieved | `references/arxiv-1307.4818/` | arXiv | b (macros unavailable) | 2026-08-16 | +| SOR23 | J. Sorce, *Notes on the type classification of von Neumann algebras*, arXiv:2302.01958 | retrieved | `references/arxiv-2302.01958/` | arXiv | a | 2026-08-16 | +| NAA13 | P. Naaijkens, *Quantum spin systems on infinite lattices*, arXiv:1311.2717 | retrieved | `references/arxiv-1311.2717/` | arXiv | a | 2026-08-16 | +| HM06 | H. Halvorson, M. Müger, *Algebraic Quantum Field Theory*, arXiv math-ph/0602036 | retrieved | `references/arxiv-math-ph-0602036/` | arXiv | a | 2026-08-16 | +| VN30 | J. von Neumann, *Zur Algebra der Funktionaloperationen und Theorie der normalen Operatoren*, Math. Ann. 102 (1930) 370–427 | not retrieved — tried the GDZ id and mets endpoints (JavaScript-only shell, no METS served) and EUDML doc/159384 (HTTP 403); Springer paywall not pursued | — | — | c | 2026-08-16 | +| CON00 | J. B. Conway, *A Course in Operator Theory*, American Mathematical Society, 2000 | not retrieved | — | — | d | 2026-08-16 | +| PED79 | G. K. Pedersen, *C\*-algebras and their Automorphism Groups* | not retrieved | — | — | b (method attribution only) | 2026-08-16 | +| MUR90 / DIX77 / TAK79 / BLA06 | the standard C\*-algebra and operator-algebra textbooks | not retrieved | — | — | c | 2026-08-16 | + +## Not investigated + +- **The `[ext: …]` edges lane 5 never reached.** Formalization status was + measured for Kaplansky density, the spectral theorem, the Borel functional + calculus, Sakai's characterisation, the reduction/direct-integral theorem and + the σ-topologies. It was **not** measured for: the single-generator theorem; + the Dixmier and Conway pointers; Pedersen's proof strategy; Wedderburn's + decomposition result; Murray–von Neumann 1936; Bratteli–Robinson's + infinite-region statement; the infinite-ampliation commutant identity that (X9) consumes; and + the identification $C[0,1]'' = L^\infty[0,1]$ that the commutative-case row + uses. +- **Sources listed as not retrieved, and what rests on them.** VN30 carries the + attribution of the theorem itself and of (R15); every row citing it is (c) and + carries a statement instead of a locator. CON00 carries SOR23's only proof + pointer. PED79 carries SHI12's method attribution — nothing in SHI12's proof + depends on it for correctness. The textbook row is why no note in this + repository may carry a locator into any of them. +- **Degeneracy checklist items skipped:** none. The real-scalar case is filed + `open` rather than skipped. +- **Variants sighted and not pursued.** KOS13's relative commutant inside an + arbitrary ambient algebra is recorded at (D9) but not developed — the note + treats only the case where the ambient algebra is $B(H)$. KOS13's later + sections (spatial derivatives, Connes cocycles) and HIA20's later chapters + were not swept for restatements of the theorem carrying different hypotheses. +- **Internal edges never opened**, so the floor of the proof readings is: SHI12's + Hahn–Banach separation for locally convex spaces, its Riesz representation for + bounded sesquilinear forms, its Cauchy–Schwarz equality case, and two of its + remarks; LAN98's decomposition into self-adjoint parts and its refined + Gelfand–Naimark decomposition. (R6), (R3)(v) and (R4) therefore have + unverified floors. +- **The unexamined base.** Everything above stands on: the tier (c) attribution + of the theorem to VN30, which no one here has opened; the tier (d) row (X9), + which is the only bridge between the corpus's WOT/SOT framework and its + σ-topology framework; the tier (b) reading (R2) that the corpus proof + establishes the density form, which no source states; the tier (b) status of + every mathematical reading of a KOS13 quote, whose macros cannot be + reconstructed from the arXiv package; and, for the prior-art rows, a + statement-level measurement of this repository that was never elaborated by + `lake build`. From ae20f4ae1d889f69c760716e2231aa08cb1c5df0 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 19:03:13 +0000 Subject: [PATCH 108/113] docs: add the 'do not bridge what should be unified' principle to AGENTS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit State the rule against reimplementing a Mathlib object locally and papering over the mismatch with a conversion lemma or Equiv/Homeomorph — migrate to the Mathlib object instead, since a bridge makes the duplication permanent and a ForMathlib/ copy can never be upstreamed once one exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- AGENTS.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index f07bd8a..bc97b67 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,6 +41,23 @@ follow the literature, even when it forces you to build supporting API that Mathlib does not yet provide. +**Do not bridge what should be unified.** +- When Mathlib already provides an object — a type copy, a topology, a + structure — use it. Do not reimplement it locally and then paper over the + mismatch with a conversion lemma, an `Equiv`, or a `Homeomorph` between the + two copies. +- If such a local reimplementation already exists, migrate to the Mathlib + object and delete the local one. Do not add a bridge to keep both alive. +- The same applies to two local spellings of one notion (image vs preimage + form, bundled vs unbundled): pick one and state every result in it. +- A conversion lemma is acceptable only when both sides are genuinely outside + your control — both already in Mathlib, or the local object carries structure + the Mathlib one cannot. + **Why:** a bridge makes the duplication permanent. Every later lemma must + then pick a side and be transported across, and a `ForMathlib/` copy of + something Mathlib already has can never be upstreamed — which is the only + reason that directory exists. + **Prove what is provable; do not *defer* it.** - Do not introduce a `class` / `structure` field (or a `def … : Prop` hypothesis) that stands in for a theorem when that theorem has a known From 2d7f460ff068bdef74691762230e9ac5db8fdc25 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Sun, 16 Aug 2026 19:04:12 +0000 Subject: [PATCH 109/113] chore: wrap lines over 120 columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mechanical /lint-fix pass over the 120-column limit: re-wrap at binders, arguments, and calc steps, and re-flow doc-comment prose. No semantic change — Notation.lean's symbol table is reformatted as an HTML table since a Markdown pipe-table row cannot be wrapped without breaking its syntax. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- .../CStarAlgebra/GNS/Construction.lean | 9 ++++-- .../Algebra/CStarAlgebra/GNS/DirectSum.lean | 7 +++-- .../Algebra/CStarAlgebra/GNS/PureState.lean | 30 +++++++++++++------ .../CStarAlgebra/GNS/Representation.lean | 27 +++++++++++------ .../Algebra/CStarAlgebra/PureState.lean | 12 +++++--- QuantumSystem/Algebra/CStarAlgebra/State.lean | 15 ++++++---- QuantumSystem/Algebra/LocalNet/Net.lean | 4 +-- .../Algebra/LocalNet/SplitProperty.lean | 8 ++--- .../VonNeumannAlgebra/StructureTheorem.lean | 5 ++-- .../Analysis/Entropy/RelativeEntropy.lean | 6 ++-- .../Analysis/Matrix/LiebConcavity.lean | 21 ++++++++----- .../DiagonalAmplification.lean | 3 +- QuantumSystem/Notation.lean | 23 +++++++++----- 13 files changed, 113 insertions(+), 57 deletions(-) diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean index 197fcd4..cae69f8 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Construction.lean @@ -46,7 +46,8 @@ with respect to the positive sesquilinear form coming from the state `ω` (ultim consequence of the Cauchy–Schwarz inequality for states). -/ noncomputable def innerQuotient (xq yq : A ⧸ Nω) : ℂ := Quotient.liftOn₂' xq yq (fun x y => ω (star x * y)) - (fun x₁ y₁ x₂ y₂ (hx : CStarAlgebraIdeal.leftRel Nω x₁ x₂) (hy : CStarAlgebraIdeal.leftRel Nω y₁ y₂) => by + (fun x₁ y₁ x₂ y₂ (hx : CStarAlgebraIdeal.leftRel Nω x₁ x₂) + (hy : CStarAlgebraIdeal.leftRel Nω y₁ y₂) => by rw [CStarAlgebraIdeal.leftRel, QuotientAddGroup.leftRel_apply] at hx hy change ω (star x₁ * y₁) = ω (star x₂ * y₂) have hx' : ω (star (x₂ - x₁) * (x₂ - x₁)) = 0 := by simp only [sub_eq_neg_add]; exact hx @@ -305,7 +306,8 @@ lemma πω_sub (a b : A) : πω ω (a - b) = πω ω a - πω ω b := by /-- Zero element maps to zero operator: `πω(0) = 0`. -/ lemma πω_zero : πω ω (0 : A) = 0 := - ext_on_completion (ω := ω) (πω ω 0) 0 fun x => by simp [πω_apply_coe, πω'_zero, UniformSpace.Completion.coe_zero] + ext_on_completion (ω := ω) (πω ω 0) 0 fun x => by + simp [πω_apply_coe, πω'_zero, UniformSpace.Completion.coe_zero] /-- The bundled non‑unital *-homomorphism `πω : A →⋆ₙₐ[ℂ] 𝓑(Hω)`. -/ noncomputable def πωStarHom : A →⋆ₙₐ[ℂ] 𝓑(Hω) where @@ -525,7 +527,8 @@ lemma ξω_norm : ‖ξω ω‖ = 1 := by by_contra h_not; push Not at h_not -- Expand definition of norm via supremum over ratios ‖ω a‖/‖a‖ rw [State.norm_def] at h_not - obtain ⟨_, ⟨a, ha, rfl⟩, h_r_large⟩ : ∃ r ∈ {s : ℝ | ∃ a : A, a ≠ 0 ∧ s = ‖ω a‖ / ‖a‖}, ‖stateOnQuot ω‖ < r := by + obtain ⟨_, ⟨a, ha, rfl⟩, h_r_large⟩ : + ∃ r ∈ {s : ℝ | ∃ a : A, a ≠ 0 ∧ s = ‖ω a‖ / ‖a‖}, ‖stateOnQuot ω‖ < r := by by_contra h_no; push Not at h_no have : sSup {s : ℝ | ∃ a : A, a ≠ 0 ∧ s = ‖ω a‖ / ‖a‖} ≤ ‖stateOnQuot ω‖ := by refine csSup_le ?_ h_no diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean index 4372566..8e416f6 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/DirectSum.lean @@ -73,7 +73,8 @@ lemma componentWiseMap_memℓp (a : A) (x : Hilbert A) : /-- The norm bound for the component-wise map. -/ lemma componentWiseMap_norm_bound (a : A) (x : Hilbert A) : - ‖(⟨fun ψ => componentWiseMap a ψ (x.val ψ), componentWiseMap_memℓp a x⟩ : Hilbert A)‖ ≤ ‖a‖ * ‖x‖ := by + ‖(⟨fun ψ => componentWiseMap a ψ (x.val ψ), componentWiseMap_memℓp a x⟩ : Hilbert A)‖ + ≤ ‖a‖ * ‖x‖ := by have h2pos : (0 : ℝ) < (2 : ℝ≥0∞).toReal := by norm_num have h2 : (2 : ℝ≥0∞).toReal = 2 := by norm_num rw [lp.norm_eq_tsum_rpow h2pos, lp.norm_eq_tsum_rpow h2pos] @@ -88,7 +89,9 @@ lemma componentWiseMap_norm_bound (a : A) (x : Hilbert A) : rw [memℓp_gen_iff zero_lt_two] at this simp only [h2] at this exact this - have sum_ineq : ∑' ψ, ‖componentWiseMap a ψ (x.val ψ)‖ ^ (2 : ℝ) ≤ ‖a‖ ^ 2 * ∑' ψ, ‖x.val ψ‖ ^ (2 : ℝ) := by + have sum_ineq : + ∑' ψ, ‖componentWiseMap a ψ (x.val ψ)‖ ^ (2 : ℝ) ≤ + ‖a‖ ^ 2 * ∑' ψ, ‖x.val ψ‖ ^ (2 : ℝ) := by rw [← tsum_mul_left] apply tsum_le_of_sum_le' (by positivity) intro s diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean index b57730a..ed86017 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/PureState.lean @@ -279,8 +279,11 @@ lemma normalized_vectorFunctional_mem_quasiStateSpace (T : GNS.Representation ω lemma trichotomy_from_purity {ψ : PureState A} - (W : Submodule ℂ (PureState.gnsRepresentation ψ).H) (hWinv : (PureState.gnsRepresentation ψ).IsInvariant W) (_hWclosed : IsClosed (W : Set (PureState.gnsRepresentation ψ).H)) - (v₁ v₂ : (PureState.gnsRepresentation ψ).H) (hv₁ : v₁ ∈ W) (hv₂ : v₂ ∈ Wᗮ) (hξ : (PureState.gnsRepresentation ψ).ξ = v₁ + v₂) (horth : ⟪v₁, v₂⟫ = 0) : + (W : Submodule ℂ (PureState.gnsRepresentation ψ).H) + (hWinv : (PureState.gnsRepresentation ψ).IsInvariant W) + (_hWclosed : IsClosed (W : Set (PureState.gnsRepresentation ψ).H)) + (v₁ v₂ : (PureState.gnsRepresentation ψ).H) (hv₁ : v₁ ∈ W) (hv₂ : v₂ ∈ Wᗮ) + (hξ : (PureState.gnsRepresentation ψ).ξ = v₁ + v₂) (horth : ⟪v₁, v₂⟫ = 0) : ‖v₁‖ ^ 2 = 0 ∨ ‖v₁‖ ^ 2 = 1 := by let T := PureState.gnsRepresentation ψ by_contra h_contra @@ -413,10 +416,12 @@ lemma trichotomy_from_purity {ψ : PureState A} rw [h_decomp] have h1 : (T.π a) v₁ - v₁ ∈ W := Submodule.sub_mem W (hWinv a ⟨v₁, hv₁, rfl⟩) hv₁ have h2 : (T.π a) v₂ ∈ Wᗮ := isInvariant_orthogonal T W hWinv a ⟨v₂, hv₂, rfl⟩ - have h_pythag := norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero ((T.π a) v₁ - v₁) ((T.π a) v₂) ((Submodule.mem_orthogonal W _).mp h2 _ h1) + have h_pythag := norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero + ((T.π a) v₁ - v₁) ((T.π a) v₂) ((Submodule.mem_orthogonal W _).mp h2 _ h1) rw [← sq, ← sq, ← sq] at h_pythag exact h_pythag - have h_sq_le : ‖(T.π a) v₁ - v₁‖ ^ 2 ≤ ‖(T.π a) T.ξ - v₁‖ ^ 2 := by rw [h_orth]; linarith [sq_nonneg ‖(T.π a) v₂‖] + have h_sq_le : ‖(T.π a) v₁ - v₁‖ ^ 2 ≤ ‖(T.π a) T.ξ - v₁‖ ^ 2 := by + rw [h_orth]; linarith [sq_nonneg ‖(T.π a) v₂‖] rw [sq_le_sq, abs_of_nonneg (norm_nonneg _), abs_of_nonneg (norm_nonneg _)] at h_sq_le exact lt_of_le_of_lt h_sq_le ha have h_norm_v2 : ‖(T.π a) v₂‖ < ε := by @@ -427,10 +432,12 @@ lemma trichotomy_from_purity {ψ : PureState A} rw [h_decomp] have h1 : (T.π a) v₁ - v₁ ∈ W := Submodule.sub_mem W (hWinv a ⟨v₁, hv₁, rfl⟩) hv₁ have h2 : (T.π a) v₂ ∈ Wᗮ := isInvariant_orthogonal T W hWinv a ⟨v₂, hv₂, rfl⟩ - have h_pythag := norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero ((T.π a) v₁ - v₁) ((T.π a) v₂) ((Submodule.mem_orthogonal W _).mp h2 _ h1) + have h_pythag := norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero + ((T.π a) v₁ - v₁) ((T.π a) v₂) ((Submodule.mem_orthogonal W _).mp h2 _ h1) rw [← sq, ← sq, ← sq] at h_pythag exact h_pythag - have h_sq_le : ‖(T.π a) v₂‖ ^ 2 ≤ ‖(T.π a) T.ξ - v₁‖ ^ 2 := by rw [h_orth]; linarith [sq_nonneg ‖(T.π a) v₁ - v₁‖] + have h_sq_le : ‖(T.π a) v₂‖ ^ 2 ≤ ‖(T.π a) T.ξ - v₁‖ ^ 2 := by + rw [h_orth]; linarith [sq_nonneg ‖(T.π a) v₁ - v₁‖] rw [sq_le_sq, abs_of_nonneg (norm_nonneg _), abs_of_nonneg (norm_nonneg _)] at h_sq_le exact lt_of_le_of_lt h_sq_le ha -- Contradiction @@ -463,7 +470,9 @@ lemma trichotomy_from_purity {ψ : PureState A} · apply mul_lt_mul_of_pos_left h_norm_diff hv₁_norm_pos · exact inv_pos.mpr h_pos _ = ε * (t⁻¹ * ‖v₁‖) := by ring - _ ≤ ε * K := by gcongr; apply le_add_of_nonneg_right; apply mul_nonneg (inv_nonneg.mpr (by linarith)) (norm_nonneg _) + _ ≤ ε * K := by + gcongr; apply le_add_of_nonneg_right + apply mul_nonneg (inv_nonneg.mpr (by linarith)) (norm_nonneg _) _ = 1/2 := by dsimp [ε] have hK_ne : K ≠ 0 := hK_pos.ne' @@ -479,7 +488,8 @@ lemma trichotomy_from_purity {ψ : PureState A} dsimp only [χ] change ‖(1 - (t : ℂ))⁻¹ • (T.vectorFunctional v₂) a‖ < 1/2 rw [vectorFunctional_apply, smul_eq_mul] - rw [norm_mul, ← Complex.ofReal_one, ← Complex.ofReal_sub, norm_inv, Complex.norm_real, Real.norm_eq_abs, abs_of_pos (by linarith : 0 < 1 - t)] + rw [norm_mul, ← Complex.ofReal_one, ← Complex.ofReal_sub, norm_inv, Complex.norm_real, + Real.norm_eq_abs, abs_of_pos (by linarith : 0 < 1 - t)] calc (1 - t)⁻¹ * ‖⟪v₂, (T.π a) v₂⟫‖ _ ≤ (1 - t)⁻¹ * (‖v₂‖ * ‖(T.π a) v₂‖) := by apply mul_le_mul_of_nonneg_left @@ -490,7 +500,9 @@ lemma trichotomy_from_purity {ψ : PureState A} · apply mul_lt_mul_of_pos_left h_norm_v2 hv₂_norm_pos · exact inv_pos.mpr (by linarith) _ = ε * ((1 - t)⁻¹ * ‖v₂‖) := by ring - _ ≤ ε * K := by gcongr; apply le_add_of_nonneg_left; apply mul_nonneg (inv_nonneg.mpr (by linarith)) (norm_nonneg _) + _ ≤ ε * K := by + gcongr; apply le_add_of_nonneg_left + apply mul_nonneg (inv_nonneg.mpr (by linarith)) (norm_nonneg _) _ = 1/2 := by dsimp [ε] have hK_ne : K ≠ 0 := hK_pos.ne' diff --git a/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean b/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean index 62e6eb8..8a4df78 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/GNS/Representation.lean @@ -300,7 +300,8 @@ private lemma linear_isometry_equiv_map_cyclic_vector (T₁ T₂ : Representatio U T₁.ξ = T₂.ξ := by suffices ‖(U : T₁.H →L[ℂ] T₂.H) T₁.ξ - T₂.ξ‖ = 0 by exact eq_of_sub_eq_zero (norm_eq_zero.mp this) refine le_antisymm (le_of_forall_pos_le_add fun ε hε => ?_) (norm_nonneg _) - obtain ⟨x₁, hx₁_close, hx₁_mem⟩ := Metric.dense_iff.mp (dense_cyclicSet T₁) T₁.ξ (ε / 2) (by linarith : 0 < ε / 2) + obtain ⟨x₁, hx₁_close, hx₁_mem⟩ := + Metric.dense_iff.mp (dense_cyclicSet T₁) T₁.ξ (ε / 2) (by linarith : 0 < ε / 2) obtain ⟨a, ha⟩ := Set.mem_iUnion.mp hx₁_mem simp only [Set.mem_singleton_iff] at ha subst ha; rw [Metric.mem_ball, dist_eq_norm] at hx₁_close @@ -308,8 +309,10 @@ private lemma linear_isometry_equiv_map_cyclic_vector (T₁ T₂ : Representatio calc ‖(U : T₁.H →L[ℂ] T₂.H) T₁.ξ - T₂.ξ‖ ≤ ‖(U : T₁.H →L[ℂ] T₂.H) T₁.ξ - (U : T₁.H →L[ℂ] T₂.H) (T₁.π a T₁.ξ)‖ + ‖(U : T₁.H →L[ℂ] T₂.H) (T₁.π a T₁.ξ) - T₂.ξ‖ := by - convert norm_add_le ((U : T₁.H →L[ℂ] T₂.H) T₁.ξ - (U : T₁.H →L[ℂ] T₂.H) (T₁.π a T₁.ξ)) - ((U : T₁.H →L[ℂ] T₂.H) (T₁.π a T₁.ξ) - T₂.ξ) using 2; abel + convert norm_add_le + ((U : T₁.H →L[ℂ] T₂.H) T₁.ξ - (U : T₁.H →L[ℂ] T₂.H) (T₁.π a T₁.ξ)) + ((U : T₁.H →L[ℂ] T₂.H) (T₁.π a T₁.ξ) - T₂.ξ) using 2 + abel _ = ‖(U : T₁.H →L[ℂ] T₂.H) (T₁.ξ - T₁.π a T₁.ξ)‖ + ‖T₂.π a T₂.ξ - T₂.ξ‖ := by rw [map_sub, h_cyclic] _ = ‖T₁.ξ - T₁.π a T₁.ξ‖ + ‖T₂.π a T₂.ξ - T₂.ξ‖ := by @@ -348,7 +351,8 @@ private lemma linear_isometry_equiv_intertwines (T₁ T₂ : Representation ω) simp only [ContinuousLinearMap.coe_comp', Function.comp_apply] have h_dense := dense_cyclicSet T₁ unfold cyclicSet at h_dense - have h_on_cyclic : ∀ b : A, (U : T₁.H →L[ℂ] T₂.H) (T₁.π a (T₁.π b T₁.ξ)) = T₂.π a ((U : T₁.H →L[ℂ] T₂.H) (T₁.π b T₁.ξ)) := + have h_on_cyclic : ∀ b : A, (U : T₁.H →L[ℂ] T₂.H) (T₁.π a (T₁.π b T₁.ξ)) = + T₂.π a ((U : T₁.H →L[ℂ] T₂.H) (T₁.π b T₁.ξ)) := fun b => linear_isometry_equiv_intertwines_on_cyclic T₁ T₂ U h_cyclic a b let f : T₁.H → T₂.H := fun y => (U : T₁.H →L[ℂ] T₂.H) (T₁.π a y) let g : T₁.H → T₂.H := fun y => T₂.π a ((U : T₁.H →L[ℂ] T₂.H) y) @@ -388,7 +392,8 @@ private lemma extendCyclicMap_eq (T₁ T₂ : Representation ω) (x : cyclicSet (cyclicMap T₁ T₂) (cyclicMap_isometry T₁ T₂) x private lemma extend_cyclic_map_left_inv (T₁ T₂ : Representation ω) : - ∀ x : T₁.H, (extendCyclicMap (T₁ := T₂) (T₂ := T₁)) ((extendCyclicMap (T₁ := T₁) (T₂ := T₂)) x) = x := by + ∀ x : T₁.H, + (extendCyclicMap (T₁ := T₂) (T₂ := T₁)) ((extendCyclicMap (T₁ := T₁) (T₂ := T₂)) x) = x := by intro x set U_fun := extendCyclicMap (T₁ := T₁) (T₂ := T₂) set V_fun := extendCyclicMap (T₁ := T₂) (T₂ := T₁) @@ -414,7 +419,8 @@ private lemma extend_cyclic_map_left_inv (T₁ T₂ : Representation ω) : _ = T₁.π a T₁.ξ := hV private lemma extend_cyclic_map_right_inv (T₁ T₂ : Representation ω) : - ∀ y : T₂.H, (extendCyclicMap (T₁ := T₁) (T₂ := T₂)) ((extendCyclicMap (T₁ := T₂) (T₂ := T₁)) y) = y := by + ∀ y : T₂.H, + (extendCyclicMap (T₁ := T₁) (T₂ := T₂)) ((extendCyclicMap (T₁ := T₂) (T₂ := T₁)) y) = y := by intro y set U_fun := extendCyclicMap (T₁ := T₁) (T₂ := T₂) set V_fun := extendCyclicMap (T₁ := T₂) (T₂ := T₁) @@ -460,9 +466,11 @@ private lemma extend_cyclic_map_add (T₁ T₂ : Representation ω) : (cyclicMap_well_defined T₁ T₂ ⟨_, mem_cyclicSet (T := T₁) b⟩ b rfl) calc U_fun (T₁.π a T₁.ξ + T₁.π b T₁.ξ) = U_fun ((T₁.π a + T₁.π b) T₁.ξ) := by rw [ContinuousLinearMap.add_apply] - _ = U_fun (T₁.π (a + b) T₁.ξ) := by rw [show T₁.π (a + b) = T₁.π a + T₁.π b from T₁.π.map_add' a b] + _ = U_fun (T₁.π (a + b) T₁.ξ) := by + rw [show T₁.π (a + b) = T₁.π a + T₁.π b from T₁.π.map_add' a b] _ = T₂.π (a + b) T₂.ξ := hUab - _ = (T₂.π a + T₂.π b) T₂.ξ := by rw [show T₂.π (a + b) = T₂.π a + T₂.π b from T₂.π.map_add' a b] + _ = (T₂.π a + T₂.π b) T₂.ξ := by + rw [show T₂.π (a + b) = T₂.π a + T₂.π b from T₂.π.map_add' a b] _ = T₂.π a T₂.ξ + T₂.π b T₂.ξ := by rw [ContinuousLinearMap.add_apply] _ = U_fun (T₁.π a T₁.ξ) + U_fun (T₁.π b T₁.ξ) := by rw [← hUa, ← hUb] @@ -484,7 +492,8 @@ private lemma extend_cyclic_map_smul (T₁ T₂ : Representation ω) : change U_fun (c • T₁.π a T₁.ξ) = c • U_fun (T₁.π a T₁.ξ) calc U_fun (c • T₁.π a T₁.ξ) = U_fun ((c • T₁.π a) T₁.ξ) := rfl - _ = U_fun ((T₁.π (c • a)) T₁.ξ) := by rw [show T₁.π (c • a) = c • T₁.π a from T₁.π.map_smul' c a] + _ = U_fun ((T₁.π (c • a)) T₁.ξ) := by + rw [show T₁.π (c • a) = c • T₁.π a from T₁.π.map_smul' c a] _ = T₂.π (c • a) T₂.ξ := hU1 _ = (c • T₂.π a) T₂.ξ := by rw [show T₂.π (c • a) = c • T₂.π a from T₂.π.map_smul' c a] _ = c • T₂.π a T₂.ξ := rfl diff --git a/QuantumSystem/Algebra/CStarAlgebra/PureState.lean b/QuantumSystem/Algebra/CStarAlgebra/PureState.lean index 84eca5a..e3e0f60 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/PureState.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/PureState.lean @@ -165,7 +165,8 @@ private lemma exists_unitization_state_norm (b : A) (hb : 0 ≤ b) (hb_ne : b haveI : IsStarNormal b' := IsSelfAdjoint.isStarNormal (IsSelfAdjoint.of_nonneg hb') haveI : IsClosed (StarAlgebra.elemental ℂ b' : Set (Unitization ℂ A)) := StarAlgebra.elemental.isClosed ℂ b' - have h_spec_S : (‖b'‖ : ℂ) ∈ spectrum ℂ (⟨b', StarAlgebra.elemental.self_mem ℂ b'⟩ : StarAlgebra.elemental ℂ b') := by + have h_spec_S : (‖b'‖ : ℂ) ∈ + spectrum ℂ (⟨b', StarAlgebra.elemental.self_mem ℂ b'⟩ : StarAlgebra.elemental ℂ b') := by rwa [StarSubalgebra.spectrum_eq] obtain ⟨φ, hφ⟩ := WeakDual.CharacterSpace.mem_spectrum_iff_exists.mp h_spec_S -- Extend φ to a state ψ on Unitization ℂ A @@ -345,7 +346,8 @@ noncomputable def toState {φ : WeakDual ℂ A} (h : IsPureState φ) : State ℂ simp [h_all_zero a] exact h_ne_zero this.symm obtain ⟨a₀, ha₀⟩ := h_exists - have h_nonempty : { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ }.Nonempty := + have h_nonempty : + { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ }.Nonempty := ⟨‖(WeakDual.toStrongDual φ) a₀‖ / ‖a₀‖, a₀, ha₀, rfl⟩ have h_bdd : BddAbove { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ } := by use ‖WeakDual.toStrongDual φ‖ @@ -356,7 +358,8 @@ noncomputable def toState {φ : WeakDual ℂ A} (h : IsPureState φ) : State ℂ have h_opNorm_eq : ‖WeakDual.toStrongDual φ‖ = sSup { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ } := by apply le_antisymm - · have h_nonneg : 0 ≤ sSup { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ } := by + · have h_nonneg : + 0 ≤ sSup { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ } := by apply Real.sSup_nonneg rintro _ ⟨a, _, rfl⟩ exact div_nonneg (norm_nonneg _) (norm_nonneg _) @@ -367,7 +370,8 @@ noncomputable def toState {φ : WeakDual ℂ A} (h : IsPureState φ) : State ℂ · rw [mul_comm] calc ‖(WeakDual.toStrongDual φ) a‖ = ‖a‖ * (‖(WeakDual.toStrongDual φ) a‖ / ‖a‖) := by field_simp [norm_pos_iff.mpr ha] - _ ≤ ‖a‖ * sSup { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ } := by + _ ≤ ‖a‖ * + sSup { r : ℝ | ∃ a : A, a ≠ 0 ∧ r = ‖(WeakDual.toStrongDual φ) a‖ / ‖a‖ } := by apply mul_le_mul_of_nonneg_left _ (norm_nonneg _) apply le_csSup h_bdd exact ⟨a, ha, rfl⟩ diff --git a/QuantumSystem/Algebra/CStarAlgebra/State.lean b/QuantumSystem/Algebra/CStarAlgebra/State.lean index 559baa5..b9a9c76 100644 --- a/QuantumSystem/Algebra/CStarAlgebra/State.lean +++ b/QuantumSystem/Algebra/CStarAlgebra/State.lean @@ -172,18 +172,21 @@ lemma cauchy_schwarz_ineq : ‖ω (star y * x)‖^2 ≤ (ω (star x * x)) * (ω intro t obtain ⟨γ, hγ_norm, hγ_phase⟩ := Complex.phase_alignment (ω (star y * x)) let s : A := ((t : ℂ) * γ) • x + y - have hexp2 : (ω (star s * s)).re = (positiveReal ω x) * (t * t) + (2 * ‖ω (star y * x)‖ ) * t + (positiveReal ω y) := by + have hexp2 : (ω (star s * s)).re = + (positiveReal ω x) * (t * t) + (2 * ‖ω (star y * x)‖ ) * t + (positiveReal ω y) := by have hquad := quadratic_expansion (ω := ω) (x := x) (y := y) (z := ((t : ℂ) * γ)) have h1 : (‖(t : ℂ) * γ‖^2 : ℂ) = (t^2 : ℂ) := by rw [Complex.norm_mul, hγ_norm, mul_one, Complex.norm_real, pow_two, pow_two] norm_cast exact abs_mul_abs_self t - have h2 : conj ((t : ℂ) * γ) * ω (star x * y) + ((t : ℂ) * γ) * ω (star y * x) = 2 * t * ‖ω (star y * x)‖ := by + have h2 : conj ((t : ℂ) * γ) * ω (star x * y) + ((t : ℂ) * γ) * ω (star y * x) = + 2 * t * ‖ω (star y * x)‖ := by have : ((t : ℂ) * γ) * ω (star y * x) = t * (γ * ω (star y * x)) := by ring rw [conj_linear_combination_real, this, hγ_phase] norm_cast ring_nf - have hequiv : ω (star s * s) = (t^2 : ℂ) * ω (star x * x) + 2 * t * ‖ω (star y * x)‖ + ω (star y * y) := by + have hequiv : + ω (star s * s) = (t^2 : ℂ) * ω (star x * x) + 2 * t * ‖ω (star y * x)‖ + ω (star y * y) := by unfold s rw [hquad, h1, ← h2] ring_nf @@ -211,7 +214,8 @@ lemma kernel_degenerate_left (a : A) (hx : ω (star x * x) = 0) : ω (star a * x exact norm_eq_zero.mp (sq_eq_zero_iff.mp (le_antisymm (by exact_mod_cast this) (sq_nonneg _))) /-- If `ω(star x * x) = 0` and `ω(star y * y) = 0`, then `ω(star (x + y) * (x + y)) = 0`. -/ -lemma kernel_closed_under_add (hx : ω (star x * x) = 0) (hy : ω (star y * y) = 0) : ω (star (x + y) * (x + y)) = 0 := by +lemma kernel_closed_under_add (hx : ω (star x * x) = 0) (hy : ω (star y * y) = 0) : + ω (star (x + y) * (x + y)) = 0 := by calc ω (star (x + y) * (x + y)) = ω (star x * x + star x * y + star y * x + star y * y) := by rw [star_add, add_mul, mul_add, mul_add] @@ -219,7 +223,8 @@ lemma kernel_closed_under_add (hx : ω (star x * x) = 0) (hy : ω (star y * y) = _ = ω (star x * x) + ω (star x * y) + ω (star y * x) + ω (star y * y) := by rw [map_add, map_add, map_add] _ = 0 := by - rw [hx, hy, kernel_degenerate_left (ω := ω) (x := y) (a := x) hy, kernel_degenerate_left (ω := ω) (x := x) (a := y) hx] + rw [hx, hy, kernel_degenerate_left (ω := ω) (x := y) (a := x) hy, + kernel_degenerate_left (ω := ω) (x := x) (a := y) hx] ring /-- If `ω(star x * x) = 0`, then `ω(star (c • x) * (c • x)) = 0` for any scalar `c`. -/ diff --git a/QuantumSystem/Algebra/LocalNet/Net.lean b/QuantumSystem/Algebra/LocalNet/Net.lean index 29f6b70..92fd016 100644 --- a/QuantumSystem/Algebra/LocalNet/Net.lean +++ b/QuantumSystem/Algebra/LocalNet/Net.lean @@ -125,8 +125,8 @@ theorem Orthogonal.mono_right {O₁ O₂ O₃ : K} (h₀ : O₃ ≤ O₂) (h : O (h.symm.mono_left h₀).symm /-- Causal orthogonality is hereditary under shrinking both regions. -/ -theorem Orthogonal.mono {O₁' O₁ O₂' O₂ : K} (h₁ : O₁' ≤ O₁) (h₂ : O₂' ≤ O₂) (h : O₁ ⟂ O₂) : - O₁' ⟂ O₂' := +theorem Orthogonal.mono {O₁' O₁ O₂' O₂ : K} (h₁ : O₁' ≤ O₁) (h₂ : O₂' ≤ O₂) + (h : O₁ ⟂ O₂) : O₁' ⟂ O₂' := (h.mono_left h₁).mono_right h₂ /-! ### The derived relation `⊥̂` diff --git a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean index 6d5f1cf..8164c14 100644 --- a/QuantumSystem/Algebra/LocalNet/SplitProperty.lean +++ b/QuantumSystem/Algebra/LocalNet/SplitProperty.lean @@ -128,8 +128,8 @@ class ProperContainment (K : Type*) [Preorder K] [CausalOrthogonality K] where /-- Proper containment implies containment. -/ le_of_properlyContained : ∀ ⦃O₁ O₂ : K⦄, ProperlyContained O₁ O₂ → O₁ ≤ O₂ /-- Proper containment survives shrinking the inner region and enlarging the outer one. -/ - properlyContained_mono : ∀ ⦃O₀ O₁ O₂ O₃ : K⦄, O₀ ≤ O₁ → ProperlyContained O₁ O₂ → O₂ ≤ O₃ → - ProperlyContained O₀ O₃ + properlyContained_mono : ∀ ⦃O₀ O₁ O₂ O₃ : K⦄, O₀ ≤ O₁ → ProperlyContained O₁ O₂ → + O₂ ≤ O₃ → ProperlyContained O₀ O₃ /-- **Causal collar**: a properly containing region contains a region causally orthogonal to the inner one and not contained in it. The last clause is the nondegeneracy that makes the collar a genuine buffer rather than a region orthogonal to everything (such as the empty @@ -157,8 +157,8 @@ theorem ProperlyContained.le {O₁ O₂ : K} (h : O₁ ⋐ O₂) : O₁ ≤ O₂ /-- Proper containment survives shrinking the inner region and enlarging the outer one (dot-notation form). -/ -theorem ProperlyContained.mono {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) (h₃ : O₂ ≤ O₃) : - O₀ ⋐ O₃ := +theorem ProperlyContained.mono {O₀ O₁ O₂ O₃ : K} (h₀ : O₀ ≤ O₁) (h : O₁ ⋐ O₂) + (h₃ : O₂ ≤ O₃) : O₀ ⋐ O₃ := properlyContained_mono h₀ h h₃ /-- The causal collar of a proper containment (dot-notation form). -/ diff --git a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean index 9c27382..9f13e75 100644 --- a/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean +++ b/QuantumSystem/Algebra/VonNeumannAlgebra/StructureTheorem.lean @@ -65,8 +65,9 @@ carries the matrix unit `e_{pq}` to the amplified rank-one operator `|δ_p⟩⟨ * [Yngvason] J. Yngvason, *Localization and Entanglement in Relativistic Quantum Physics*, in *The Message of Quantum Science*, Lecture Notes in Physics 899, Springer 2015, pp. 325–348; - arXiv:1401.2652. Its §5.1 ("Causal Independence and Split Property") displays the two equations - cited below as `(38)`, `𝒜₁ ⊂ 𝒩 ⊂ 𝒜₂′`, and `(39)`, `𝒜₁ ⊂ ℬ(ℋ₁) ⊗ 𝟏` and `𝒜₂ ⊂ 𝟏 ⊗ ℬ(ℋ₂)`. + arXiv:1401.2652. Its §5.1 ("Causal Independence and Split Property") displays the two + equations cited below as `(38)`, `𝒜₁ ⊂ 𝒩 ⊂ 𝒜₂′`, and `(39)`, `𝒜₁ ⊂ ℬ(ℋ₁) ⊗ 𝟏` and + `𝒜₂ ⊂ 𝟏 ⊗ ℬ(ℋ₂)`. * [DL84] S. Doplicher, R. Longo, *Standard and split inclusions of von Neumann algebras*, Invent. Math. 75 (1984) 493–536. * [dB74] D. Buchholz, *Product states for local algebras*, Comm. Math. Phys. 36 (1974) 287–304. diff --git a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean index 0e2861b..796e176 100644 --- a/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean +++ b/QuantumSystem/Analysis/Entropy/RelativeEntropy.lean @@ -1565,7 +1565,8 @@ private lemma trace_rpow_mul_jointly_concave (hs0 : 0 ≤ s) (hs1 : s ≤ 1) : p * (Tr (ρ₁ ^ s * σ₁ ^ (1 - s))).re + (1 - p) * (Tr (ρ₂ ^ s * σ₂ ^ (1 - s))).re ≤ - (Tr ((p • ρ₁.toMatrix + (1 - p) • ρ₂.toMatrix) ^ s * (p • σ₁.toMatrix + (1 - p) • σ₂.toMatrix) ^ (1 - s))).re := by + (Tr ((p • ρ₁.toMatrix + (1 - p) • ρ₂.toMatrix) ^ s * + (p • σ₁.toMatrix + (1 - p) • σ₂.toMatrix) ^ (1 - s))).re := by have hpsd₁ := ρ₁.posSemidef have hpsd₂ := ρ₂.posSemidef have hpsdσ₁ := σ₁.posSemidef @@ -1623,7 +1624,8 @@ theorem relativeEntropy_jointly_convex push_cast; ring_nf] rw [EReal.coe_le_coe_iff] -- Step 4: Derivative argument - -- Define h(s) = Re[Tr (ρ_mix^s σ_mix^{1-s})] - p Re[Tr (ρ₁^s σ₁^{1-s})] - (1-p) Re[Tr (ρ₂^s σ₂^{1-s})] + -- Define h(s) = Re[Tr (ρ_mix^s σ_mix^{1-s})] - p Re[Tr (ρ₁^s σ₁^{1-s})] + -- - (1-p) Re[Tr (ρ₂^s σ₂^{1-s})] let g : ℝ → ℝ := fun s => (ρ_mix.toMatrix ^ s * σ_mix.toMatrix ^ (1 - s)).trace.re - (p * (ρ₁.toMatrix ^ s * σ₁.toMatrix ^ (1 - s)).trace.re + diff --git a/QuantumSystem/Analysis/Matrix/LiebConcavity.lean b/QuantumSystem/Analysis/Matrix/LiebConcavity.lean index 773834c..d82ce71 100644 --- a/QuantumSystem/Analysis/Matrix/LiebConcavity.lean +++ b/QuantumSystem/Analysis/Matrix/LiebConcavity.lean @@ -156,7 +156,8 @@ private lemma lieb_concavity_effros {m : Type*} [Fintype m] [DecidableEq m] w₂ * (liebJointFunction K p A₂ hA₂.posSemidef B₂ hB₂.posSemidef).re ≤ (liebJointFunction K p (w₁ • A₁ + w₂ • A₂) ((hA₁.posSemidef.real_smul hw₁).add (hA₂.posSemidef.real_smul hw₂)) - (w₁ • B₁ + w₂ • B₂) ((hB₁.posSemidef.real_smul hw₁).add (hB₂.posSemidef.real_smul hw₂))).re := by + (w₁ • B₁ + w₂ • B₂) + ((hB₁.posSemidef.real_smul hw₁).add (hB₂.posSemidef.real_smul hw₂))).re := by classical /- Proof by Effros's Matrix Perspective Approach -/ -- 1. Setup the function f(x) = -x^p, which is Matrix Convex. @@ -201,12 +202,16 @@ private lemma lieb_concavity_effros {m : Type*} [Fintype m] [DecidableEq m] simp only [dotProduct_sub, dotProduct_add] at h_vec_nonneg -- Connect to Lieb function -- Use the spectral identity: ⟨v, matrixPerspective(f, L_A, R_B) v⟩ = -liebJointFunction(K, p, A, B) - have h_ident1 : (star v ⬝ᵥ (term1 *ᵥ v)).re = -(liebJointFunction K p A₁ hA₁.posSemidef B₁ hB₁.posSemidef).re := by + have h_ident1 : (star v ⬝ᵥ (term1 *ᵥ v)).re = + -(liebJointFunction K p A₁ hA₁.posSemidef B₁ hB₁.posSemidef).re := by simpa [term1, f] using - matrixPerspective_inner_eq_neg_liebJointFunction K p (le_of_lt hp0) (le_of_lt hp1) A₁ B₁ hA₁ hB₁ hL₁_psd hR₁_pd - have h_ident2 : (star v ⬝ᵥ (term2 *ᵥ v)).re = -(liebJointFunction K p A₂ hA₂.posSemidef B₂ hB₂.posSemidef).re := by + matrixPerspective_inner_eq_neg_liebJointFunction K p (le_of_lt hp0) (le_of_lt hp1) A₁ B₁ + hA₁ hB₁ hL₁_psd hR₁_pd + have h_ident2 : (star v ⬝ᵥ (term2 *ᵥ v)).re = + -(liebJointFunction K p A₂ hA₂.posSemidef B₂ hB₂.posSemidef).re := by simpa [term2, f] using - matrixPerspective_inner_eq_neg_liebJointFunction K p (le_of_lt hp0) (le_of_lt hp1) A₂ B₂ hA₂ hB₂ hL₂_psd hR₂_pd + matrixPerspective_inner_eq_neg_liebJointFunction K p (le_of_lt hp0) (le_of_lt hp1) A₂ B₂ + hA₂ hB₂ hL₂_psd hR₂_pd have hA_comb : (w₁ • A₁ + w₂ • A₂).PosDef := PosDef.convex_comb_nonneg hA₁ hA₂ hw₁ hw₂ hw have hB_comb : (w₁ • B₁ + w₂ • B₂).PosDef := PosDef.convex_comb_nonneg hB₁ hB₂ hw₁ hw₂ hw -- The combined identity follows from matrixPerspective_inner_eq_neg_liebJointFunction @@ -252,7 +257,8 @@ private lemma lieb_concavity_effros {m : Type*} [Fintype m] [DecidableEq m] -- After substitution, the goal matches h_apply. -- The matrices are definitionally equal after applying hLlin and hRlin. -- term_comb = matrixPerspective f L R _ _ - -- = matrixPerspective f (leftMulMatrix (w₁•A₁+w₂•A₂)) (rightMulMatrix (w₁•B₁+w₂•B₂)) _ _ + -- = matrixPerspective f (leftMulMatrix (w₁•A₁+w₂•A₂)) + -- (rightMulMatrix (w₁•B₁+w₂•B₂)) _ _ -- The proof terms may differ but the matrices are equal by proof irrelevance. -- Since both sides compute the same quadratic form value, they are equal. -- We establish this by showing the matrixPerspective matrices are equal. @@ -302,7 +308,8 @@ private lemma lieb_joint_concavity {m : Type*} [Fintype m] [DecidableEq m] w₂ * (liebJointFunction K p A₂ hA₂.posSemidef B₂ hB₂.posSemidef).re ≤ (liebJointFunction K p (w₁ • A₁ + w₂ • A₂) ((hA₁.posSemidef.real_smul hw₁).add (hA₂.posSemidef.real_smul hw₂)) - (w₁ • B₁ + w₂ • B₂) ((hB₁.posSemidef.real_smul hw₁).add (hB₂.posSemidef.real_smul hw₂))).re := by + (w₁ • B₁ + w₂ • B₂) + ((hB₁.posSemidef.real_smul hw₁).add (hB₂.posSemidef.real_smul hw₂))).re := by -- Handle boundary cases p = 0 and p = 1 separately rcases eq_or_lt_of_le hp0 with rfl | hp0' · -- p = 0: Tr(K†BK) is linear in B, so equality holds diff --git a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean index ad61311..f4edae8 100644 --- a/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean +++ b/QuantumSystem/ForMathlib/Analysis/InnerProductSpace/DiagonalAmplification.lean @@ -225,7 +225,8 @@ lemma diagonal_star {n : ℕ} (T : H →L[ℂ] H) : (ContinuousLinearMap.adjoint_inner_left (A := T) (x := y.ofLp i) (y := x.ofLp i)) /-- `diagonal` as a `StarAlgHom` (so we can map `StarSubalgebra`s). -/ -noncomputable def diagonalStarAlgHom (n : ℕ) : (H →L[ℂ] H) →⋆ₐ[ℂ] (Hn (H := H) n →L[ℂ] Hn (H := H) n) where +noncomputable def diagonalStarAlgHom (n : ℕ) : + (H →L[ℂ] H) →⋆ₐ[ℂ] (Hn (H := H) n →L[ℂ] Hn (H := H) n) where toFun := fun T => diagonal (H := H) (n := n) T map_one' := by ext x i diff --git a/QuantumSystem/Notation.lean b/QuantumSystem/Notation.lean index f56a49e..7ceaa7c 100644 --- a/QuantumSystem/Notation.lean +++ b/QuantumSystem/Notation.lean @@ -10,13 +10,22 @@ public import Mathlib.LinearAlgebra.Matrix.Trace Notations and abbreviations for quantum information theory. -| Symbol | Expansion | How to activate | Defined in | -|---|---|---|---| -| `Tr A` | `Matrix.trace A` | always available (prefix notation) | this file | -| `log ρ` | `DensityMatrix.log ρ` | `open scoped Matrix.QuantumInfo` | `State.lean` | -| `S(ρ)` | `Matrix.vonNeumannEntropy ρ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/VonNeumannEntropy.lean` | -| `D(ρ ∥ σ)` | `Matrix.relativeEntropy ρ σ` | `open scoped Matrix.QuantumInfo` | `Analysis/Entropy/RelativeEntropy.lean` | -| `⟪X, Y⟫_HS` | `Matrix.hsInnerProduct X Y` | `open scoped Matrix.QuantumInfo` | `Analysis/Matrix/LiebConcavity.lean` | +<table> +<tr><th>Symbol</th><th>Expansion</th><th>How to activate</th><th>Defined in</th></tr> +<tr><td><code>Tr A</code></td><td><code>Matrix.trace A</code></td> + <td>always available (prefix notation)</td><td>this file</td></tr> +<tr><td><code>log ρ</code></td><td><code>DensityMatrix.log ρ</code></td> + <td><code>open scoped Matrix.QuantumInfo</code></td><td><code>State.lean</code></td></tr> +<tr><td><code>S(ρ)</code></td><td><code>Matrix.vonNeumannEntropy ρ</code></td> + <td><code>open scoped Matrix.QuantumInfo</code></td> + <td><code>Analysis/Entropy/VonNeumannEntropy.lean</code></td></tr> +<tr><td><code>D(ρ ∥ σ)</code></td><td><code>Matrix.relativeEntropy ρ σ</code></td> + <td><code>open scoped Matrix.QuantumInfo</code></td> + <td><code>Analysis/Entropy/RelativeEntropy.lean</code></td></tr> +<tr><td><code>⟪X, Y⟫_HS</code></td><td><code>Matrix.hsInnerProduct X Y</code></td> + <td><code>open scoped Matrix.QuantumInfo</code></td> + <td><code>Analysis/Matrix/LiebConcavity.lean</code></td></tr> +</table> ## `Tr` syntax From 7f81394768ff11360ab44754e75295dd341540e2 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Mon, 17 Aug 2026 03:06:10 +0000 Subject: [PATCH 110/113] feat(math-extract): add a render check; drop the broken macro preamble MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured against the plugin VS Code's own Markdown preview uses (@vscode/markdown-it-katex): no macro definition form survives from one math span to the next inside a note — not \newcommand, not \gdef, not \global\def. Each span is rendered with fresh options, so a note cannot define macros for itself. The `$$\newcommand{...}$$` preamble this skill previously prescribed does not work, and the failure is silent until a reader opens the note and sees a wall of `Undefined control sequence`. Add scripts/check_render.py + scripts/render_check.js: the latter renders a note through the real pipeline and reports every ParseError with a line number, plus "portability hazards" — spans that happen to render here but rely on behaviour engines disagree about (a subscripted thin space, an unbraced multi-token argument like \widetilde\mathcal U). The former is a lighter allowlist-based fallback for when node/the pipeline isn't available, generated by probing a real KaTeX build one command at a time and keeping only what actually rendered. Rewrite note-format.md's macro section and SKILL.md's step 6 accordingly: plain KaTeX in a note's own voice, source macros confined to fenced code or backticks, no preamble. Wired in as a fifth check alongside the firewall/quote/locator/discipline checks. Also record this run's source-retrieval attempts and locator adjudications in sources.md, per the skill's append-only ledger. --- .claude/skills/math-extract/SKILL.md | 39 +- .../references/katex-commands.txt | 968 ++++++++++++++++++ .../math-extract/references/note-format.md | 138 ++- .../math-extract/scripts/check_render.py | 209 ++++ .../math-extract/scripts/render_check.js | 152 +++ 5 files changed, 1459 insertions(+), 47 deletions(-) create mode 100644 .claude/skills/math-extract/references/katex-commands.txt create mode 100755 .claude/skills/math-extract/scripts/check_render.py create mode 100644 .claude/skills/math-extract/scripts/render_check.js diff --git a/.claude/skills/math-extract/SKILL.md b/.claude/skills/math-extract/SKILL.md index 58476bf..5f5b832 100644 --- a/.claude/skills/math-extract/SKILL.md +++ b/.claude/skills/math-extract/SKILL.md @@ -230,10 +230,11 @@ non-empty, and the append-only tables have lost no rows. ### 6. Verify, then report -Run all four checks against the note. **They are the acceptance criteria, not a +Run all five checks against the note. **They are the acceptance criteria, not a formality** — this is the one step that costs your own tool calls rather than an agent's, and it is worth it, because a fabricated quote or an invented theorem -number is the worst thing this skill can produce. +number is the worst thing this skill can produce, and a note that renders as a +wall of `ParseError` is the worst thing a reader can be handed. The commands below are the detection half; the judgement is yours. Each was measured against a note written to violate all four, and each flagged the bad @@ -293,6 +294,39 @@ so read every hit rather than counting them. step consumes but the list omits is the exact omission the field exists to catch; a listed edge no step consumes is an error in one of the two. +5. **Render check.** + + ```bash + uv run .claude/skills/math-extract/scripts/check_render.py docs/math/<slug>.md + ``` + + Every math span must parse **on its own**, because that is how a markdown + previewer renders it. The script reports two classes of defect and exits + non-zero on either: + + - a command KaTeX does not define — almost always a source's private macro + (`\Tr`, `\A`, `\U`) that leaked out of a quote and into the note's own + prose, or an in-note macro definition, which never carries; + - with the pipeline installed, a **real render of the document** through + markdown-it and the plugin VS Code's preview uses, which catches what an + allowlist cannot: an unbraced argument (`\widetilde\mathcal U`), a + mis-paired delimiter, and *portability hazards* — spans that typeset here + but rely on behaviour engines disagree about, such as a subscripted thin + space (`\mathrm{Tr}\,_2`). + + Enable the real render once per checkout with + `(cd .claude/skills/math-extract && npm install --no-save markdown-it @vscode/markdown-it-katex)`; + `node_modules/` is gitignored. Without it the script still runs, says so, and + leaves brace and span-boundary errors unchecked — a partial check, not a pass. + + **Do not silence a finding with a macro preamble.** Measured through that + plugin, **no** definition form carries to the next math span — not + `\newcommand`, not `\gdef`, not `\global\def` — because each span is + rendered with fresh options. A note cannot define macros for itself. The two + fixes, in `references/note-format.md`, are: plain KaTeX in the note's own + voice, and code (a fenced block, or backticks for an inlined fragment) around + anything verbatim that carries source macros. + Then update `sources.md`: one row per source attempted this run, and a `Notes` entry for any locator you adjudicated. **This is the only step that writes to that file.** @@ -316,6 +350,7 @@ Report to the user in Japanese, in this shape: - Quote check: <n>/<n> matched; <n> downgraded; <n> deleted - Locator check: <n> tier-(c)/(d) rows, all carrying a statement instead of a number - Discipline: <n> model-dependent rows, all with witnesses; <n> rejected rows, all with typed discriminators +- Render: <n> math spans parsed independently, <n> ParseErrors <| real KaTeX parse not available — brace errors unchecked> ## Corpus | Key | How obtained | Cost | diff --git a/.claude/skills/math-extract/references/katex-commands.txt b/.claude/skills/math-extract/references/katex-commands.txt new file mode 100644 index 0000000..4da5d2e --- /dev/null +++ b/.claude/skills/math-extract/references/katex-commands.txt @@ -0,0 +1,968 @@ +\! +\# +\$ +\% +\& +\, +\. +\: +\; +\= +\> +\AA +\Alpha +\And +\Bbb +\Bbbk +\Beta +\Big +\Bigg +\Biggl +\Biggm +\Biggr +\Bigl +\Bigm +\Bigr +\Box +\Bra +\Braket +\Bumpeq +\Cap +\Chi +\Colonapprox +\Coloneq +\Coloneqq +\Colonsim +\Complex +\Cup +\DOTSB +\DOTSI +\DOTSX +\Dagger +\Darr +\Delta +\Diamond +\Doteq +\Downarrow +\Epsilon +\Eqcolon +\Eqqcolon +\Eta +\Finv +\Game +\Gamma +\H +\Harr +\Huge +\Im +\Iota +\Join +\KaTeX +\Kappa +\Ket +\LARGE +\LaTeX +\Lambda +\Large +\Larr +\Leftarrow +\Leftrightarrow +\Lleftarrow +\Longleftarrow +\Longleftrightarrow +\Longrightarrow +\Lrarr +\Lsh +\Mu +\N +\Nu +\Omega +\Omicron +\Overrightarrow +\P +\Phi +\Pi +\Pr +\Psi +\R +\Rarr +\Re +\Reals +\Rho +\Rightarrow +\Rrightarrow +\Rsh +\S +\Set +\Sigma +\Subset +\Supset +\Tau +\TeX +\TextOrMath +\Theta +\Uarr +\Uparrow +\Updownarrow +\Upsilon +\Vdash +\Vert +\Vvdash +\Xi +\Z +\Zeta +\^ +\_ +\aa +\acute +\alef +\alefsym +\aleph +\allowbreak +\alpha +\amalg +\angl +\angle +\angln +\approx +\approxcolon +\approxcoloncolon +\approxeq +\arccos +\arcctg +\arcsin +\arctan +\arctg +\arg +\argmax +\argmin +\ast +\asymp +\atop +\backepsilon +\backprime +\backsim +\backsimeq +\backslash +\bar +\barwedge +\bcancel +\because +\begin +\beta +\beth +\between +\bf +\big +\bigcap +\bigcirc +\bigcup +\bigg +\biggl +\biggm +\biggr +\bigl +\bigm +\bigodot +\bigoplus +\bigotimes +\bigr +\bigsqcup +\bigstar +\bigtriangledown +\bigtriangleup +\biguplus +\bigvee +\bigwedge +\binom +\blacklozenge +\blacksquare +\blacktriangle +\blacktriangledown +\blacktriangleleft +\blacktriangleright +\blue +\blueA +\blueB +\blueC +\blueD +\blueE +\bm +\bmod +\bold +\boldsymbol +\bot +\bowtie +\boxdot +\boxed +\boxminus +\boxplus +\boxtimes +\bra +\brace +\brack +\braket +\breve +\bull +\bullet +\bumpeq +\c +\cal +\cancel +\cap +\cdot +\cdotp +\cdots +\centerdot +\cfrac +\ch +\check +\checkmark +\chi +\choose +\circ +\circeq +\circlearrowleft +\circlearrowright +\circledR +\circledS +\circledast +\circledcirc +\circleddash +\clap +\clubs +\clubsuit +\cnums +\colon +\colonapprox +\coloncolon +\coloncolonapprox +\coloncolonequals +\coloncolonminus +\coloncolonsim +\coloneq +\coloneqq +\colonequals +\colonminus +\colonsim +\color +\colorbox +\complement +\cong +\coprod +\copyright +\cos +\cosec +\cosh +\cot +\cotg +\coth +\csc +\ctg +\cth +\cup +\curlyeqprec +\curlyeqsucc +\curlyvee +\curlywedge +\curvearrowleft +\curvearrowright +\dArr +\dag +\dagger +\daleth +\darr +\dashleftarrow +\dashrightarrow +\dashv +\dbinom +\dblcolon +\ddag +\ddagger +\ddddot +\dddot +\ddot +\ddots +\def +\deg +\degree +\delta +\det +\dfrac +\diagdown +\diagup +\diamond +\diamonds +\diamondsuit +\digamma +\dim +\displaystyle +\div +\divideontimes +\dot +\doteq +\doteqdot +\dotplus +\dots +\dotsb +\dotsc +\dotsi +\dotsm +\dotso +\dotsx +\doublebarwedge +\doublecap +\doublecup +\downarrow +\downdownarrows +\downharpoonleft +\downharpoonright +\edef +\ell +\emph +\empty +\emptyset +\end +\enskip +\enspace +\epsilon +\eqcirc +\eqcolon +\eqqcolon +\eqsim +\eqslantgtr +\eqslantless +\equalscolon +\equalscoloncolon +\equiv +\errmessage +\eta +\eth +\exist +\exists +\exp +\expandafter +\fallingdotseq +\fbox +\flat +\footnotesize +\forall +\frac +\frak +\frown +\futurelet +\gamma +\gcd +\gdef +\ge +\geq +\geqq +\geqslant +\gets +\gg +\ggg +\gggtr +\gimel +\global +\gnapprox +\gneq +\gneqq +\gnsim +\goldA +\goldB +\goldC +\goldD +\goldE +\grave +\gray +\grayA +\grayB +\grayC +\grayD +\grayE +\grayF +\grayG +\grayH +\grayI +\green +\greenA +\greenB +\greenC +\greenD +\greenE +\gt +\gtrapprox +\gtrdot +\gtreqless +\gtreqqless +\gtrless +\gtrsim +\gvertneqq +\hArr +\harr +\hat +\hbar +\hbox +\hearts +\heartsuit +\hom +\hookleftarrow +\hookrightarrow +\hphantom +\href +\hslash +\htmlClass +\htmlId +\htmlStyle +\huge +\iff +\iiint +\iint +\image +\imageof +\imath +\impliedby +\implies +\in +\includegraphics +\inf +\infin +\infty +\injlim +\int +\intercal +\intop +\iota +\isin +\it +\jmath +\kaBlue +\kaGreen +\kappa +\ker +\ket +\lArr +\lBrace +\lVert +\lambda +\land +\lang +\langle +\large +\larr +\lbrace +\lbrack +\lceil +\ldotp +\ldots +\le +\leadsto +\left +\leftarrow +\leftarrowtail +\leftharpoondown +\leftharpoonup +\leftleftarrows +\leftrightarrow +\leftrightarrows +\leftrightharpoons +\leftrightsquigarrow +\leftthreetimes +\leq +\leqq +\leqslant +\lessapprox +\lessdot +\lesseqgtr +\lesseqqgtr +\lessgtr +\lesssim +\let +\lfloor +\lg +\lgroup +\lhd +\lim +\liminf +\limsup +\ll +\llap +\llbracket +\llcorner +\lll +\llless +\lmoustache +\ln +\lnapprox +\lneq +\lneqq +\lnot +\lnsim +\log +\longleftarrow +\longleftrightarrow +\longmapsto +\longrightarrow +\looparrowleft +\looparrowright +\lor +\lozenge +\lparen +\lq +\lrArr +\lrarr +\lrcorner +\lt +\ltimes +\lvert +\lvertneqq +\maltese +\mapsto +\maroonA +\maroonB +\maroonC +\maroonD +\maroonE +\mathbb +\mathbf +\mathbin +\mathcal +\mathclap +\mathclose +\mathellipsis +\mathfrak +\mathinner +\mathit +\mathllap +\mathnormal +\mathop +\mathopen +\mathord +\mathpunct +\mathrel +\mathring +\mathrlap +\mathrm +\mathscr +\mathsf +\mathsfit +\mathsterling +\mathstrut +\mathtt +\max +\measuredangle +\medspace +\message +\mho +\mid +\middle +\min +\mintA +\mintB +\mintC +\minuscolon +\minuscoloncolon +\minuso +\mod +\models +\mp +\mu +\multimap +\nLeftarrow +\nLeftrightarrow +\nRightarrow +\nVDash +\nVdash +\nabla +\natnums +\natural +\ncong +\ne +\nearrow +\neg +\negmedspace +\negthickspace +\negthinspace +\neq +\newcommand +\newline +\nexists +\ngeq +\ngeqq +\ngeqslant +\ngtr +\ni +\nleftarrow +\nleftrightarrow +\nleq +\nleqq +\nleqslant +\nless +\nmid +\nobreak +\nobreakspace +\noexpand +\nonumber +\normalsize +\not +\notag +\notin +\notni +\nparallel +\nprec +\npreceq +\nrightarrow +\nshortmid +\nshortparallel +\nsim +\nsubseteq +\nsubseteqq +\nsucc +\nsucceq +\nsupseteq +\nsupseteqq +\ntriangleleft +\ntrianglelefteq +\ntriangleright +\ntrianglerighteq +\nu +\nvDash +\nvdash +\nwarrow +\odot +\oiiint +\oiint +\oint +\omega +\omicron +\ominus +\operatorname +\operatornamewithlimits +\oplus +\orange +\ordinarycolon +\origof +\oslash +\otimes +\over +\overbrace +\overbracket +\overgroup +\overleftarrow +\overleftharpoon +\overleftrightarrow +\overline +\overlinesegment +\overrightarrow +\overrightharpoon +\overset +\owns +\parallel +\partial +\perp +\phantom +\phase +\phi +\pi +\pink +\pitchfork +\plim +\plusmn +\pm +\pmb +\pmod +\pod +\pounds +\prec +\precapprox +\preccurlyeq +\preceq +\precnapprox +\precneqq +\precnsim +\precsim +\prime +\prod +\projlim +\propto +\providecommand +\psi +\purple +\purpleA +\purpleB +\purpleC +\purpleD +\purpleE +\qquad +\quad +\r +\rArr +\rBrace +\rVert +\rang +\rangle +\rarr +\ratio +\rbrace +\rbrack +\rceil +\real +\reals +\red +\redA +\redB +\redC +\redD +\redE +\relax +\renewcommand +\restriction +\rfloor +\rgroup +\rhd +\rho +\right +\rightarrow +\rightarrowtail +\rightharpoondown +\rightharpoonup +\rightleftarrows +\rightleftharpoons +\rightrightarrows +\rightsquigarrow +\rightthreetimes +\risingdotseq +\rlap +\rm +\rmoustache +\rparen +\rq +\rrbracket +\rtimes +\rvert +\scriptscriptstyle +\scriptsize +\scriptstyle +\sdot +\searrow +\sec +\sect +\set +\setminus +\sf +\sh +\sharp +\shortmid +\shortparallel +\show +\sigma +\sim +\simcolon +\simcoloncolon +\simeq +\sin +\sinh +\sixptsize +\small +\smallfrown +\smallint +\smallsetminus +\smallsmile +\smash +\smile +\sout +\space +\spades +\spadesuit +\sphericalangle +\sqcap +\sqcup +\sqrt +\sqsubset +\sqsubseteq +\sqsupset +\sqsupseteq +\square +\stackrel +\star +\sub +\sube +\subset +\subseteq +\subseteqq +\subsetneq +\subsetneqq +\substack +\succ +\succapprox +\succcurlyeq +\succeq +\succnapprox +\succneqq +\succnsim +\succsim +\sum +\sup +\supe +\supset +\supseteq +\supseteqq +\supsetneq +\supsetneqq +\surd +\swarrow +\tan +\tanh +\tau +\tbinom +\tealA +\tealB +\tealC +\tealD +\tealE +\text +\textbf +\textcircled +\textcolor +\textcopyright +\textit +\textmd +\textnormal +\textregistered +\textrm +\textsf +\textstyle +\texttt +\textup +\tfrac +\tg +\th +\therefore +\theta +\thetasym +\thickapprox +\thicksim +\thickspace +\thinspace +\tilde +\times +\tiny +\to +\top +\triangle +\triangledown +\triangleleft +\trianglelefteq +\triangleq +\triangleright +\trianglerighteq +\tt +\twoheadleftarrow +\twoheadrightarrow +\u +\uArr +\uarr +\ulcorner +\underbar +\underbrace +\underbracket +\undergroup +\underleftarrow +\underleftrightarrow +\underline +\underlinesegment +\underrightarrow +\underset +\unlhd +\unrhd +\uparrow +\updownarrow +\upharpoonleft +\upharpoonright +\uplus +\upsilon +\upuparrows +\urcorner +\url +\utilde +\v +\vDash +\varDelta +\varGamma +\varLambda +\varOmega +\varPhi +\varPi +\varPsi +\varSigma +\varTheta +\varUpsilon +\varXi +\varepsilon +\varinjlim +\varkappa +\varliminf +\varlimsup +\varnothing +\varphi +\varpi +\varprojlim +\varpropto +\varrho +\varsigma +\varsubsetneq +\varsubsetneqq +\varsupsetneq +\varsupsetneqq +\vartheta +\vartriangle +\vartriangleleft +\vartriangleright +\varvdots +\vcentcolon +\vcenter +\vdash +\vdots +\vec +\vee +\veebar +\vert +\vphantom +\wedge +\weierp +\widecheck +\widehat +\widetilde +\wp +\wr +\xLeftarrow +\xLeftrightarrow +\xRightarrow +\xcancel +\xdef +\xhookleftarrow +\xhookrightarrow +\xi +\xleftarrow +\xleftequilibrium +\xleftharpoondown +\xleftharpoonup +\xleftrightarrow +\xleftrightharpoons +\xlongequal +\xmapsto +\xrightarrow +\xrightequilibrium +\xrightharpoondown +\xrightharpoonup +\xrightleftarrows +\xrightleftharpoons +\xtofrom +\xtwoheadleftarrow +\xtwoheadrightarrow +\yen +\zeta +\{ +\| +\} +\~ diff --git a/.claude/skills/math-extract/references/note-format.md b/.claude/skills/math-extract/references/note-format.md index 0f8636e..116eb60 100644 --- a/.claude/skills/math-extract/references/note-format.md +++ b/.claude/skills/math-extract/references/note-format.md @@ -37,15 +37,12 @@ revisions: --- <!-- -Macros the quotes below need, copied from each source's own preamble: - \lok DL84, references/<slug-of-source>/raw/<file>.tex:144 -Omit this block and the comment when no quote carries a source macro. +No macro preamble: quotes carrying a source's private macros go in fenced code +blocks, and everything the note says in its own voice is plain KaTeX. See +"Source macros" below before reintroducing one — \newcommand does not survive +from one math span to the next. --> -$$ -\newcommand{\lok}[1]{{\mathcal #1}} -$$ - # <Object, as a mathematician names it> ## What this object is for @@ -65,7 +62,9 @@ $$ **(D1) [DL84] §1** — tier (a) > <verbatim quote, in the source's language, unmodified, formulas in the -> source's own notation> +> source's own notation. If it carries the source's own macros, fence it: +> a ``` block inside the blockquote keeps the bytes exact and keeps every +> renderer from trying to typeset them.> [tr.] <optional translation, outside the quote, tier (b)> @@ -181,41 +180,88 @@ $$ ## Section rules -### Macro preamble +### Source macros, and why there is no macro preamble Verbatim quotes carry the source's own LaTeX, and sources define their own -macros — `\lok`, `\A`, `\bC`. Any renderer that parses `$…$` (KaTeX in VS Code's -Markdown preview, MathJax elsewhere) raises a parse error on every one of them, -and **the fix is never to edit the quote**: those bytes are the evidence the -quote check verifies. Transcribe the definitions instead, into a `$$` block -between the frontmatter and the H1 — it must precede the first quote that uses -them — with an HTML comment naming the file and line each was copied from. - -- **Copy the definition; do not paraphrase it.** `\newcommand{\lok}[1]{{\mathcal - #1}}` lifted from the paper's preamble can be audited against that preamble. - An equivalent written from scratch cannot, and a wrong transcription - mis-renders a quote that the quote check will still pass — it checks the - source bytes, not what they display as. -- **Only the macros the note actually uses.** -- **`\renewcommand` where the renderer already defines the name.** `\H` is the - Hungarian-umlaut accent in KaTeX's own macro table, so `\newcommand{\H}` is an - error; sources redefining it hit the same wall and write `\renewcommand`, so - copying them is both correct and faithful. -- **The definitions are per-note, and that is the point.** Renderers reset the - macro table per document, so two notes may transcribe one name differently — - which is what the sources do. Defining the macros once in an editor or - workspace setting instead would put every note into a single namespace, and - the first collision would render one source's quote in another source's - notation **without raising an error**. A silently mis-rendered verbatim quote - is worse than a visible parse error, which is why this block belongs in the - note and not in a configuration file. -- A renderer that does not share macro state across a document simply ignores - the block, and the quotes show as source LaTeX — which is what they are. - Nothing downstream depends on it, and no editor configuration is required. - -The block is presentation, not mathematics: it carries no claim, so it needs no -tier and no locator beyond the file:line provenance in the comment. - +macros — `\lok`, `\A`, `\bC`, `\Tr`. Any renderer that typesets `$…$` (KaTeX in +VS Code's Markdown preview, MathJax elsewhere) raises a parse error on every one +of them, and **the fix is never to edit the quote**: those bytes are the evidence +the quote check verifies. + +**The fix is also not a macro preamble — in any definition form.** An earlier +version of this file prescribed one. It does not work, and the failure is silent +until a reader opens the note: + +> Measured through `@vscode/markdown-it-katex`, the plugin VS Code's own Markdown +> preview uses: a `$$` block defining a macro with `\newcommand`, with `\gdef`, +> or with `\global\def` leaves that macro **undefined in every later math +> span**. The plugin renders each span with fresh options, so nothing is carried. +> Bare KaTeX is only slightly better — there `\gdef` survives when the caller +> passes a shared `macros` object, and `\newcommand`, being a local definition, +> never does — but no markdown previewer passes one. +> +> The practical consequence: **a note cannot define macros for itself.** Every +> occurrence throws `Undefined control sequence`. + +So there are exactly two ways to keep a source's macros out of a reader's face: + +1. **In the note's own voice, write plain KaTeX.** `\mathcal{A}`, `\mathrm{Tr}`, + `\operatorname{supp}`, `\varphi`. A source's private macro has no business in + a sentence the note is asserting — the note is not that source, and every such + import is a rendering failure waiting for a reader. +2. **Put anything verbatim that carries source macros into code.** A fenced + block inside the blockquote for a displayed quote, backticks for a fragment + inlined into a table cell. The bytes stay exactly as fetched, the quote check + greps them unchanged, and no renderer tries to typeset them. A quote that will + not render is still a quote, and showing it as source LaTeX is showing it as + what it is. + +When a source's macros are *unrecoverable* — a private `\documentclass` or +`\usepackage` absent from the arXiv package, as with KW20's `Book_KW` — that is +a fact about the source and belongs in `sources.md`, not a rendering problem to +solve in the note. + +Beyond macro names, the other way a note breaks a renderer is an argument that +looks braced and is not: `\widetilde\mathcal U` and `\Delta_\mathcal U` are both +parse errors, because `\widetilde` and `_` take a single token and `\mathcal` +then has no argument. **Brace it**: `\widetilde{\mathcal U}`, +`\Delta_{\mathcal U}`. No allowlist can catch this — only a parser can, which is +why the render check runs one. + +#### Regenerating the KaTeX allowlist + +`references/katex-commands.txt` is what `scripts/check_render.py` calls a known +command. It was produced by harvesting every `\name` literal from a KaTeX build +and then **rendering each one to see whether it actually works**, keeping only +what did — so it contains no guesses, and its misses are conservative rather +than permissive. Commands that cannot be probed in isolation (`\begin`, +`\gdef`, `\left`, the `\bigl` family) were verified separately in a syntactic +context that exercises them. + +To regenerate against a newer KaTeX, from the skill directory: + +```bash +npm install --no-save katex +node -e ' + const fs=require("fs"), katex=require("katex"); + const src=fs.readFileSync(require.resolve("katex/dist/katex.mjs"),"utf8"); + const cand=new Set(); + for (const m of src.matchAll(/["\x27`]\\\\([A-Za-z]+|[^A-Za-z\s"\x27`\\\\])["\x27`]/g)) cand.add("\\"+m[1]); + const ok=[]; + for (const c of [...cand].sort()) + for (const f of [c, c+"{x}", c+"{x}{y}", c+" x"]) + { try { katex.renderToString(f,{throwOnError:true,strict:false}); ok.push(c); break; } catch(e) {} } + fs.writeFileSync("references/katex-commands.txt", ok.join("\n")+"\n"); + console.log(ok.length); +' +``` + +then re-add by hand the contextual commands the standalone probe rejects, each +verified with a form that exercises it, and re-run the render check on every +note under `docs/math/` before committing the new list. + +None of this is mathematics: it is presentation, carries no claim, and needs no +tier and no locator. The check that enforces it is step 6.5 of `SKILL.md`. ### Frontmatter - `worst-tier` is the **minimum tier over load-bearing rows** — the rows the @@ -252,7 +298,7 @@ mean, and why the generality is the one under discussion. Not a survey. writes it at merge from the (D#) blocks below it, choosing as columns the axes along which the corpus actually splits (quantification level, what the second object is, extra data such as a distinguished vector — whatever the - variants genuinely differ on). Like the macro preamble it carries no tier and + variants genuinely differ on). It is presentation, so it carries no tier and no locator, and when grid and (D#) block disagree, the grid is wrong. The verbatim blocks and `differs from:` lines are unchanged by its presence. **Why:** filling one column per axis is what makes a variant axis visible at @@ -452,9 +498,11 @@ which is not the claim the row makes. `source.flat.txt` rather than `source.txt` because a quotation crossing a line break matches only there; see `ingestion.md`. -A quote that will not *render* is still a quote. Fix it with the macro preamble -above, never by touching the bytes: normalising a formula so a previewer stops -complaining destroys the only thing that makes the row checkable. +A quote that will not *render* is still a quote. Put it in a fenced code block, +as `Source macros` above requires, never touch the bytes: normalising a formula +so a previewer stops complaining destroys the only thing that makes the row +checkable — and the quote check greps a fenced block exactly as it greps a +blockquote. **Why:** it makes tier (a) mechanically decidable instead of self-reported, at a cost of seconds. Converted PDFs are model output, not text, so a quote taken diff --git a/.claude/skills/math-extract/scripts/check_render.py b/.claude/skills/math-extract/scripts/check_render.py new file mode 100755 index 0000000..8f5a279 --- /dev/null +++ b/.claude/skills/math-extract/scripts/check_render.py @@ -0,0 +1,209 @@ +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.11" +# /// +"""Render check for an extraction note. + +Every math span in `docs/math/<slug>.md` must render **on its own**, and that is +the part that bites: **a note cannot define macros for itself.** Measured through +`@vscode/markdown-it-katex`, the plugin VS Code's own Markdown preview uses, +`\\newcommand`, `\\gdef` and `\\global\\def` all fail to reach the next math +span — the plugin renders each span with fresh options, so nothing is carried. +(Bare KaTeX behaves slightly better: `\\gdef` survives when the caller passes a +shared `macros` object. No markdown previewer does.) + +So a note whose prose says `$\\A_\\U$` throws `Undefined control sequence` on +every occurrence, however carefully the preamble was written, and the reader sees +a wall of ParseErrors instead of the mathematics. This script is what stops that +reaching the tracked note. + + uv run .claude/skills/math-extract/scripts/check_render.py docs/math/<slug>.md + +Exit 0 clean, 1 on findings, 2 on a usage error. + +What counts as a math span: `$...$` inline and `$$`-delimited blocks, **outside +fenced code**. Fenced code is deliberately exempt — it is the sanctioned place +for a verbatim quote that carries its source's private macros, because the bytes +survive untouched and no renderer tries to typeset them. + +The allowlist in `references/katex-commands.txt` was generated by probing a real +KaTeX build, one command at a time, and keeping only what actually rendered; it +contains no guesses. Regenerate it against a newer KaTeX with the recipe in +`references/note-format.md`. +""" + +from __future__ import annotations + +import re +import shutil +import subprocess +import sys +from pathlib import Path + +SKILL = Path(__file__).resolve().parent.parent +ALLOWLIST = SKILL / "references" / "katex-commands.txt" +RENDER_JS = SKILL / "scripts" / "render_check.js" + +FIX_ORDER = """Fix by preference order: + 1. In the note's OWN prose, write plain KaTeX (\\mathcal{A}, \\mathrm{Tr}, + \\operatorname{supp}) — a source's private macro has no business there. + 2. Put a verbatim quote that carries source macros in a fenced code block, or + a short inlined fragment in `backticks`; the bytes stay exact and nothing + tries to typeset them. + 3. Brace any multi-token argument: \\widetilde{\\mathcal U}, \\Delta_{\\mathcal U}. + 4. There is no step 4. A macro preamble does not work in the pipeline VS Code + uses, whatever the definition form.""" + + +def real_render(note: Path) -> tuple[str, int]: + """Parse every span with a real KaTeX build, when one is available. + + This is the stronger half of the check. The allowlist below catches unknown + command *names*; only a parser catches an unbraced argument such as + `\\widetilde\\mathcal U`, an unbalanced delimiter, or a bad environment. + + Returns (report, findings). findings < 0 means the check could not run. + """ + if not (shutil.which("node") and RENDER_JS.is_file()): + return ("real render: skipped (no node)", -1) + if not (SKILL / "node_modules" / "@vscode" / "markdown-it-katex").is_dir(): + return ( + "real render: skipped — enable it with\n" + f" (cd {SKILL} && npm install --no-save markdown-it @vscode/markdown-it-katex)\n" + " node_modules/ is already gitignored, so nothing is added to the tree.", + -1, + ) + proc = subprocess.run( + ["node", str(RENDER_JS), str(note)], capture_output=True, text=True + ) + body = (proc.stdout + proc.stderr).strip() + return (body, 0 if proc.returncode == 0 else 1) + +# `\foo`, or a single non-letter control symbol such as `\<`, `\{`, `\|`. +COMMAND_RE = re.compile(r"\\[A-Za-z]+|\\[^A-Za-z\s]") +# A definition in the note's own macro preamble. +DEF_RE = re.compile(r"\\(?:gdef|gdef\s*|global\s*\\def|def|newcommand|renewcommand|providecommand)\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?") +LOCAL_DEF_RE = re.compile(r"\\(?:newcommand|renewcommand|providecommand)\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?") +GLOBAL_DEF_RE = re.compile(r"(?:\\gdef|\\global\s*\\def)\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?") + + +def math_spans(text: str) -> list[tuple[int, str, str]]: + """Yield (line_number, kind, tex) for every span a renderer will typeset.""" + spans: list[tuple[int, str, str]] = [] + in_fence = False + in_block = False + block_start = 0 + block_buf: list[str] = [] + + for lineno, raw in enumerate(text.split("\n"), 1): + stripped = raw.lstrip("> ").rstrip() + if stripped.startswith("```") or stripped.startswith("~~~"): + in_fence = not in_fence + continue + if in_fence: + continue + if stripped == "$$": + if in_block: + spans.append((block_start, "block", "\n".join(block_buf))) + block_buf = [] + else: + block_start = lineno + in_block = not in_block + continue + if in_block: + block_buf.append(raw) + continue + # HTML comments never render. + line = re.sub(r"<!--.*?-->", "", raw) + for m in re.finditer(r"(?<!\\)\$([^$\n]+?)(?<!\\)\$", line): + spans.append((lineno, "inline", m.group(1))) + return spans + + +def main() -> int: + if len(sys.argv) != 2: + print(__doc__) + return 2 + note = Path(sys.argv[1]) + if not note.is_file(): + print(f"not a file: {note}") + return 2 + if not ALLOWLIST.is_file(): + print(f"missing allowlist: {ALLOWLIST}") + return 2 + + supported = {c for c in ALLOWLIST.read_text().split("\n") if c} + text = note.read_text() + spans = math_spans(text) + + # Macros the note defines for itself, split by whether they actually carry. + globals_: set[str] = set() + locals_: dict[str, int] = {} + for lineno, _kind, tex in spans: + for m in GLOBAL_DEF_RE.finditer(tex): + globals_.add(m.group(1)) + for m in LOCAL_DEF_RE.finditer(tex): + locals_.setdefault(m.group(1), lineno) + + findings: list[str] = [] + + for name, lineno in sorted({**locals_, **{g: 0 for g in globals_}}.items()): + findings.append( + f"{note}:{lineno or '?'}: `{name}` is defined inside the note. " + f"No definition form carries: measured through @vscode/markdown-it-katex, " + f"neither \\newcommand nor \\gdef nor \\global\\def survives to the next " + f"math span, because the plugin renders each span with fresh options" + ) + + undefined: dict[str, list[int]] = {} + for lineno, _kind, tex in spans: + body = GLOBAL_DEF_RE.sub("", LOCAL_DEF_RE.sub("", tex)) + for m in COMMAND_RE.finditer(body): + name = m.group(0) + if name in supported: + continue + undefined.setdefault(name, []).append(lineno) + + for name, lines in sorted(undefined.items()): + where = ", ".join(str(n) for n in lines[:6]) + more = f" (+{len(lines) - 6} more)" if len(lines) > 6 else "" + findings.append( + f"{note}: `{name}` is not a KaTeX command and is not \\gdef'd in this note " + f"— used at line(s) {where}{more}" + ) + + print(f"{len(spans)} math spans; {len(globals_) + len(locals_)} in-note macro " + f"definitions (none of which carry); {len(undefined)} undefined commands") + + report, rc = real_render(note) + print(report) + + # The pipeline is authoritative when it ran: it decides what a math span is, + # and this scanner's idea of that is an approximation. Its findings are + # reported only as a hint in that case, and are the whole verdict otherwise. + if rc >= 0: + if findings: + print("\n(scanner hints, superseded by the pipeline above:)") + for f in findings: + print(" " + f) + if rc == 0: + print("\nrender check: clean") + return 0 + print() + print(FIX_ORDER) + return 1 + + if not findings: + print("render check: scanner clean; the pipeline did not run, so brace, " + "delimiter and span-boundary errors remain unchecked") + return 0 + print() + for f in findings: + print(f) + print() + print(FIX_ORDER) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.claude/skills/math-extract/scripts/render_check.js b/.claude/skills/math-extract/scripts/render_check.js new file mode 100644 index 0000000..5e62be9 --- /dev/null +++ b/.claude/skills/math-extract/scripts/render_check.js @@ -0,0 +1,152 @@ +// Ground truth for the render check: run an extraction note through the same +// markdown + KaTeX pipeline a previewer uses, and report every ParseError with +// the note's own line number. +// +// Why a real markdown pipeline and not a hand-rolled `$…$` scanner: the scanner +// version of this script reported "0 ParseErrors" on a note that threw two of +// them in VS Code. A markdown renderer decides what a math span *is* — where it +// starts, where it ends, whether a `$` is math at all — and it does not agree +// with a regex. Delimiter pairing across lines, `$` inside table cells, and +// emphasis interacting with `^*` are all places the two diverge. So the check +// renders the document. +// +// Two facts worth keeping in view while reading a failure: +// +// * KaTeX's \newcommand is a *local* definition. It does not survive from one +// math span to the next -- not even when the renderer passes a shared +// `macros` object -- so a `$$`-block preamble of \newcommands leaves every +// later use throwing `Undefined control sequence`. Only \gdef is written +// back, and only a renderer that shares macro state carries it. +// * A command can be perfectly well defined and still fail: `\widetilde\mathcal U` +// and `\Delta_\mathcal U` are parse errors because `\widetilde` and `_` take a +// single token. No allowlist catches that; a parser does. +// +// node render_check.js <note.md> +// +// Reported in two classes: +// +// ParseError the pipeline could not typeset the span at all. +// portability hazard the span typesets *here* but relies on behaviour engines +// disagree about — `\,_2` (a subscripted thin space) and +// `\Delta_\mathcal U` (an unbraced multi-token argument) +// are the two that reached a reader before this check +// existed. KaTeX 0.16.47 and 0.18.4 both accept them. +// +// Requires markdown-it and @vscode/markdown-it-katex, which is the plugin VS +// Code's own Markdown preview uses: +// +// (cd .claude/skills/math-extract && npm install --no-save markdown-it @vscode/markdown-it-katex) +// +// Exit 0 clean, 1 on findings, 2 if the pipeline is unavailable. + +const fs = require('fs'); + +let MarkdownIt, katexPlugin, katex; +try { + MarkdownIt = require('markdown-it'); + katex = require('@vscode/markdown-it-katex/node_modules/katex'); + katexPlugin = require('@vscode/markdown-it-katex').default + || require('@vscode/markdown-it-katex'); +} catch (e) { + console.error('pipeline unavailable: ' + e.message); + process.exit(2); +} + +const file = process.argv[2]; +if (!file) { console.error('usage: node render_check.js <note.md>'); process.exit(2); } +const text = fs.readFileSync(file, 'utf8'); + +const errors = []; +const md = new MarkdownIt({ html: true }) + .use(katexPlugin, { + throwOnError: true, + strict: false, + // The plugin swallows the error and emits it as HTML; capture it instead. + errorColor: '#cc0000', + }); + +// The plugin catches KaTeX errors internally and renders them as text, so hook +// the renderer rules to see them rather than trusting an exception to escape. +for (const rule of ['math_inline', 'math_block', 'math_inline_block', 'math_block_eqno']) { + const prev = md.renderer.rules[rule]; + if (!prev) continue; + md.renderer.rules[rule] = function (tokens, idx, options, env, self) { + const out = prev.call(this, tokens, idx, options, env, self); + if (/katex-error|ParseError|Undefined control sequence/i.test(out)) { + const tok = tokens[idx]; + const line = tok.map ? tok.map[0] + 1 : null; + // Re-run the span through KaTeX directly to recover the message text; the + // plugin only leaves a coloured placeholder in the HTML. + let why = 'KaTeX error'; + try { + katex.renderToString(tok.content, { throwOnError: true, strict: false }); + } catch (err) { + why = (err.rawMessage || err.message || why).split('\n')[0]; + } + errors.push({ line, tex: tok.content, why }); + } + return out; + }; +} + +// Portability hazards: constructs that *this* KaTeX build happens to accept but +// that other engines reject. They are the ones that get reported by a reader +// rather than by the check, so they are collected from the spans the pipeline +// actually extracted -- inline code and fenced blocks are excluded for free. +const hazards = []; +const HAZARD_RULES = [ + [/\\[,;:!]\s*[_^]|\\q?quad\s*[_^]/, + 'a spacing command (\\, \\; \\: \\! \\quad) immediately subscripted or superscripted — ' + + 'subscripting a space is meaningless and engines disagree on whether it is an error'], + [/(?:[_^]|\\widetilde|\\overline|\\bar|\\hat|\\tilde|\\vec)\s*\\(?:mathcal|mathrm|mathbb|mathfrak|operatorname)\b/, + 'an unbraced multi-token argument (e.g. \\widetilde\\mathcal U) — brace it: \\widetilde{\\mathcal U}'], +]; +for (const rule of ['math_inline', 'math_block', 'math_inline_block', 'math_block_eqno']) { + const prev = md.renderer.rules[rule]; + if (!prev) continue; + const wrapped = md.renderer.rules[rule]; + md.renderer.rules[rule] = function (tokens, idx, options, env, self) { + const tex = tokens[idx].content; + for (const [re, why] of HAZARD_RULES) if (re.test(tex)) hazards.push({ tex, why }); + return wrapped.call(this, tokens, idx, options, env, self); + }; +} + +// The plugin dumps each KaTeX error object through `console.log` as it goes. +// We report the same errors ourselves, with line numbers, so silence it for the +// duration of the render only. +const realLog = console.log; +console.log = () => {}; +try { + md.render(text); +} finally { + console.log = realLog; +} + +// The token map is only reliable for block tokens; recover inline line numbers +// by locating the offending TeX in the source. +const lines = text.split('\n'); +function locate(tex) { + const needle = tex.trim().split('\n')[0].trim(); + if (!needle) return null; + for (let i = 0; i < lines.length; i++) if (lines[i].includes(needle)) return i + 1; + return null; +} + +for (const e of errors) { + const line = locate(e.tex) || e.line || '?'; + console.log(`line ${line}: ${e.why.slice(0, 160)}`); + console.log(` ${e.tex.replace(/\s+/g, ' ').slice(0, 130)}`); +} + +for (const h of hazards) { + const line = locate(h.tex) || '?'; + console.log(`line ${line}: portability hazard — ${h.why}`); + console.log(` ${h.tex.replace(/\s+/g, ' ').slice(0, 130)}`); +} + +console.log( + `\n${errors.length} ParseError(s) and ${hazards.length} portability hazard(s) ` + + `from the markdown+KaTeX pipeline` +); +process.exit(errors.length + hazards.length ? 1 : 0); From 82993836fdf99e114822431185bdfff7dd184212 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Mon, 17 Aug 2026 03:06:38 +0000 Subject: [PATCH 111/113] docs(math): extract the Umegaki relative entropy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New docs/math/umegaki-relative-entropy.md via /math-extract (large run, S=6, D=9, R=21, five lanes + a refutation pass). Adopts Hiai's standard f-divergence at f(t)=t log t (the totalised Araki relative-modular form) as the general definition, justified by the type-III generality-loss discriminator against the trace-based forms (Umegaki 1962, Hiai's semifinite restatement, Khatri–Wilde's finite-dimensional form). Notable findings the refutation pass forced onto the record: - Umegaki's own paper never uses the phrase "relative entropy" — it calls the object "information"; Hiai's "semifinite" attribution to it is a defensible generalisation of a claim the 1962 paper makes about itself, not a transcription of its (finite-class) standing hypothesis. - No source in the corpus proves the adopted form agrees with the trace form on a general semifinite algebra — only on B(H) and in finite dimensions — recorded as the note's principal open limitation. - Data processing fails for sub-unital (non-unital) Schwarz maps, with a worked 2x2 counterexample. - Umegaki's own monotonicity theorem is not the modern data-processing inequality: it needs two extra hypotheses the general form does not. worst-tier: c (the relative modular operator's basic properties are attested through Hiai's citations to Araki, whose papers could not be retrieved — see sources.md). Sources retrieved: Umegaki 1962 (Project Euclid PDF, MinerU-converted and independently cross-checked against the PDF's own OCR text layer), Hiai 2018, Vedral 2002, Witten 2018, Hollands–Sanders 2017 (already cached), Khatri–Wilde 2020. Araki's 1976/77 papers could not be obtained; recorded in sources.md with what was tried. --- .claude/skills/math-extract/sources.md | 6 + docs/math/README.md | 1 + docs/math/umegaki-relative-entropy.md | 1130 ++++++++++++++++++++++++ 3 files changed, 1137 insertions(+) create mode 100644 docs/math/umegaki-relative-entropy.md diff --git a/.claude/skills/math-extract/sources.md b/.claude/skills/math-extract/sources.md index aaa2d73..6412b09 100644 --- a/.claude/skills/math-extract/sources.md +++ b/.claude/skills/math-extract/sources.md @@ -85,3 +85,9 @@ different object is in the wrong file. | KOS13 | R. P. Kostecki, *W\*-algebras and noncommutative integration*, arXiv:1307.4818 | retrieved | `references/arxiv-1307.4818/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), byte-verbatim — **but its macros cannot be recovered**: `\usepackage{rpk}` and `\usepackage{motta}` at `raw/wstarint-arxiv.tex:35–36` are the author's private packages and are not in the arXiv package, so `\df \comm \N \C \BH \CC \II \zentr \limp` are undefined. A quote from KOS13 survives `grep -F`, but any *mathematical reading* of it is tier **(b)**, not (a). **WOT and SOT never occur anywhere in the document**: it states the double commutant theorem entirely in σ-topologies, and fixes them itself — `these topologies are usually called $\sigma$-strong and $\sigma$-strong-$\star$`. Keeps `W*`-algebra (Sakai predual) and von Neumann algebra as **distinct** notions. Its commutant is relative to an arbitrary ambient algebra. Three defects: it states the commutant's monotonicity **backwards** (`N₁ ⊆ N₂ ⟹ N₁' ⊆ N₂'`, false as printed), it drops the closure from Kreĭn–Milman one sentence after stating it correctly, and `source.txt:3779`/`3799` are a duplicated paragraph | 2026-08-16 | | SOR23 | J. Sorce, *Notes on the type classification of von Neumann algebras*, arXiv:2302.01958 | retrieved | `references/arxiv-2302.01958/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; macros at `raw/type_classification.tex:26,30,32,38`, `\ket`/`\bra` from the `physics` package. **Convention trap: its definition of "$*$-subalgebra" includes the identity operator.** Its statement of the double commutant theorem therefore looks false when read with the standard non-unital meaning (witnesses `{0}` and `ℂp` for a proper projection) and is true under its own definition — do not quote that statement without the definition. It also contradicts itself on the unit: the front matter requires it, `def:vN-algebra` omits it. `H` separable is a **standing** assumption declared in the front matter, and is unused by its double-commutant statement. Points its only proof at `section 21 of \cite{conway2000course}`, whose bibliography entry reads *A course in operator theory* (2000) — **not** *A Course in Functional Analysis*. Typo: its weak-convergence clause quantifies over `\ket{x}` only, omitting `\ket{y}` | 2026-08-16 | | MUR90 / PED79 / DIX77 / TAK79 / BLA06 | Murphy, *C\*-algebras and Operator Theory* (1990); Pedersen, *C\*-algebras and their Automorphism Groups* (1979); Dixmier, *C\*-algebras* (1977); Takesaki, *Theory of Operator Algebras I* (1979); Blackadar, *Operator Algebras* (2006) | not retrieved | — | — | 2026-08-16 | The standard C\*-algebra textbooks. Only a web search was attempted; no legitimate free copy was found for any of them, and no pirated copy was pursued. **The widely-repeated attribution of the separable refinement of Gelfand–Naimark to "Murphy Thm 3.4.1" is unverified** — nobody in this repository has opened the book, so no note may carry that locator. Expires 2027-02-16 | 2026-08-16 | +| UME62 | H. Umegaki, *Conditional expectation in an operator algebra, IV (entropy and information)*, Kodai Math. Sem. Rep. **14** (1962) 59–85 | partial | `references/umegaki-1962-cond-exp-iv/` | published | 2026-08-16 | **Project Euclid is behind Incapsula**: the `.../....pdf` URL returns a bot-block HTML page, and J-STAGE has no `kmj1949` record for this article (404 on both `_pdf` forms). What works is the download endpoint with a browser User-Agent: `curl -L -A "Mozilla/5.0 …" "https://projecteuclid.org/journalArticle/Download?urlId=10.2996%2Fkmj%2F1138844604"` → 2.4 MB PDF. Converted with MinerU `pipeline` (27 pp., GPU), so `source.txt` is model output. **The PDF carries a real OCR text layer**, extracted independently with `pypdf` to `pdftextlayer.txt` (`=== PDFPAGE n ===` separators; journal page = PDF page + 58), which raises cross-checked rows to (b) `mineru-cross-checked-against-PDF-text-layer`. No page-*image* check is possible: `pdftoppm`, `pdftotext`, `mutool`, `gs` are all absent from this container (same limitation as dB74). The text layer's OCR is 1962-vintage and mangles letters (`b`→`δ`, `ρ`→`^`, `≺`→`-<`), so it is usable for prose and structure, **not** for formulas. **MinerU dropped all four footnotes**; they survive only in the text layer. Three adjudications: (i) `locator §1`: the standing hypothesis is `of finite class and sigma-finite` with a faithful normal **finite** trace, *and* the same paragraph descopes it — `this assumption is not necessarily essential`, all theorems holding for semifinite `A` and a semi-trace `by a little or simply modified proofs`, subject to an unverified side condition on subalgebras; so HIA18's "semifinite" attribution is a **defensible generalisation of a claim the source makes about itself**, not an over-attribution. (ii) `locator footnote 7)` (`pdftextlayer.txt:782`): reads condition (8.3) for sufficiency **is satisfied** for a semi-trace — an earlier reading of this line as "is *not necessarily* satisfied" was wrong. Of the four semi-trace footnotes only fn 4) carves anything out, and it concerns the operator-entropy of `L^p` elements. **Unverified against a page image; the OCR is the sole witness.** (iii) `locator §4, Definition 1`: the definition carries only `a ≺ b` (defined in §1 as `s(a) ≤ s(b)`) and `τ(a)=τ(b)=1` — **finite entropy is not in it**; the class `ℰ` is defined separately at the end of §3 and is a hypothesis of the theorems. The phrase **"relative entropy" occurs zero times** in all three extractions | 2026-08-16 | +| HIA18 | F. Hiai, *Quantum f-divergences in von Neumann algebras I. Standard f-divergences*, arXiv:1805.02050; J. Math. Phys. 59 (2018) 102202 | retrieved | `references/arxiv-1805.02050/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim; single source file, macros by `\def` at `raw/main.tex:24–47` (`\bR \bC \cH \BH \Tr \< \> \ffi \sa \fS`). **Citation-key trap: `\bibitem{LR}` is Lesniewski–Ruskai 1999** (*Monotone Riemannian metrics and relative entropy on noncommutative probability spaces*), **not Lieb–Ruskai 1973** — and it is the citation carrying (F-3.1), the integral representation that the whole of §3 rests on. Other keys check out: `Ar5` = Araki, Publ. RIMS 11 (1976) 809–833; `Ar2` = Araki, Publ. RIMS 13 (1977) 173–192; `Ko` = Kosaki, J. Operator Theory 16 (1986) 335–348; `Pe2` = Petz, CMP 114 (1988) 345–349; `Um` = UME62. Cites Araki, never quotes him, so no locator into Araki may be printed as checked. **Label collision**: the example following Theorem 3.5 is labelled `E-12` in the LaTeX and prints as Example 3.6 — the same object. Four transcription slips, none affecting a statement: Example 2.5 writes `\Delta_{\phi,\phi}` where the relative modular operator of a *pair* is meant; the proof of Lemma 3.1 writes `f` for `f_n`; Cor. 4.4(1)'s proof has `1-s(s)` for `1-x(s)` and a `\sigma` where `\rho` belongs; Cor. 4.4(3)'s proof cites (F-2.9) where (F-2.8) is meant; Thm 4.5's proof writes `\sigma(1-{\alpha_0})` for `\sigma(1-e_{\alpha_0})`. **It states no tensor-product additivity** — its Prop. 2.3(4) is direct-sum additivity, and merging the two is an error | 2026-08-16 | +| VED02 | V. Vedral, *The role of relative entropy in quantum information theory*, arXiv:quant-ph/0102094; Rev. Mod. Phys. 74 (2002) 197 | retrieved | `references/arxiv-quant-ph-0102094/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), verbatim. Natural log throughout, and it says why. **Its definition of the relative entropy has no support condition and no `+∞` branch**, and never says where the formula is undefined — so it is a partial function whose domain the source does not state. Its properties F1–F3 are explicitly "left to the reader", and F2 (partial-trace monotonicity, the Lieb–Ruskai content) is what its whole CPTP argument consumes. **Symbol collision: `S_N` denotes both the von Neumann relative entropy and, a page later, the `N`-copy measured relative entropy.** Wording slip: F3 is an equality but is called "This inequality". Citation-key note: HS17's `\cite{vedral}` is Vedral–**Plenio** 1998, a different work | 2026-08-16 | +| KW20 | S. Khatri, M. M. Wilde, *Principles of Quantum Communication Theory: A Modern Approach*, arXiv:2011.04672 | retrieved | `references/arxiv-2011.04672/` | arXiv | 2026-08-16 | arXiv LaTeX (rung 1), byte-verbatim, **4.3 million characters — grep and jump, never read linearly**. **Its macros cannot be recovered**: `raw/sc.tex:1` is `\documentclass{Book_KW}`, a private class absent from the arXiv package, so `\Tr`, `\supp`, `\ket`, `\bra`, `\braket` are undefined in the bytes we hold (same failure mode as KOS13's `\usepackage{rpk}`). A quote survives `grep -F`, but any *rendering* of it needs reconstructed definitions. **The flattener collapses whitespace runs**: a quote copied from `source.txt` that crosses a double space (e.g. `$\rho$ and positive semi-definite`) matches `source.txt` and **fails** `source.flat.txt` — shorten the span rather than editing the bytes. Finite dimensions are a standing assumption *by fiat*. Its second argument is only positive semi-definite, so **its Klein inequality is conditional on `Tr σ ≤ 1`** and is not the same statement as HIA18's (which needs `ρ(1)=σ(1)>0`) or HS17's (both states). It **proves** operator Jensen and Stinespring itself, and states the operator convexity of `x ↦ x log_b x` and of `x^β` on `[-1,0) ∪ [1,2]` as numbered facts, deferring only the proofs — so a note calling `t log t` operator convex an unsourced edge is wrong about this corpus | 2026-08-16 | +| ARA76 / ARA77 | H. Araki, *Relative entropy of states of von Neumann algebras*, Publ. RIMS **11** (1976) 809–833; and *… II*, Publ. RIMS **13** (1977) 173–192 | not retrieved | — | — | 2026-08-16 | The papers the general (type-III-capable) definition is attributed to. Tried for I: Project Euclid `journalArticle/Download?urlId=10.2977%2Fprims%2F1195191148` with a browser UA (returns HTML, not a PDF — unlike the Kodai article, where the same endpoint works); the `.full` article page (404 via WebFetch); `kurims.kyoto-u.ac.jp/~prims/pdf/11-3/11-3-{11..14}.pdf` (404); `ems.press/journals/prims/articles?volume=11` (404). No PDF was converted. **Citation-key trap that survives the miss: WIT18's `\cite{Araki2}` is Araki, *Inequalities in Von Neumann Algebras*, Strasbourg RCP25 22 (1975) 1–25 — NOT the 1977 Publ. RIMS part II.** So "Araki 1976/77, per WIT18" is wrong; attribute 1977 to HIA18 or HS17 only, whose keys were verified. Expires 2027-02-16 | 2026-08-16 | +| KOS86 / PET88 / OP93 / LR99 / HAA75 | Kosaki, *Relative entropy of states: a variational expression*, J. Operator Theory 16 (1986) 335–348; Petz, *A variational expression for the relative entropy*, CMP 114 (1988) 345–349; Ohya–Petz, *Quantum entropy and its use*, Springer 1993; Lesniewski–Ruskai, J. Math. Phys. 40 (1999) 5702–5724; Haagerup, *The standard form of von Neumann algebras*, Math. Scand. 37 (1975) 271–283 | not retrieved | — | — | 2026-08-16 | Not sought — the extraction ran entirely through HIA18's and HS17's reproductions of them. **Ohya–Petz is the load-bearing one**: HS17 rests its *entire* property list (h1)–(h7) on it with no theorem numbers at all, and two of those items (superadditivity in the first argument; the tensor chain rule) appear in no other source of the 2026-08-16 corpus. HIA18 reproduces Kosaki's Theorem 3.2 formula verbatim and says its own differs by the integration range `[1/n,+∞)` vs `[1/n,n]`; whether Kosaki states it on `M_*^+` or on states is **not** recoverable from that reproduction. Expires 2027-02-16 | 2026-08-16 | diff --git a/docs/math/README.md b/docs/math/README.md index 9cae27c..bb2b5e3 100644 --- a/docs/math/README.md +++ b/docs/math/README.md @@ -31,6 +31,7 @@ the product. | Split inclusion of von Neumann algebras | [split-inclusion.md](split-inclusion.md) | `VonNeumannAlgebra.IsSplitInclusion` | | Faithful representation of a separable C\*-algebra on a separable Hilbert space | [separable-faithful-representation.md](separable-faithful-representation.md) | `CStarRep.exists_isometric_separable` | | Von Neumann bicommutant theorem | [bicommutant-theorem.md](bicommutant-theorem.md) | `DoubleCommutant.bicommutant_tfae` | +| Umegaki relative entropy | [umegaki-relative-entropy.md](umegaki-relative-entropy.md) | none | <!-- One row per note. "Implemented as" is a fact recorded after the object is formalized — the fully-qualified declaration that ended up carrying it, or diff --git a/docs/math/umegaki-relative-entropy.md b/docs/math/umegaki-relative-entropy.md new file mode 100644 index 0000000..f68fef0 --- /dev/null +++ b/docs/math/umegaki-relative-entropy.md @@ -0,0 +1,1130 @@ +--- +object: Umegaki relative entropy +slug: umegaki-relative-entropy +status: draft +worst-tier: c +mathlib-rev: 5450b53e5ddc75d46418fabb605edbf36bd0beb6 +implemented-as: none +revisions: + - 2026-08-16 · 2d7f460 · initial extraction · sources: UME62, HIA18, VED02, WIT18, HS17, KW20 +--- + +<!-- +No macro preamble. Every verbatim quote that carries a source's private macros +(\S, \U, \A, \a from WIT18; \Tr, \supp from KW20's unavailable Book_KW class) +is placed inside a fenced code block, so the bytes stay exactly as fetched and no +renderer tries to typeset them. Everything the note says in its own voice is +written in plain KaTeX. + +Do not reintroduce a `$$\newcommand{...}$$` block here: measured against +katex 0.18.4, \newcommand does NOT survive from one math span to the next -- not +even when the renderer passes a shared `macros` object, because \newcommand is a +local definition. Such a block leaves every later use of the macro throwing +`Undefined control sequence`. Only \gdef carries, and only into renderers that +share macro state at all. `scripts/check_render.py` enforces this. +--> +# Umegaki relative entropy + +## What this object is for + +The Umegaki relative entropy is a two-argument, non-symmetric, jointly convex, +jointly lower semicontinuous functional on pairs of normal positive functionals +on an operator algebra, whose classical special case is the Kullback–Leibler +divergence and whose operational meaning is the optimal error exponent in +asymmetric quantum hypothesis testing. Its defining structural property is +*monotonicity* under the adjoints of well-behaved positive unital maps — the +data-processing inequality — from which the literature derives non-negativity, +subadditivity, strong subadditivity, sufficiency of a subalgebra and the +entanglement measures of quantum field theory. + +Its generality is forced by a definitional obstruction, not by taste. The naive +formula $\mathrm{Tr}\,\rho(\log\rho-\log\sigma)$ needs a trace and needs $\log\sigma$, and +a type III von Neumann algebra — the case that actually occurs for the local +algebras of a quantum field — has neither. The object therefore has two lives: a +trace-based one (Umegaki 1962) and a relative-modular-operator one (Araki +1976/77), and the point of the modern treatment is that the second restricts to +the first where the first exists. + +## Definition + +### Variants as the sources write them + +The columns are the axes along which this corpus actually splits. `Total?` asks +whether the definition assigns a value to *every* pair, or is a partial function +whose domain is a hypothesis. `Apparatus` is what the formula is built out of. + +| (D#) | Source | Ambient algebra | Trace needed | Apparatus | Arguments | Total? | Tier | +|---|---|---|---|---|---|---|---| +| (D1) | [UME62] | finite class, σ-finite | **yes**, faithful normal finite | trace + Radon–Nikodym densities in $L^1(A)$ | both normalised | **no** — domain is $a\prec b$ | b | +| (D2) | [HIA18] §1 | semifinite | **yes**, semifinite | trace + density operators | both normal states | yes, case split | a / c | +| (D3) | [HIA18] §1 | arbitrary | no | relative modular operator | both normal states | yes, case split | a / c | +| (D4) | [HIA18] Def. 2.1 | arbitrary | no | standard $f$-divergence at $f(t)=t\log t$ | both in $M_*^+$, unnormalised | yes, boundary term | a | +| (D5) | [VED02] | none (matrices) | Tr | bare formula | both states | **no** — silent off the domain | a | +| (D6) | [WIT18] | arbitrary, with a cyclic separating vector | no | relative modular operator, vector form | $\Psi$ cyclic separating; $\Phi$ any | yes, $+\infty$ a consequence | a / c | +| (D7) | [HS17] | standard form, σ-finite | no | relative modular operator + Connes cocycle | both **faithful** normal states | partial, then stipulated | a / c | +| (D8) | [KW20] | $\mathcal B(\mathcal H)$, $\dim\mathcal H<\infty$ | Tr | bare formula, base 2 | first a state, second only PSD | yes, case split | a | +| (D9) | [HIA18] §3 / Kosaki | arbitrary | no | supremum over step-function paths | both in $M_*^+$ | yes | a / c | + +**(D1) [UME62] §4, Definition 1 (journal pp. 68–69)** — tier (b), +`mineru-cross-checked-against-PDF-text-layer` + +The cache is MinerU model output, so no blockquote is taken from it; the +following is a paraphrase, and every clause below was confirmed independently +against the PDF's own OCR text layer (`pdftextlayer.txt`, extracted with `pypdf`) +as well as against the MinerU conversion. + +Standing setting (§1): $A$ is a von Neumann algebra **of finite class and +σ-finite**, carrying a fixed faithful normal (finite) trace $\tau$; $L^p(A)$ are +Segal's measurable-operator spaces; a normal state $\rho$ has a +Radon–Nikodym derivative $d\rho/d\tau\in L^1(A)$ with +$\rho(a)=\tau((d\rho/d\tau)a)$. For self-adjoint $a,b$, Umegaki writes $a\prec b$ +to mean $s(a)\le s(b)$, $s(\cdot)$ the support projection. + +Definition 1: for $a,b\in L^1(A)$ with $a,b\ge 0$, $a\prec b$ and +$\tau(a)=\tau(b)=1$, +$$I(a,b)=\tau(a\log a-a\log b),$$ +called the **information** between $a$ and $b$; and for normal states with +$\sigma\prec\rho$, $I(\sigma,\rho):=I(d\sigma/d\tau,\,d\rho/d\tau)$. The singular +part is cut off inside the definition by $a\log b:=a\,s(b)\log b$. + +Four points that are easy to get wrong: + +1. **The name is *information*, not *relative entropy*.** See (X6): the string + "relative entropy" occurs zero times in the paper. *Entropy* is reserved for + the one-argument $H(a)=-\tau(a\log a)$, and §5 defines a separate symmetric + *divergence* $J(a,b)=I(a,b)+I(b,a)$ on the stricter domain $a\sim b$. +2. **The support condition is a hypothesis of the definition, not a case.** + Outside $a\prec b$, $I(a,b)$ receives no value at all. There is no $+\infty$ + branch anywhere in the paper. +3. **Finite entropy is *not* in Definition 1.** The class + $\mathcal E=\{a\in L^1(A): a\ge0,\ |H(a)|<\infty,\ \tau(a)=1\}$ is defined + separately at the end of §3 and is a hypothesis of the *theorems* (R7)–(R11). + Proposition 4.1 gives two independent sufficient conditions for $I(a,b)$ to be + unambiguous in $(-\infty,+\infty]$: $ab=ba$, or $H(a)$ finite with $b$ bounded. +4. **The setting is *finite*, not semifinite — but Umegaki descopes it himself.** + §1 states that a faithful normal trace exists iff $A$ is of finite class and + σ-finite, then says the assumption "is not necessarily essential" and that for + semifinite $A$ with a semi-trace all theorems and propositions hold "by a + little or simply modified proofs", subject to an unverified side condition on + subalgebras. Footnote 5) goes further and *extends the definition itself* to + the semifinite case for $0\le a\in L^1(A)$ and $0\le b\in A$ with $a\prec b$, + where $b$ need not lie in $L^1(A)$ — so **Umegaki's own semifinite extension + already drops the normalisation of the second argument**, which is (D8)'s + asymmetric regime, in 1962. See (C4) and (X7). + +`differs from (D2):` a finite trace rather than a semifinite one; a partial +function rather than a total one; both arguments normalised; and a different +name. +`sources claim equivalence:` [HIA18] presents (D2) *as* Umegaki's; no source in +the corpus remarks on the finite/semifinite difference. + +**(D2) [HIA18] §1, eq. (F-1.1)** — tier (a) for HIA18's restatement, tier (c) as +a claim about what [UME62] says + +> ``` +> D(\rho\|\sigma):=\begin{cases} +> \tau(d_\rho(\log d_\rho-\log d_\sigma)) & \text{if $s(\rho)\le s(\sigma)$}, \\ +> +\infty & \text{otherwise}, +> \end{cases} +> ``` + +introduced by + +> the relative entropy $D(\rho\|\sigma)$ was first +> introduced in 1962 by Umegaki \cite{Um} for normal states $\rho,\sigma$ on a semifinite von + +and glossed + +> where $\tau$ is a semifinite trace on $M$, $d_\rho$ is the density operator of $\rho$ with +> respect to $\tau$ and $s(\rho)$ is the support projection of $\rho$. + +`differs from (D1):` semifinite versus finite trace; total versus partial; and +the **letters are swapped** — see (C1), under which +$D_{\mathrm{HIA}}(\rho\|\sigma)=I_{\mathrm{UME}}(\sigma,\rho)$. +`sources claim equivalence:` yes, by identification. See (X7) for the +adjudication: this is a defensible generalisation of a claim [UME62] makes about +itself, not a transcription of its standing hypothesis. + +**(D3) [HIA18] §1, eq. (F-1.2)** — tier (a) for the restatement, tier (c) for the +attribution to Araki, whose papers were not obtained + +> ``` +> D(\rho\|\sigma):=\begin{cases} +> -\<\xi_\rho,(\log\Delta_{\sigma,\rho})\xi_\rho\> +> =\<\xi_\sigma,(\Delta_{\rho,\sigma}\log\Delta_{\rho,\sigma})\xi_\sigma\> +> & \text{if $s(\rho)\le s(\sigma)$}, \\ +> +\infty & \text{otherwise}, +> \end{cases} +> ``` + +preceded by + +> Later in 1970's Araki +> \cite{Ar5,Ar2} extended Umegaki's relative entropy, by introducing the \emph{relative modular +> operator} $\Delta_{\rho,\sigma}$ for normal states $\rho,\sigma$, to general +> von Neumann algebras as + +Supporting apparatus (HIA18 §2.1, tier (a) for HIA18's statements): every +$\sigma\in M_*^+$ has a unique vector representative $\xi_\sigma$ in the natural +cone with $\sigma(x)=\langle\xi_\sigma,x\xi_\sigma\rangle$; +$S_{\rho,\sigma}(x\xi_\sigma+\eta):=s_M(\sigma)x^*\xi_\rho$ for $x\in M$, +$\eta\in(1-s_{M'}(\sigma))\mathcal H$; +$\Delta_{\rho,\sigma}:=S_{\rho,\sigma}^*\overline{S_{\rho,\sigma}}$; the support +projection of $\Delta_{\rho,\sigma}$ is $s_M(\rho)s_{M'}(\sigma)$. + +Note the **two equal expressions with opposite subscript orders** inside +(F-1.2). That is the notational trap; see (C2). + +`differs from (D1)/(D2):` no trace, no density operators, no semifiniteness — +valid for an arbitrary von Neumann algebra, type III included. +`sources claim equivalence:` [HIA18] says Araki *extended* Umegaki's, by +citation, not by proof. The reduction is *proved* in this corpus only for +$\mathcal B(\mathcal H)$ ((R3)) and for finite-dimensional bipartite systems ((R13)). See +`## Open questions`. + +**(D4) [HIA18] Definition 2.1, eqs. (F-2.4)–(F-2.6)** — tier (a) + +For $\rho,\sigma\in M_*^+$ (arbitrary normal **positive functionals**, not +necessarily states) and $f$ convex on $(0,\infty)$: + +> We then introduce the {\it standard $f$-divergence} $S_f(\rho\|\sigma)$ of $\rho,\sigma$ by + +> ``` +> S_f(\rho\|\sigma):=\<\xi_\sigma,f(\Delta_{\rho,\sigma})\xi_\sigma\> +> +f(0^+)\sigma(1-s_M(\rho))+f'(+\infty)\rho(1-s_M(\sigma)). +> ``` + +with $f(\Delta_{\rho,\sigma}):=\int_{(0,+\infty)}f(t)\,dE_{\rho,\sigma}(t)$ — the +spectral integral over the **open** interval, the endpoints carried by the two +boundary terms explicitly — and the scalar conventions $bf(0/b):=f(0^+)b$, +$0f(a/0):=f'(+\infty)a$, $(+\infty)\cdot0:=0$, $(+\infty)c:=+\infty$ for $c>0$. +The relative entropy is the case $f(t)=t\log t$, for which $f(0^+)=0$ and +$f'(+\infty)=+\infty$. + +`differs from (D3):` **not in value** — (D4) *is* (D3) at $f=t\log t$, extended +off states to all of $M_*^+$. It differs in *mechanism*: the $+\infty$ on +non-dominated supports is not a case split but the boundary term +$f'(+\infty)\rho(1-s_M(\sigma))$, which is what makes (D4) automatically +homogeneous, additive over direct sums and jointly lower semicontinuous. +`sources claim equivalence:` yes — HIA18 Remark 2.7 and Example 3.12, proved in +source for $\mathcal B(\mathcal H)$ with $\dim\mathcal H<\infty$. + +A near-miss recorded here rather than as its own variant: HIA18 Remark 2.7 also +displays Petz's *quasi-entropy* at $k=1$, which for $f=t\log t$ gives +$\mathrm{Tr}\, D_\rho(\log D_\rho-\log^+ D_\sigma)$ with $\log^+0:=0$ — finite for every +pair — and calls it improper. That is a formulation the literature exhibits and +discards; it is (X1). + +**(D5) [VED02], the Definition following the von Neumann entropy, eq. (def8)** — +tier (a) + +> {\bf Definition}. {\em The von Neumann relative entropy} between +> the two states $\sigma$ and $\rho$ is defined as + +> ``` +> S_N(\sigma ||\rho) = \mbox{Tr} \sigma (\ln \sigma - \ln \rho) \;\; . +> ``` + +Explicit natural logarithm. **No support condition and no $+\infty$ branch at +all**; the singular case is not discussed anywhere in the paper. The attribution +is in the same paragraph: + +> this quantity was first considered by Umegaki (1962), but for +> consistency reasons I name it after von Neumann; I will also refer +> to it as the quantum relative entropy). + +`differs from (D8):` no support condition, hence a partial function whose domain +the source never states; natural log; second argument a state. +`sources claim equivalence:` with Umegaki's, asserted. VED02 is internally +consistent in keeping $\sigma$ first throughout (F1–F3, Theorem 5, the Stein +exponent). + +**(D6) [WIT18] §"Relative Entropy In Quantum Field Theory", eq. (onorf)** — +tier (a) for WIT18's statements, tier (c) as a claim about Araki + +> \S_{\Psi|\Phi}(\U)= -\la\Psi|\log \Delta_{\Psi|\Phi}|\Psi\ra. + +with $\Delta_{\Psi|\Phi}:=S^\dagger_{\Psi|\Phi}S_{\Psi|\Phi}$ and +$S_{\Psi|\Phi}\,a|\Psi\rangle=a^\dagger|\Phi\rangle$; $\Psi$ must be cyclic and +separating for $\mathcal A_{\mathcal U}$, while $\Phi$ may be any state. The singular case is a +consequence rather than a stipulation: + +> ``` +> For example, $\S_{\Psi|\Phi}(\U)$ may be $+\infty$ if $\Delta_{\Psi|\Phi}$ has a zero eigenvalue, which will occur if $\Phi$ is not separating for $\A_\U$. +> ``` + +`differs from (D3):` the subscript convention on $S$ and $\Delta$ is reversed +(C2), and the first argument must carry a cyclic separating vector. +`sources claim equivalence:` yes, and **proved in source** for the +finite-dimensional case — see (R13). + +**(D7) [HS17], the Definition of the relative entropy, eq. (drel1)** — tier (a) +for HS17's statements, tier (c) as a claim about Araki + +> H(\omega, \omega') = \langle \Omega | \log \Delta_{\omega, \omega'} \ \Omega\rangle + +together with the Connes-cocycle expression +$\lim_{t\to0}\omega([D\omega:D\omega']_t-1)/(it)$ as part of the same +definition — a **third** equivalent expression, present in no other corpus +source. Standing hypotheses: + +> ``` +> One assumes to be given two faithful, normal states $\omega, \omega'$ on a v. Neumann algebra $\A$ in standard form. +> ``` + +and three stipulations the others do not make: an explicit two-parameter +rescaling rule +$H(\lambda\omega,\lambda'\omega')=\lambda H(\omega,\omega')+\lambda\log(\lambda/\lambda')$; +$H(\omega,\omega')=\infty$ when $\omega'$ is not normal; and the frank + +> When $\omega$ or $\omega'$ are not faithful (such that +> $|\Omega\rangle,|\Omega'\rangle$ are not standard), the definition has to be somewhat modified~\cite{ohya_1}. + +The **plus** sign here is not a disagreement with HIA18's minus: HS17 uses +HIA18's subscript order and inserts the index-reversed $\Delta$. See (C2). + +`differs from (D3):` requires both states faithful; carries the cocycle formula +as part of the definition; and its domain is the positive functionals of a +**C\*-algebra**, not $M_*^+$ — see (C8). +`sources claim equivalence:` the $\mathcal B(\mathcal H)$ reduction is computed in source; the +general equality with Araki's is asserted by citation. + +**(D8) [KW20], Definition (`def-rel_ent`)** — tier (a) + +Stated for *every state* $\rho$ and *positive semi-definite operator* $\sigma$ — +the asymmetry is in the definition's own hypothesis, not a later remark: + +> the \textit{quantum relative entropy of $\rho$ and $\sigma$}, denoted by $D(\rho\Vert\sigma)$, is defined as + +> ``` +> D(\rho\Vert\sigma)=\left\{\begin{array}{l l} \Tr[\rho(\log_2 \rho-\log_2\sigma)] & \text{if }\supp(\rho)\subseteq\supp(\sigma),\\ +\infty & \text{otherwise}. \end{array}\right. +> ``` + +with $0\log_2 0=0$, base 2 uniformly, finite dimensions throughout, and the +asymmetry stated deliberately: + +> More generally, we could define the quantum relative entropy exactly as above, but with both arguments being positive semi-definite operators. For our purposes in this book, however, it suffices to restrict the first argument to be a state. + +`differs from (D2):` base 2; finite dimensions; second argument merely positive +semi-definite. +`sources claim equivalence:` with Umegaki's, by citation; with the regularised +form $\lim_{\varepsilon\to0^+}D(\rho\|\sigma+\varepsilon\mathbb 1)$, **proved in +source** — see (R14). + +**(D9) [HIA18] §3, Theorem 3.5 and Example 3.12; Kosaki 1986** — tier (a) for +HIA18's own expression, tier (c) for Kosaki's, whose paper was not obtained + +HIA18's expression, obtained by specialising its Theorem 3.5 to $f=-\log t$, is a +supremum over $n\in\mathbb N$ and over $M$-valued step functions $x(\cdot)$ of an +explicit expression involving $\sigma(1)\log n$, a correction term +$(\sigma(1)-\rho(1))\tfrac{2}{n+1}$, and +$-\int_{[1/n,n]}\{\sigma((1-x(s))^*(1-x(s)))+s^{-1}\rho(x(s)x(s)^*)\}s^{-1}\,ds$. + +Substitution sentence for Kosaki (tier (c), no locator into Kosaki's paper): +*Kosaki, "Relative entropy of states: a variational expression" (J. Operator +Theory 16 (1986) 335–348, per HIA18's bibliography) expresses the relative +entropy as a supremum over $n$ and over $M$-valued step functions $x(\cdot)$ of +$\sigma(1)\log n-\int_{[1/n,+\infty)}\{\sigma((1-x(s))^*(1-x(s)))+s^{-1}\rho(x(s)x(s)^*)\}s^{-1}\,ds$ +— the integration range $[1/n,+\infty)$ being the only difference HIA18 names — +from which positivity, joint convexity, lower semicontinuity and monotonicity +follow directly. Whether Kosaki states it on $M_*^+$ or on states is not +recoverable from HIA18's reproduction.* + +HIA18 on the relation: + +> This expression is similar to but a bit different from the variational expression + +`differs from (D4):` the same functional, presented as a supremum; the cut-off +interval is two-sided in HIA18 and one-sided in Kosaki, which HIA18 explains as +what makes its expression behave under the transpose +$\widetilde f(t)=tf(t^{-1})$. +`sources claim equivalence:` yes — HIA18 derives its own from Theorem 3.5, +proved in source, and reports Kosaki's as an alternative for the same quantity. + +There is a **second, genuinely different** variational expression, Petz's, at +(R16); it is not a further (D#) because HIA18 states it for the relative entropy +already defined, not as a definition. + +### Adopted general form + +Let $M$ be a von Neumann algebra in standard form $(M,\mathcal H,J,\mathcal P)$, and let +$M_*^+$ be the positive cone of its predual — the normal positive linear +functionals on $M$, **not** required to be normalised, faithful, or nonzero. For +$\rho,\sigma\in M_*^+$ let $\xi_\rho,\xi_\sigma$ be their unique vector +representatives in the natural cone $\mathcal P$, let $s_M(\cdot)$ and +$s_{M'}(\cdot)$ denote the support projections in $M$ and in $M'$, let +$S_{\rho,\sigma}$ be the conjugate-linear operator determined on the dense +subspace $M\xi_\sigma+(1-s_{M'}(\sigma))\mathcal H$ by +$S_{\rho,\sigma}(x\xi_\sigma+\eta):=s_M(\sigma)x^*\xi_\rho$, and let +$\Delta_{\rho,\sigma}:=S_{\rho,\sigma}^*\overline{S_{\rho,\sigma}}$ be the +relative modular operator, with spectral measure $E_{\rho,\sigma}$ on +$s_M(\rho)s_{M'}(\sigma)\mathcal H$. Writing $f(t)=t\log t$ on $(0,\infty)$, so that +$f(0^+)=0$ and $f'(+\infty)=+\infty$, the **Umegaki relative entropy of $\rho$ +with respect to $\sigma$** is +$$ +D(\rho\|\sigma)\;:=\;\int_{(0,+\infty)}t\log t\;d\|E_{\rho,\sigma}(t)\xi_\sigma\|^2 +\;+\;0\cdot\sigma(1-s_M(\rho))\;+\;(+\infty)\cdot\rho(1-s_M(\sigma)), +$$ +the integral taken over the **open** interval, under the scalar conventions +$(+\infty)\cdot0:=0$ and $(+\infty)c:=+\infty$ for $c>0$. Its value lies in +$(-\infty,+\infty]$ for every pair; it is $+\infty$ exactly when +$s_M(\rho)\not\le s_M(\sigma)$ or the spectral integral diverges. Natural +logarithm (C3). The definition carries **no** hypothesis of semifiniteness, +σ-finiteness, separability, faithfulness, normalisation, or finite dimension — +(A1)–(A5) are all absent from it — and the only standing assumption is that $M$ +is presented in a standard form, which is (A6) and is provable. + +This is **(D4)**, i.e. **(D3) totalised**. The discriminator is **(X4) type III +generality loss**: on the local algebra $\mathcal A_{\mathcal U}$ of a wedge region there is no +trace at all, so (D1)/(D2)/(D8) have no referent there, while every ingredient +above exists for every von Neumann algebra — and (D4) loses nothing, because it +reproduces the trace expression on $\mathcal B(\mathcal H)$ ((R3)) and the classical +$f$-divergence on an abelian algebra ((R4)). **(X3)** shows the choice is forced +already one type earlier: the density-matrix form (D8) fails on any type II +factor, where a trace exists but $\mathrm{Tr}\,$-densities do not. Two further decisions +inside the modular family are settled by **(X5)**: the domain is $M_*^+$ rather +than the faithful states of (D7) or the cyclic-separating-vector states of (D6), +because the named pair $\rho=\mathrm{diag}(1,0)$, +$\sigma=\mathrm{diag}(\tfrac12,\tfrac12)$ on $M_2(\mathbb C)$ has relative +entropy $\log 2$ with $\rho$ not faithful, and neither (D6) nor (D7) reaches it. + +Two limits of this choice, stated here rather than buried: + +- **Nothing in this corpus proves that the adopted form agrees with (D1)/(D2) on + a general semifinite algebra.** What is proved is agreement on $\mathcal B(\mathcal H)$ (R3) and + in finite dimensions (R13); the nearest general statement, (R17), is restricted + to pairs related by a *bounded* relative Hamiltonian, is written with the + canonical trace on a crossed product rather than a trace on $M$, and is hedged + by its own source as a "complete resemblance". See `## Open questions`. +- (D7)'s domain is strictly **larger**: HS17 defines $H$ on the positive + functionals of a C\*-algebra, assigning $+\infty$ off the normal ones. That is + a totalisation by stipulation, recorded as (C8); the adopted form does not + include it. + +## Notation and conventions + +| (C#) | Axis | This note | Per source | Translation | +|---|---|---|---|---| +| (C1) | which argument is differentiated, and its letter | first argument, called $\rho$ | role order identical in **all six** sources: $(\text{first})(\log\text{first}-\log\text{second})$. Letters: [HIA18] [KW20] [WIT18] write $\rho$/$\Psi$ first; [UME62] [VED02] call that argument $\sigma$ | $D_{\mathrm{HIA}}(\rho\|\sigma)=I_{\mathrm{UME}}(\sigma,\rho)=S_{\mathrm{VED}}(\sigma\|\rho)$ after renaming | +| (C2) | subscript order on $S_{\cdot,\cdot}$, $\Delta_{\cdot,\cdot}$ | HIA18's: acts on the **second** index's vector | [HIA18] $S_{\rho,\sigma}(x\xi_\sigma+\eta)=s_M(\sigma)x^*\xi_\rho$; [HS17] $S_{\omega,\omega'}a\|\Omega'\rangle=a^*\|\Omega\rangle$; [WIT18] $S_{\Psi\|\Phi}a\|\Psi\rangle=a^\dagger\|\Phi\rangle$ — the **first** index | $\Delta^{\mathrm{WIT}}_{\Psi\|\Phi}=\Delta^{\mathrm{HIA}}_{\Phi,\Psi}$. HS17's $+$ with $\Delta_{\omega,\omega'}$ and HIA18's $-$ with $\Delta_{\sigma,\rho}$ are the same expression twice | +| (C3) | base of the logarithm | natural | explicit `\ln` [VED02]; explicit `\log_2` [KW20]; implicit natural [UME62] [HIA18] [WIT18] [HS17] | $D_{\mathrm{KW20}}=D/\ln 2$. Weightless for the definition ((X10)) but **two corpus statements are base-locked**: WIT18's positivity step $\log\lambda\le\lambda-1$ is false in base 2, and any pairing of $D$ with an exponential (Stein exponents) fixes the base | +| (C4) | normalisation of the arguments | none — both range over $M_*^+$ | both states: [UME62] main text, [VED02], [WIT18], [HS17] base case, [HIA18] (D2). First normalised / second free: [KW20], and **[UME62] footnote 5) in the semifinite case**. Both free: [HIA18] (D4), [HS17]'s extension | [HS17] gives the two-parameter rule $H(\lambda\omega,\lambda'\omega')=\lambda H+\lambda\log(\lambda/\lambda')$; [HIA18] states only joint homogeneity $S_f(\lambda\rho\|\lambda\sigma)=\lambda S_f(\rho\|\sigma)$. Consistent, but (R10)(h4) needs the former | +| (C5) | mechanism for the singular case | boundary term | hypothesis [UME62]; case split [HIA18](D2) [KW20]; boundary term [HIA18](D4); regularised limit [KW20]; consequence of a zero eigenvalue [WIT18]; silence [VED02] | all give $+\infty$ where all are defined; only the *shape* differs | +| (C6) | spelling of the support condition | $s_M(\rho)\le s_M(\sigma)$ | $s(\rho)\le s(\sigma)$ [HIA18]; $\operatorname{supp}(\rho)\subseteq\operatorname{supp}(\sigma)$ [KW20]; $\sigma\prec\rho$ [UME62], in its own letters | one condition, three spellings; always the dominated support is on the differentiated argument | +| (C7) | conjugate-linearity of the inner product | first slot | **no source in the corpus states it.** Inferred (tier (b)) from [HIA18] writing $\sigma(x)=\langle\xi_\sigma,x\xi_\sigma\rangle$ with $J$ a conjugate-linear involution, and [WIT18]'s Dirac notation | value-irrelevant for $\langle\xi,A\xi\rangle$ with $A$ self-adjoint | +| (C8) | domain of the functional | $M_*^+\times M_*^+$ | [HS17] extends to **all** positive functionals of a C\*-algebra, setting $H=\infty$ off the normal ones | a stipulated totalisation, not covered by the adopted form. **[HS17] is internally inconsistent**: its Definition totalises on the second argument only, while its (h1) reads as totalising on both | + +## Results and dependencies + +Grouped by source. Numbering is this note's. + +### (R1) $S_f(\rho\|\sigma)$ is well defined in $(-\infty,+\infty]$ + +For every $\rho,\sigma\in M_*^+$ and convex $f$, the expression of the adopted +form is well defined with values in $(-\infty,+\infty]$; in particular the +relative entropy never takes the value $-\infty$. + +- Source: [HIA18] Lemma 2.2 · tier (a) · **proved in source** +- Depends on: (A6), convexity of $f$ — which $t\log t$ satisfies, and which is + strictly weaker than the (A7) needed later, [ext: HIA18 §2.1 cites + [Ar2, Lemma 2.2] for the closability of $S_{\rho,\sigma}$ and + $F_{\rho,\sigma}$ and the identity + $S^*_{\rho,\sigma}=\overline{F_{\rho,\sigma}}$, which is what makes + $\Delta_{\rho,\sigma}$ a positive self-adjoint operator] +- Conventions: (C4) +- Proof route: (i) convexity gives an affine minorant $f(t)\ge a+bt$; (ii) + integrate it against $d\|E_{\rho,\sigma}(t)\xi_\sigma\|^2$; (iii) the constant + term evaluates to $a\,\sigma(s_M(\rho))$ by the support identity of (A6); (iv) + the linear term evaluates to $b\,\rho(s_M(\sigma))$, using + $J\Delta^{1/2}\xi_\sigma=s_M(\sigma)\xi_\rho$ from the closability edge; (v) + both are finite reals, so the integral exceeds $-\infty$. +- Verbatim: + > For every $\rho,\sigma\in M_*^+$, $S_f(\rho\|\sigma)$ is well defined with values in $(-\infty,+\infty]$. + +### (R2) Invariance, degenerate values, homogeneity, direct-sum additivity + +(1) $S_f(\rho\circ\Phi\|\sigma\circ\Phi)=S_f(\rho\|\sigma)$ for a +\*-isomorphism $\Phi$. (2) $S_f(0\|\sigma)=f(0^+)\sigma(1)$, +$S_f(\rho\|0)=f'(+\infty)\rho(1)$, $S_f(\sigma\|\sigma)=f(1)\sigma(1)$. +(3) $S_f(\lambda\rho\|\lambda\sigma)=\lambda S_f(\rho\|\sigma)$ for +$\lambda\ge0$. (4) Additivity over a **direct sum** $M=M_1\oplus M_2$. + +- Source: [HIA18] Proposition 2.3 · tier (a) · **proved in source** +- Depends on: (A6), [ext: Haagerup's uniqueness of the standard form up to a + unitary intertwining the modular conjugations and natural cones — needed for + (1) only] +- Conventions: (C4) +- Proof route: (1) uniqueness of the standard form; (2) directly from the + definition; (3) substitute $\xi_{\lambda\sigma}=\sqrt\lambda\,\xi_\sigma$ and + $\Delta_{\lambda\rho,\lambda\sigma}=\Delta_{\rho,\sigma}$, with $\lambda=0$ + from (2); (4) the standard form of a direct sum is the direct sum of the + standard forms, so $\Delta$ decomposes and the definition reads off. +- **This is direct-sum, not tensor-product, additivity.** No tensor additivity + statement appears in [HIA18]; the tensor statement is (R11), (R18), (R10)(h7), + (R15)(3), and they must not be merged. + +### (R3) The modular form reproduces the trace form on a type I factor + +For $M=\mathcal B(\mathcal H)$ with $\mathcal H$ arbitrary, +$\Delta_{\rho,\sigma}=L_{D_\rho}R_{D_\sigma^{-1}}$ (generalised inverse), and +$S_f(\rho\|\sigma)$ evaluates to the double sum +$\sum_{a>0}\sum_{b>0}bf(a/b)\mathrm{Tr}\, P_aQ_b$ plus the two boundary terms. At +$f=t\log t$ this is $\mathrm{Tr}\, D_\rho(\log D_\rho-\log D_\sigma)$ when +$s_M(\rho)\le s_M(\sigma)$ and $+\infty$ otherwise. + +- Source: [HIA18] Example 2.6 and Remark 2.7 · tier (a) · **proved in source** +- Depends on: (R1), the standard form of $\mathcal B(\mathcal H)$ on the Hilbert–Schmidt class with + $J=\ {}^*$ +- Conventions: (C5), (C6) +- **This is the corpus's cleanest statement that the adopted form restricts to + the trace form — but it is for $\mathcal B(\mathcal H)$, not for a general semifinite algebra.** +- Verbatim: + > On the other hand, $S_{t\log t}(\rho\|\sigma)$ in \eqref{F-2.6} coincides with the usual \emph{relative entropy} + +### (R4) The commutative case is the classical $f$-divergence + +For $M\cong L^\infty(\Omega,\mu)$ with $\mu$ σ-finite and $\rho,\sigma$ given by +densities $\phi,\psi$, $\Delta_{\rho,\sigma}$ is multiplication by the classical +Radon–Nikodym derivative and $S_f(\rho\|\sigma)$ equals +$\int_{\{\phi>0\}\cap\{\psi>0\}}\psi f(\phi/\psi)\,d\mu$ plus the two boundary +integrals — the classical $f$-divergence, hence at $f=t\log t$ the +Kullback–Leibler divergence. + +- Source: [HIA18] Example 2.5 · tier (a) · **proved in source** (HIA18 calls the + computation straightforward) +- Depends on: (R1) +- Conventions: (C6) +- The σ-finiteness here is the *example's*, needed to write $M_*\cong L^1$; it is + not a hypothesis of the adopted form. Mutually singular measures give + $+\infty$, the correct classical value. + +### (R5) Transpose symmetry + +$S_f(\rho\|\sigma)=S_{\widetilde f}(\sigma\|\rho)$ with +$\widetilde f(t):=tf(1/t)$. Since $t\log t$ and $-\log t$ are transposes, +$D(\sigma\|\rho)=S_{t\log t}(\sigma\|\rho)=S_{-\log t}(\rho\|\sigma)$. + +- Source: [HIA18] Proposition 2.4 and Example 3.12 · tier (a) · **proved in + source** +- Depends on: (R1), (A6) — for the support identity + $s_M(\rho)s_{M'}(\sigma)=Js_M(\sigma)s_{M'}(\rho)J$ used at step (ii), + [ext: HIA18 §2.2 cites [Ar2, Theorem 2.4] for + $\Delta_{\rho,\sigma}=J\Delta_{\sigma,\rho}^{-1}J$] +- Proof route: (i) $\widetilde f(0^+)=f'(+\infty)$ and + $\widetilde f{}'(+\infty)=f(0^+)$, so only the spectral term needs work; + (ii) apply the $J$-conjugation identity together with + $s_M(\rho)s_{M'}(\sigma)=Js_M(\sigma)s_{M'}(\rho)J$; (iii) convert the spectral + measure of one pair into that of the other; (iv) change variables in the + integral. + +### (R6) Variational expression + +For $f$ operator convex, $S_f(\rho\|\sigma)$ equals a supremum over $n$ and over +$M$-valued step functions of an explicit expression; see (D9). + +- Source: [HIA18] Theorem 3.5 · tier (a) · **proved in source** +- Depends on: (R1), (A7), [ext: the Lesniewski–Ruskai integral representation of + an operator convex function on $(0,\infty)$ as + $a+b(t-1)+c(t-1)^2+\int(t-1)^2/(t+s)\,d\mu(s)$ with $c\ge0$, $\mu\ge0$ + and the data unique — HIA18 cites it as `\cite{LR}`, which is + **Lesniewski**–Ruskai 1999, not Lieb–Ruskai] +- Conventions: (C4) +- Proof route: (i) rewrite $S_{f_n}$ using the truncated representation; (ii) + HIA18 Lemma 3.4 turns the spectral integral into an infimum over $M$-valued + step functions; (iii) take $\sup_n$ and apply HIA18 Lemma 3.2's monotone + convergence $S_{f_n}\nearrow S_f$. +- **This is the engine of the whole theory**: (R7) and everything after it is + read off from it. + +### (R7) Joint lower semicontinuity, joint convexity, monotonicity, martingale convergence + +For $f$ operator convex and $\rho,\sigma\in M_*^+$: (i) $(\rho,\sigma)\mapsto +S_f(\rho\|\sigma)$ is jointly lower semicontinuous in the $\sigma(M_*,M)$ +topology; (ii) it is jointly convex and jointly subadditive; (iii) it is +monotone in each argument under the stated sign conditions on $f(0^+)$ and +$f'(+\infty)$; (iv) **data processing** — for $\Phi:N\to M$ **unital**, positive, +normal and a Schwarz map, $S_f(\rho\circ\Phi\|\sigma\circ\Phi)\le +S_f(\rho\|\sigma)$; (v) martingale convergence along an increasing net of unital +subalgebras generating $M$. + +- Source: [HIA18] Theorem 4.1 · tier (a) · **proved in source**, all five parts +- Depends on: (R6), (R2)(3), (A7), (A11) +- Conventions: (C4). $\Phi$ acts on observables, so states pull back — the + Heisenberg picture. **Schwarz is strictly weaker than 2-positive and much + weaker than completely positive**, so this is a stronger theorem than the + usual CPTP data-processing inequality. +- Proof route: (i)+(ii) the bracketed expression in the variational formula is + affine and $\sigma(M_*,M)$-continuous in $(\rho,\sigma)$, and a supremum of + such is jointly lsc and jointly convex — convexity and subadditivity being + equivalent by the homogeneity of (R2)(3); (iii) read off the sign of the + boundary coefficients in the same formula; (iv) push an $N$-valued step + function $x(\cdot)$ to $y(s):=\Phi(x(s))$ and use unitality plus the Schwarz + inequality to dominate each bracket, then take suprema; (v) take the dense + subspace in (R6) to be $\bigcup_\alpha M_\alpha$, so that restricting the step + functions recovers the restricted divergence. +- Verbatim: + > \emph{Monotonicity:} Let $N$ be another von Neumann algebra and $\Phi:N\to M$ be a unital positive linear map that is normal + +### (R8) Peierls–Bogoliubov and strict positivity + +(1) $S_f(\rho\|\sigma)\ge\sigma(1)f(\rho(1)/\sigma(1))$, with equality (for +non-linear $f$, nonzero arguments) iff $\rho=(\rho(1)/\sigma(1))\sigma$. +(2) If $f$ is non-linear with $f(1)=0$ and $\rho(1)=\sigma(1)>0$ then +$S_f(\rho\|\sigma)\ge0$ with equality iff $\rho=\sigma$. At $f=t\log t$ this is +**non-negativity of the relative entropy with the equality case, on an arbitrary +von Neumann algebra**. + +- Source: [HIA18] Corollary 4.2 · tier (a) · **proved in source** +- Depends on: (R7)(iv), (A3), (A7), (A8), and HIA18's own Lemma 4.3 — an + elementary strict-convexity lemma it proves in source "since we find no + suitable reference" +- Conventions: (C4) — the hypothesis $\rho(1)=\sigma(1)$ is not decorative; see + the degeneracy row for dropped normalisation. +- Proof route: (i) apply (R7)(iv) to the subalgebra $\mathbb C1$, which is + exactly the scalar computation and yields the Peierls–Bogoliubov bound; + (ii) if $\rho=k\sigma$ then $\Delta_{\rho,\sigma}=k\Delta_\sigma$, the spectral + measure is a point mass and equality holds; (iii) conversely apply (R7)(iv) to + $\mathbb Ce+\mathbb Ce^\perp$ for each projection $e$; (iv) Lemma 4.3 forces + proportionality on every projection, hence $\rho=(\rho(1)/\sigma(1))\sigma$; + (v) part (2) is part (1) evaluated at $f(1)=0$ under the equal-mass hypothesis + $\rho(1)=\sigma(1)>0$ of (A3), with (A8) supplying the strictness. +- **Dependency inversion worth recording**: here non-negativity is a *corollary + of data processing*, not of Klein's inequality. +- Verbatim: + > \emph{Strict positivity:} Assume that $f$ is non-linear with $f(1)=0$ and $\rho(1)=\sigma(1)>0$. Then $S_f(\rho\|\sigma)\ge0$, and $S_f(\rho\|\sigma)=0$ $\iff$ $\rho=\sigma$. + +### (R9) Support reduction, orthogonal-support additivity, $\varepsilon$-regularisation + +(1) If $s_M(\rho),s_M(\sigma)\le e$ then $S_f(\rho\|\sigma)=S_f(e\rho e\|e\sigma e)$ +computed in $eMe$. (2) If the joins of the supports of two pairs are orthogonal, +$S_f$ is additive over the sum. (3) If $S_f(\omega_1\|\omega_2)<+\infty$ then +$S_f(\rho\|\sigma)=\lim_{\varepsilon\searrow0}S_f(\rho+\varepsilon\omega_1\|\sigma+\varepsilon\omega_2)$. + +- Source: [HIA18] Corollary 4.4 · tier (a) · **proved in source** +- Depends on: (R6), (R7)(i), (R7)(ii), (R7)(iv), (R2)(3), (R2)(4) +- Proof route: (1) "$\le$" by (R7)(iv), "$\ge$" by pushing $x(s)\mapsto ex(s)e$ + through (R6); (2) "$\ge$" via the subalgebra $eMe\oplus e^\perp Me^\perp$ with + (R7)(iv) and (R2)(4) and part (1), "$\le$" via the unital map + $x\mapsto exe+e^\perp xe^\perp$ and (R7)(iv); (3) "$\le$" from (R7)(i), + "$\ge$" from (R7)(ii) with (R2)(3). +- **(3) is the general-algebra analogue of (R14)**, and it is *conditional*: it + needs a reference pair of finite divergence, which $\sigma+\varepsilon\mathbb1$ + supplies only where a trace does. + +### (R10) The property list of the Araki relative entropy + +[HS17] enumerates (h1) positivity with the equality case, and $H=\infty$ for +non-normal arguments; (h2) weak lower semicontinuity **on the positive +functionals of a C\*-algebra**; (h3) subadditivity, equivalently convexity; (h4) +superadditivity in the first argument; (h5) monotonicity in the arguments; (h6) +Uhlmann's monotonicity theorem for normalised completely positive maps, with +equality for a faithful normal conditional expectation preserving a faithful +normal state; (h7) the tensor **chain rule** +$H(\omega,\omega'_1\otimes\omega'_2)=H(\omega,\omega_1\otimes\omega_2)+H(\omega_1,\omega'_1)+H(\omega_2,\omega'_2)$. + +- Source: [HS17], the (h1)–(h7) enumeration · tier (a) for the list, tier (c) for + each claim · **asserted** — every item is cited to Ohya–Petz, none is proved +- Depends on: [ext: Ohya–Petz, *Quantum entropy and its use* — a monograph + treatment of the Araki relative entropy establishing positivity with the + equality case, joint lower semicontinuity, joint convexity, superadditivity in + the first argument, monotonicity in both arguments and under normalised + completely positive maps, and the tensor chain rule. HS17 gives no theorem + numbers]; for (h6) additionally [ext: Lindblad 1973 and Uhlmann 1977 — + monotonicity of the relative entropy under normalised completely positive maps + between von Neumann algebras] +- Conventions: (C4) — (h4) needs HS17's two-parameter rescaling rule and is + **not** derivable from the joint homogeneity of (R2)(3); (C8) for (h2). +- Independent corpus support: (h1) is (R8)(2), (R12), (R15); (h2) is (R7)(i) but + only on $M_*^+$, a smaller domain; (h3) is (R7)(ii); (h5) is (R7)(iii); + (h6) is (R7)(iv), (R13), (R14), (R19). **(h4) and (h7) rest on Ohya–Petz alone + within this corpus.** Both were verified in finite dimensions during the + refutation pass — (h4) reduces exactly to the Holevo bound + $\chi\le H(\{\lambda_i\})$ via the compensation identity, with equality iff the + states are mutually orthogonal; (h7) is an algebraic identity needing no + product hypothesis on $\omega$. +- **(h5) is degenerate as printed**: for positive functionals on a unital + algebra, $\phi\le\omega$ with $\|\phi\|=\|\omega\|$ forces $\phi=\omega$, so + its first-argument clause is vacuous and (h5) states only monotonicity in the + second argument. +- Verbatim: + > (h1)] (positivity) $H(\omega, \omega') \ge 0$, and $H(\omega,\omega') = 0 \Rightarrow \omega=\omega'$ for states $\omega, \omega'$. + +### (R11) Additivity over tensor products (Umegaki) + +For $A_1,A_2$ **of finite class** with faithful normal traces, $A=A_1\otimes A_2$ +with $\tau=\tau_1\otimes\tau_2$, and $a_i\prec b_i$ in $\mathcal E(A_i)$: +$I(a_1\otimes a_2,\,b_1\otimes b_2)=I(a_1,b_1)+I(a_2,b_2)$, and likewise for the +divergence $J$. Corollary: $H(a_1\otimes a_2)=H(a_1)+H(a_2)$. + +- Source: [UME62] Theorem 3 and Corollary 3.1, §6 · tier (b), + `mineru-unchecked` · **proved in source** +- Depends on: (R7'), (A2), (A3), [ext: the tensor product of two von Neumann + algebras of finite class, with the tensor product of two faithful normal + traces, is again of finite class with a faithful normal trace — UME62 cites + Dixmier and Misonou by name for the direct-product construction] +- Conventions: (C1), (C4) +- Proof route: (i) split $\log(a_1\otimes a_2)$ into + $\log(a_1\otimes1)+\log(1\otimes a_2)$, an identity UME62 uses without proof; + (ii) regroup into the two bracketed differences, each of which is an + information in its own factor and therefore defined by (R7') under (A2); + (iii) factor $\tau=\tau_1\otimes\tau_2$ across elementary tensors, which is + where the Dixmier–Misonou edge enters; (iv) use $\tau(a_i)=1$ from (A3) to + kill the cross terms. +- Umegaki identifies this as the operator generalisation of the + Kullback–Leibler form of the Shannon–Wiener theorem for independent events. + It is **not** (R2)(4). + +### (R7') Non-negativity of the information + +For $a,b\in\mathcal E$ with $a\prec b$, $I(a,b)$ is uniquely determined and, when +finite, non-negative. Likewise for normal states of finite entropy. + +- Source: [UME62] Theorem 1, Corollary 4.1, Theorem 1′, §4 · tier (b), + `mineru-unchecked` · **proved in source** +- Depends on: (A2), (A3), and UME62's own Lemma 7.1 ($a\prec b$ implies + $a^e\prec b^e$) and Corollary 2.1, both proved in source, [ext: the operator + entropy $h(a)=-a\log a$ is operator concave and satisfies $h(E[a|B])\ge + E[h(a)|B]$ for every von Neumann subalgebra $B$ — UME62 attributes this to + Nakamura–Umegaki and independently to Davis, generalising Segal], [ext: the + classical Kullback–Leibler inequality that the information of two probability + densities is non-negative, with the second-order mean-value expansion of + $-h(\lambda)$ — UME62 cites Kullback–Leibler] + ((A1) is standing in [UME62] and so carries no edge, though the whole + statement is written through its trace.) +- Proof route: (i) for bounded $b$, Proposition 4.1(ii) makes $I(a,b)$ + unambiguous; (ii) condition onto the **commutative** algebra generated by $b$ + and apply the operator Jensen inequality $a^e\log a^e\le(a\log a)^e$; + (iii) Lemma 7.1 propagates $a\prec b$ to $a^e\prec b^e$, so by Corollary 2.1 + the cross term conditions cleanly; + (iv) subtracting reduces the claim to $I(a^e,b)\ge0$, where the two + operators commute; (v) expand $-h(\lambda)$ to second order and use + $\tau(a)=\tau(b)=1$ to kill the linear part, leaving a manifestly non-negative + trace; (vi) for unbounded $b$, approximate monotonically inside the algebra + generated by $b$ and rule out two limits by a commutation argument. +- **The dependency order is the reverse of (R8)**: here non-negativity is + primitive and monotonicity ((R12)) is derived from it. + +### (R12) Monotonicity under a conditional expectation — **doubly conditional** + +Theorem 4: for $a,b\in\mathcal E$ **affiliated with the commutant $B'$**, +$I(a^e,b^e)\le I(a,b)$ where $e=E[\cdot|B]$. Theorem 4′: for normal states of +finite entropy **in the $B$-tracelet space $T_B$** — i.e. $\sigma(xy)=\sigma(yx)$ +for all $x\in A$, $y\in B$ — $I_B(\sigma,\rho)\le I(\sigma,\rho)$. + +- Source: [UME62] Theorems 4 and 4′, §7 · tier (b), `mineru-unchecked` · + **proved in source** +- Depends on: (R7'), (A2), (A3), (A10), and UME62's Corollary 2.1 and Lemma 7.2, + both proved in source +- Proof route: (i) expand $I(a,b)-I(a^e,b^e)$ using Corollary 2.1 to + replace $\tau(a^eX)$ by $\tau(aX)$; (ii) invoke Lemma 7.2 — this is + precisely where affiliation with $B'$ buys mutual commutation of the four + operators — to combine the three logarithms; (iii) recognise the result as + $I(a,\,b\,a^e(b^e+(I-q'))^{-1})$, whose second argument is positive with trace + 1 by (A3); (iv) apply (R7') to that residual pair, which needs (A2); + (v) for Theorem 4′, transport + $\sigma\prec\rho$ through the densities and identify $(d\sigma/d\tau)^e$ with + $d\sigma_B/d\tau_B$. +- **[UME62] does not prove data processing in the modern sense.** Neither + hypothesis appears in (R7)(iv); this is the note's sharpest correction to the + standard story that "Umegaki proved monotonicity". + +### (R13) Sufficiency of a subalgebra as the equality case + +Under a commutativity hypothesis on the density system, $B$ is sufficient for a +family $S$ of faithful normal states iff $I_B=I$ on every pair of $S$, iff +$J_B=J$ on every pair. + +- Source: [UME62] Theorem 5, §8 · tier (b), `mineru-unchecked` · **proved in + source**, importing a criterion from Umegaki's own part III +- Depends on: (R12), (A2), (A10), UME62's Lemma 7.2, and UME62's Theorem 2 — the + equality case $I(a,b)=0\iff a=b$ under $ab=ba$, proved in source, [ext: + Umegaki, *Conditional expectation in an operator algebra III* — a von Neumann + subalgebra $B$ is sufficient for a family $S$ of faithful normal states iff + $d(\sigma)d(\rho)^{-1}=d(\sigma)^ed(\rho)^{e-1}$ for every pair in $S$] +- Proof route: (i) replace sufficiency by that criterion; (ii) Lemma 7.2 makes + the four densities mutually commuting, which is what (A10) buys and what makes + (R12) applicable to the family $S\subset T_M\subset T_B$; (iii) **the + monotonicity defect is itself an information**, + $I(\sigma,\rho)-I_B(\sigma,\rho)=I(d(\sigma),\,d(\rho)d(\sigma)^ed(\rho)^{e-1})$, + which is defined because the pair lies in $\mathcal E$ by (A2); (iv) apply + Theorem 2 to that commuting pair; (v) symmetrise for the $J$ version. +- Step (iii) is the mathematically interesting content and is worth carrying + forward independently of the sufficiency statement. + +### (R14) The finite-dimensional reduction of the Araki form (Witten) + +For $\mathcal H_1\otimes\mathcal H_2$ with $\Psi$ cyclic separating, reduced density matrices +$\rho_1,\rho_2$, and a second vector $\Phi$ with reduced density matrices +$\sigma_1,\sigma_2$: $\Delta_{\Psi|\Phi}=\sigma_1\otimes\rho_2^{-1}$, hence +$\mathcal S_{\Psi|\Phi}=\mathrm{Tr}\,\rho_1(\log\rho_1-\log\sigma_1)$. + +- Source: [WIT18] §"Monotonicity of Relative Entropy In The Finite-Dimensional + Case" · tier (a) · **proved in source** +- Depends on: (A4), (A5), WIT18's earlier computation of $\Delta_{\Psi|\Phi}$, + and the conjugacy of the two reduced density matrices of a pure state +- Conventions: (C2), (C3) +- Proof route: (i) substitute WIT18's $\Delta_{\Psi|\Phi}=\sigma_1\otimes\rho_2^{-1}$, + available because (A4) makes $\Delta_{\Psi|\Phi}$ densely defined and (A5) + makes $\rho_2^{-1}$ an honest inverse, and split the logarithm; + (ii) trace out $\mathcal H_2$ in the first term; (iii) in the + second, use conjugacy to rewrite $\mathrm{Tr}_2\rho_2\log\rho_2$ as + $\mathrm{Tr}_1\rho_1\log\rho_1$; (iv) combine. +- Verbatim: + > We have arrived at the usual definition of the relative entropy in nonrelativistic quantum mechanics. + +### (R15) Non-negativity in the vector formulation, with a different equality case + +$\mathcal S_{\Psi|\Phi}(\mathcal U)\ge0$, vanishing **precisely when $\Phi=a'\Psi$ for a unitary +$a'$ in the commutant $\mathcal A_{\mathcal U}'$** — equivalently, when $\Phi$ and $\Psi$ induce +the same state on $\mathcal A_{\mathcal U}$. + +- Source: [WIT18] §"Relative Entropy In Quantum Field Theory" · tier (a) · + **proved in source**, for a general von Neumann algebra with a cyclic + separating vector +- Depends on: (A3), (A4), [ext: WIT18 credits the scalar-inequality argument to + Araki's 1976 paper] +- Conventions: (C3) — the step $\log\lambda\le\lambda-1$ is base-locked +- Proof route: (i) $\log\lambda\le\lambda-1$ lifts by functional calculus to + $-\log\Delta_{\Psi|\Phi}\ge1-\Delta_{\Psi|\Phi}$; (ii) take the expectation in + $\Psi$ and use the normalisation $\|\Psi\|=\|\Phi\|=1$ of (A3) to get $0$; + (iii) equality saturates + the scalar inequality only at $\lambda=1$, forcing + $\Delta_{\Psi|\Phi}\Psi=\Psi$; (iv) this equates all matrix elements of + $\mathcal A_{\mathcal U}$ in the two vectors; (v) cyclicity (A4) turns $a\Psi\mapsto a\Phi$ into + a unitary in the commutant. +- **Do not merge this equality case with (R8)(2)'s $\rho=\sigma$.** They agree: + $\Phi=a'\Psi$ is exactly the condition that the two vectors give the same state. +- Verbatim: + > ``` + > An important elementary property is that $\S_{\Psi|\Phi}(\U)$ is always non-negative, and vanishes precisely if $\Phi=\a'\Psi$ + > ``` + +### (R16) Monotonicity under shrinking the region + +If $\widetilde{\mathcal U}\subset\mathcal U$ then $\mathcal S_{\Psi|\Phi}(\mathcal U)\ge\mathcal S_{\Psi|\Phi}(\widetilde{\mathcal U})$, +reduced to the operator inequality +$\Delta_{\widetilde{\mathcal U}}\ge\Delta_{\mathcal U}$ in the resolvent sense. + +- Source: [WIT18] §"Monotonicity of Relative Entropy" and §"The Proof" · + tier (a) · **proved in source**, self-containedly +- Depends on: (A4), (A9), [ext: the projection onto the graph of a closed densely + defined operator $T$ is the explicit $2\times2$ matrix with entries built from + $(1+T^*T)^{-1}$ — WIT18 attributes the computation to Stone and to Halmos], + [ext: Borchers' argument that the modular operator increases as the region + shrinks, from the ordering of graph projections] +- Proof route: (i) write the graph projection explicitly; (ii) if $T_1$ extends + $T_0$ then the graphs nest and the projections are ordered; (iii) evaluate the + projections on vectors of the form $(\psi,0)$ to get + $\langle\psi,(1+T_0^*T_0)^{-1}\psi\rangle\le\langle\psi,(1+T_1^*T_1)^{-1}\psi\rangle$; + (iv) rescale $T_i\mapsto T_i/\sqrt s$ to get the resolvent statement at every + $s>0$; (v) take $T_0=S_{\widetilde{\mathcal U}}$, $T_1=S_{\mathcal U}$, legitimate because the + larger algebra has more vectors $a|\Psi\rangle$; (vi) operator monotonicity of + $\log$ (A9) from the resolvent integral representation; (vii) take the + expectation in $\Psi$ and flip the sign. +- Verbatim: + > The inequality (\ref{wonorf}) is a direct consequence of an operator inequality + +### (R17) The Araki form in Haagerup $L^1$ — the closest thing to a general reduction + +For $\varphi\in M_*^+$ faithful and $\omega=\varphi^h$ with $h\in M_{\mathrm{sa}}$, one has +$h_\omega=\exp(\log h_\varphi+h)$ in Haagerup's $L^1(M)$ and consequently +$D(\omega\|\varphi)=\mathrm{tr}(h_\omega(\log h_\omega-\log h_\varphi))$, with $\mathrm{tr}$ the +canonical trace on the crossed product. + +- Source: [HIA18], Appendix B closing remark · tier (a) · **sketched** — the key + identity is imported wholesale +- Depends on: HIA18's Proposition 5.3(3), that the relative entropy is the + $\alpha\to1$ limit of the Petz–Rényi divergences, and its Theorem B.2, both + proved in source, [ext: a Trotter-type product formula in the spatial + $L^p$-spaces], [ext: Terp's isomorphism between spatial and Haagerup + $L^p$-spaces], [ext: HIA18 cites Araki's 1973 relative-Hamiltonian paper for + uniqueness of the relative Hamiltonian], [ext: HIA18 cites Donald's theorem + that a finite infimum of $h(\rho)+D(\rho\|\varphi)$ over normal states is attained + at a unique normal state] +- **The source's own hedge and its own limitation**: HIA18 calls this a + "complete resemblance" to Umegaki's formula, and says explicitly that when the + relative Hamiltonian is unbounded above it is problematic whether the formulas + still make sense. The trace is on a crossed product, not on $M$. **This is not + a reduction theorem.** +- Verbatim: + > which has a complete resemblance to Umegaki's relative entropy in the semifinite case (see \eqref{F-1.1}). + +### (R18) The support condition as an $\varepsilon$-limit + +$D(\rho\|\sigma)=\lim_{\varepsilon\to0^+}\mathrm{Tr}\,[\rho(\log_2\rho-\log_2(\sigma+\varepsilon\mathbb1))]$, +hence $D(\rho\|\sigma)=\lim_{\varepsilon\to0^+}D(\rho\|\sigma+\varepsilon\mathbb1)$. + +- Source: [KW20] Proposition (`prop-rel_ent_lim`) · tier (a) · **proved in + source** +- Depends on: (A5) +- Conventions: (C3), (C5), (C6) +- Proof route: (i) $\sigma+\varepsilon\mathbb1$ has full support, so the + expression is finite for each $\varepsilon>0$; (ii) block-decompose $\rho$ and + $\sigma$ along $\operatorname{supp}\sigma\oplus\ker\sigma$; (iii) if supports nest, the + off-support blocks vanish and the limit is the finite value; (iv) otherwise the + $\log_2\varepsilon$ term diverges, giving $+\infty$. +- **This is what justifies the $+\infty$ branch as the right value rather than a + convention.** Its general-algebra analogue is (R9)(3), which is conditional. + +### (R19) Basic properties in finite dimensions + +Isometric invariance; Klein's inequality $D(\rho\|\sigma)\ge0$ **under +$\mathrm{Tr}\,\sigma\le1$**; faithfulness; monotonicity in $\sigma$; tensor additivity with +the rescaling corollary $D(\rho\|\beta\sigma)=D(\rho\|\sigma)+\log_2(1/\beta)$; +and the direct-sum property for classical–quantum states. + +- Source: [KW20] Proposition (`prop-rel_ent`) · tier (a) · **proved in source** +- Depends on: (R18), (A5) +- Conventions: (C3), (C4). **Note the shape of Klein's inequality here.** Because + the second argument need only be positive semi-definite, non-negativity is + conditional on $\mathrm{Tr}\,\sigma\le1$; (R8)(2) instead requires + $\rho(1)=\sigma(1)>0$; (R10)(h1) assumes both are states. **Three different + statements.** + +### (R20) Data processing in finite dimensions, and the properties derived from it + +$D(\rho\|\sigma)\ge D(\mathcal N(\rho)\|\mathcal N(\sigma))$ for every quantum +channel $\mathcal N$. Klein's inequality, isometric invariance and joint +convexity are then all corollaries. + +- Source: [KW20] Theorem (`thm-monotone_rel_ent`), via the Petz–Rényi route, and + the following Proposition · tier (a) · **proved in source**, with the operator + Jensen inequality and Stinespring's theorem also proved in the book +- Depends on: (R19), (A5), (A11), and — proved in [KW20] itself, not cited — + Stinespring's theorem, the operator Jensen inequality in the form + $f(V^*XV)\le V^*f(X)V$ for isometric $V$, and the convergence + $D_\alpha\to D$ as $\alpha\to1$, [ext: KW20 states the operator convexity + of $x\mapsto x^\beta$ on $[-1,0)\cup[1,2]$ and operator concavity on $(0,1]$ as + a numbered fact, deferring the proof to its bibliographic notes] +- Proof route: (i) Stinespring plus isometric invariance reduce a channel to a + partial trace; (ii) reduce to invertible operators by a double limit; + (iii) write the Petz–Rényi quantity as a vector expectation of + $f(\rho^{-1}\otimes\sigma^{T})$ with $f(x)=x^{1-\alpha}$; (iv) construct the + isometry $V$ carrying the smaller purification to the larger; (v) apply + operator Jensen in the form $f(V^*XV)\le V^*f(X)V$; (vi) compute $V^*(\cdot)V$ + to be the reduced object; (vii) translate through $\log$, flipping direction + where $\alpha<1$; (viii) take $\alpha\to1$. +- Verbatim: + > One of the remarkable aspects of the data-processing inequality for the qua\-ntum relative entropy is that it alone can be used to prove many of the properties of the quantum relative entropy stated in Proposition~\ref{prop-rel_ent}. + +### (R21) The operational meaning: quantum Stein's lemma + +For all states $\rho,\sigma$, the optimal achievable rate and the strong converse +rate for asymmetric quantum hypothesis testing both equal $D(\rho\|\sigma)$; in +the singular case both are $+\infty$. + +- Source: [KW20] Theorem (`thm-q_Stein_lemma`) · tier (a) · **proved in source** + (the achievability and strong-converse halves were not read through here, so no + proof route is filed) +- Depends on: (R18), (R20), (A5), [ext: Hiai–Petz 1991 — the relative entropy is + the optimal type-II error exponent in asymmetric hypothesis testing between + i.i.d. copies of two states], [ext: Ogawa–Nagaoka 2000 — the strong converse] +- **This is the answer to "why this quantity and not another."** +- Verbatim: + > For all states $\rho$ and $\sigma$, the optimal achievable and strong converse rates are equal to the quantum relative entropy of $\rho$ and $\sigma$ + +### Three incompatible orders of derivation + +Reading the corpus as one graph, the same properties are obtained three ways, and +none is the textbook order: + +- **[UME62]**: operator concavity of $-a\log a$ → non-negativity (R7') → the + equality case → *conditional* monotonicity (R12) → sufficiency (R13). +- **[HIA18]**: the Lesniewski–Ruskai integral representation → the variational + expression (R6) → monotonicity, joint convexity and joint lower semicontinuity + all at once (R7) → non-negativity (R8). +- **[WIT18] / [KW20]**: an operator-monotonicity fact → monotonicity + (R16)/(R20) → non-negativity, isometric invariance, joint convexity, + subadditivity and strong subadditivity. + +In four of the six sources **monotonicity is primitive and non-negativity is its +corollary.** Only [UME62] goes the other way, and its monotonicity is the weak, +hypothesis-laden version. + +## Hypotheses + +| (A#) | Statement | Class | Evidence | Witness | Scope | Tier | Used by | +|---|---|---|---|---|---|---|---| +| (A1) | $M$ carries a faithful normal (semi)finite trace | model-dependent | — | the local algebra $\mathcal A_{\mathcal U}$ of a wedge region: [WIT18] states QFT local algebras are type III and "do not have a trace -- even one defined only on part of the algebra" | standing in [UME62]; **absent from the adopted form** | a | (R7'), (R11), (R12), (R13); (D1), (D2), (D8) | +| (A2) | finite entropy $\|H(a)\|<\infty$ ([UME62]'s class $\mathcal E$) | model-dependent | — | on $A=L^\infty([0,1],dx)$ with $\tau=\int dx$ — inside UME62's own setting — the density $C/(x\log^2 x)$ on $(0,\tfrac12)$ is integrable while $\int f\log f$ diverges, so $H(f)=-\infty$ | local to [UME62] | b | (R7'), (R11), (R12), (R13) | +| (A3) | both arguments normalised (equal mass, in the general form) | provable | [HS17] extends $H$ off normalised states by the explicit two-parameter rule, so the unnormalised value is *determined*, not assumed; [HIA18] defines $S_f$ on all of $M_*^+$; [KW20] says restricting the first argument to a state is expository | — | local | a | (R7'), (R8)(2), (R11), (R12), (R15); **and it is load-bearing inside them** — see the dropped-normalisation degeneracy row | +| (A4) | $\Psi$ cyclic and separating for the algebra | model-dependent | — | any Schmidt-rank-one product vector, e.g. $\|1\rangle\otimes\|1\rangle$ in $\mathbb C^2\otimes\mathbb C^2$: [WIT18] states $\Psi$ is cyclic and separating iff all Schmidt coefficients are nonzero | local to [WIT18]'s (D6) | a | (R14), (R15), (R16) | +| (A5) | finite dimension | model-dependent | — | every infinite-dimensional system; in particular every QFT local algebra | standing in [KW20], implicit in [VED02] | a | (R14), (R18), (R19), (R20), (R21) | +| (A6) | $M$ is presented in a standard form | **provable** | [HIA18] Appendix A **constructs** one unconditionally from an arbitrary faithful normal semifinite weight: `Then $(M,L^2(M),J=\,^*,L^2(M)_+)$ becomes a standard form of $M$` — existence is tier (a) *inside the corpus*; only uniqueness up to unitary equivalence remains cited to Haagerup | — | standing throughout the adopted form | a | (R1)–(R9), and the adopted form itself | +| (A7) | $f$ is operator convex | **provable** for the two functions this object needs | $t\log t=\int_0^\infty\bigl(\tfrac{t}{1+s}-\tfrac{t}{t+s}\bigr)ds$; writing the integrand as $\tfrac{t}{1+s}-1+s(t+s)^{-1}$ exhibits it as an affine function plus a positive multiple of the operator convex $t\mapsto(t+s)^{-1}$, and operator convexity survives positive combinations and pointwise limits. Independently, [KW20] states it outright: `The function $x\mapsto x\log_b(x)$, for every base $b>0$ and $x\in[0,\infty)$, is operator convex` | — | standing in [HIA18] §§3–4 | a | (R6), (R7), (R8), (R9) | +| (A8) | a non-affine operator convex function on $(0,\infty)$ is strictly convex | **provable** | from the integral representation of (R6): $\frac{d^2}{dt^2}\frac{(t-1)^2}{t+s}=\frac{2(1+s)^2}{(t+s)^3}>0$, so $f''(t)\ge 2c+\int\frac{2(1+s)^2}{(t+s)^3}d\mu(s)>0$ unless $c=0$ and $\mu=0$, i.e. unless $f$ is affine | — | local to [HIA18] Cor. 4.2 | b | (R8) | +| (A9) | $\log$ is operator monotone | provable | the resolvent integral representation $\log R=\int_0^\infty(\tfrac1{s+1}-\tfrac1{s+R})ds$, which [WIT18] derives in source | — | local | a | (R16) | +| (A10) | [UME62]'s operators are affiliated with $B'$ / its states lie in the tracelet space $T_B$ | model-dependent | — | any pair of normal states of a non-abelian $A$ failing $\sigma(xy)=\sigma(yx)$ for some $x\in A$, $y\in B$; $T_B$ is automatic only when $B$ lies in the centre | local to [UME62] §§7–8 | b | (R12), (R13) | +| (A11) | $\Phi$ is **unital** | model-dependent | — | $\Phi:\mathbb C\to M_2(\mathbb C)$, $\Phi(\lambda)=\lambda p$ with $p=\mathrm{diag}(0,1)$: CP, normal, sub-unital and Schwarz with equality, yet $D(\rho\circ\Phi\|\sigma\circ\Phi)=\tfrac12\log 5>\tfrac12\log(25/9)=D(\rho\|\sigma)$ for $\rho=\mathrm{diag}(\tfrac12,\tfrac12)$, $\sigma=\mathrm{diag}(\tfrac9{10},\tfrac1{10})$ | local to (R7)(iv) | b | (R7)(iv), (R20) | +| (A12) | $M$ is σ-finite | model-dependent | — | $\mathcal B(\mathcal H)$ for $\mathcal H=\ell^2(I)$ with $I$ uncountable: an uncountable orthogonal family of rank-one projections cannot all receive positive value under a normal state | standing in [HS17]; in [HIA18] a **proof convenience only** — it says σ-finiteness lets one "sometimes reduce arguments", offered after the theorems are proved without it | a | (R10) only | +| (A13) | Hilbert spaces are separable | model-dependent | — | same as (A12) | standing in [HS17] — and **used by no result about this object** | a | **none** | +| (A14) | both states faithful | model-dependent as stated, **removable** | [HIA18] §2.1 supplies the modification [HS17] defers to Ohya–Petz: extending the domain from $M\xi_\sigma$ to $M\xi_\sigma\oplus(1-s_{M'}(\sigma))\mathcal H$, dense for every $\sigma$, replaces cyclicity; inserting $s_M(\sigma)$ into the value replaces separatingness, since $x\xi_\sigma=0$ forces $s_M(\sigma)x^*=0$ | $\rho=\mathrm{diag}(1,0)$ on $M_2(\mathbb C)$ | local to [HS17]'s (D7) | a | (D7) only | +| (A15) | normality of the arguments | provable that it is not a hypothesis | [HS17] admits non-normal functionals and assigns $+\infty$; [HIA18] builds normality into the ambient $M_*^+$, a typing decision | — | — | a | none | + +**(A13) is a standing hypothesis that no result about this object consumes.** +[HIA18] proves the same properties, in greater generality, with no separability +anywhere. It is presumably consumed elsewhere in [HS17] (nuclearity, modular +estimates), which is outside this object. + +Checked and found **not** to be hypotheses of this object: statistical +independence of two subalgebras and nuclearity (both attach to [HS17]'s +entanglement measure $E_R$, not to $H$); hyperfiniteness (searched all six +caches); commutativity $\rho\sigma=\sigma\rho$ (a hypothesis of a +well-definedness lemma only, superseded exactly as (A2) is); the type of the +algebra, which is a hypothesis of the *trace* row (A1) and of nothing else. + +## Degeneracies and boundary cases + +| Case | Effect on the adopted form | Tier | +|---|---|---| +| intended case is nonvacuous | **Holds, with a construction.** (R17)'s underlying identity gives $D(\rho\|\omega)=-h(\rho)+D(\rho\|\varphi)$ for $\omega=\varphi^h$ on an **arbitrary** von Neumann algebra; at $\rho=\omega$ this reads $D(\omega\|\varphi)=\omega(h)$, which [HIA18] uses outright. Instantiate on a QFT local algebra $\mathcal A(O)$ with $\varphi$ the vacuum — faithful, the vacuum being cyclic and separating, which [HS17] states at theorem strength for Lechner's integrable models along with "each $\mathcal A(O)$ is of type III$_1$" — and $h$ any nonzero positive element of $M_{\mathrm{sa}}$: then $D(\omega\|\varphi)=\omega(h)\in(0,\infty)$, **finite and strictly non-zero on a type III₁ algebra with no trace anywhere**. Corroborated non-constructively by [HS17]'s $E_R(\omega_0)>0$ together with its finite upper bound for massive BW-nuclear theories. The scaling pair $\rho=k\sigma$ is *not* an acceptable witness here: [HIA18]'s own computation shows it sees only the point spectral measure at $k$, so it never probes the relative modular operator and holds on every algebra | b | +| zero object / scalars | No effect on definedness; the values are forced. $D(0\|\sigma)=0$, $D(\rho\|0)=+\infty$ for $\rho\ne0$, $D(0\|0)=0$, $D(\sigma\|\sigma)=0$. On $M=\mathbb C$: $D(p\|q)=p\log(p/q)$, hence $0$ on states — degenerate only because $\mathbb C$ has one state, and this case is *load-bearing*, since (R8) feeds it in as the subalgebra $\mathbb C1$. On $M=\{0\}$ the only pair is $(0,0)$ | a | +| finite-dimensional | No effect on definedness; the modular form **reproduces** the trace form (R3), (R14). But "finite-dimensional ⇒ finite value" is **false**: dimension 2 already gives $+\infty$ | a | +| commutative | Reduces to the classical $f$-divergence, hence to Kullback–Leibler — **proved** in the corpus (R4). The sanity check the object exists to pass | a | +| non-separable / non-σ-finite | **No effect.** [HIA18]'s Example 2.6 is stated for "an arbitrary Hilbert space", and σ-finiteness appears only as a proof convenience (A12). [UME62] needs σ-finiteness for its $L^1(A)$ machinery and disclaims even that | a | +| type III | **Decisive.** No trace, so (D1)/(D2)/(D8) have no referent: no $\tau$, no $d_\rho$, no $\mathrm{Tr}\,$-density. The adopted form is unaffected, because the standard form exists for every von Neumann algebra (A6). [HS17] states the obstruction from the other side: generalising the *von Neumann entropy* to arbitrary type is hard, while the *relative* entropy generalises | a | +| non-unital / degenerate representation | **Non-unital algebra**: outside the class — a von Neumann algebra is unital, and no source contemplates otherwise. **Non-unital map**: fatal, see (A11). **Degenerate/non-standard representation**: no effect on the adopted form, since (R2)(1) makes it a function of the algebra and the functionals only; but fatal to (D6)/(D7), which are stated for a *given* representation and a *given* vector | a | +| universally orthogonal index element ($\operatorname{supp}\rho\perp\operatorname{supp}\sigma$) | Value $+\infty$, and this is the *correct* value, not a convention (R18). Named separating pair, computed from [WIT18]'s own finite-dimensional formula: $\mathcal H=\mathbb C^2\otimes\mathbb C^2$, $\Psi=\tfrac1{\sqrt2}(\|1,1\rangle+\|2,2\rangle)$, $\Phi=\|1,1\rangle$, i.e. $\rho_1=\mathrm{diag}(\tfrac12,\tfrac12)$, $\sigma_1=\mathrm{diag}(1,0)$. This is the pair that kills (X1) | a | +| quantifier swap: $\forall\Phi$ ↦ $\exists\Phi$ in monotonicity | **Destroys the statement.** $\Phi=\mathrm{id}$ satisfies the existential with equality for *every* two-argument functional, so the $\exists$ form carries no information | b | +| quantifier swap: $\sup_n\sup_{x(\cdot)}$ in (R6) | No-op — two suprema over independent index sets commute. Nor does $\sup_n$ differ from $\lim_n$, the net being increasing by [HIA18] Lemma 3.2. A third, non-trivial invariance: the inner quantifier may range over $L$-valued step functions for **any** subspace $L\ni1$ dense in $M$ in the strong\* topology, which is what powers the martingale-convergence proof | a | +| hypothesis dropped: (A3) normalisation | **Non-negativity fails**, and this is the cleanest degeneracy in the note: $D(\rho\|2\rho)=-\log 2<0$. Confirmed four independent ways — [HIA18]'s Peierls–Bogoliubov equality case, [HS17]'s two-parameter rescaling rule, [KW20]'s $D(\rho\|\beta\sigma)=D(\rho\|\sigma)+\log_2(1/\beta)$, and [WIT18]'s positivity proof, whose final step is exactly $\|\Psi\|^2-\|\Phi\|^2=0$. Everything else — monotonicity, joint convexity, lower semicontinuity, additivity — survives; only the *sign* is lost | a | +| hypothesis dropped: (A11) unitality of $\Phi$ | **Data processing fails**, with the named counterexample in (A11). The mechanism: the predual of a sub-unital map is trace-*decreasing*, and $D$ is not jointly scale-invariant, so unequal shrinkage of the two arguments can increase the value | b | +| hypothesis dropped: support condition | Nothing is dropped from the adopted form — it is total and returns $+\infty$. Under (D1) the quantity becomes **undefined**, not $+\infty$; that total-versus-partial difference is (D1)'s only structural departure | a | +| hypothesis dropped: (A14) faithfulness | Splits asymmetrically. Second argument: faithfulness is what makes $S_{\omega,\omega'}$ well defined in (D7), and dropping it needs (A14)'s modification. First argument: not needed at all — $\rho=\mathrm{diag}(1,0)$, $\sigma=\mathrm{diag}(\tfrac12,\tfrac12)$ gives $\log 2$, one bit | a | +| hypothesis dropped: (A4) cyclicity of $\Psi$ | **Definedness** fails for (D6), not merely the value: [WIT18] says $S_{\Psi\|\Phi}$ makes sense as a densely defined operator only then. The adopted form needs nothing of the sort | a | +| hypothesis dropped: (A2) finite entropy | No effect on the adopted form, which never splits $\tau(a\log a)-\tau(a\log b)$ into two separately-finite terms. It is an artefact of (D1)'s difference-of-two-traces presentation | b | +| hypothesis dropped: (A7) operator convexity, keeping convexity | The *definition* survives — [HIA18] Definition 2.1 needs only convexity, and (R1) still gives well-definedness. What fails is (R6) and hence everything after it. The definition and the main theorem genuinely have different hypotheses | a | + +## Rejected formulations and refuted claims + +**Append-only.** + +| id | Candidate or claim | Disposition | Discriminator | Tier | Date | +|---|---|---|---|---|---| +| (X1) | $\mathrm{Tr}\,\rho(\log\rho-\log^+\sigma)$ with $\log^+0:=0$ — the totalised no-branch formula (Petz's quasi-entropy at $k=1$) | rejected | **(X4) source disagreement** — [HIA18] Remark 2.7 states the candidate and calls it "improper as a standard $f$-divergence" (under its hypotheses $M=\mathcal B(\mathcal H)$, $\dim\mathcal H<\infty$, $f(0^+)<\infty$); **and (X2) degeneracy** — on $\rho=\mathrm{diag}(\tfrac12,\tfrac12)$, $\sigma=\mathrm{diag}(1,0)$ it returns $-\log2<0$ for two genuine states | a | 2026-08-16 | +| (X2) | $-S(\rho)-\mathrm{Tr}\,\rho\log\sigma$, splitting into two separately-defined terms | rejected | **(X2) degeneracy** — the split is $\infty-\infty$ already in type I, at any normal state of $\mathcal B(\mathcal H)$ with infinite von Neumann entropy, whereas the difference is defined. No type III algebra is needed; [HS17] frames the contrast as one of *definability*, not generality. [UME62] itself performs the split only under "the entropy $H(a)$ is finite and $b$ is bounded" | b | 2026-08-16 | +| (X3) | density matrices on $\mathcal B(\mathcal H)$ / finite dimensions as **the** definition | rejected | **(X3) generality loss** — witness the **hyperfinite type II₁ factor**, which [WIT18] constructs: a trace exists there, but $\mathrm{Tr}\,$-densities do not, so the formula has no referent while the adopted form does. [KW20] scopes itself explicitly to finite dimensions | a | 2026-08-16 | +| (X4) | the trace formula (D1)/(D2) taken as the **general** definition | rejected | **(X3) generality loss** — witness the local algebra $\mathcal A_{\mathcal U}$ of a wedge region, type III with no trace even on part of the algebra. **Not** a rejection of (D1)/(D2) in their own semifinite scope, where they are correct and agree with the adopted form on $\mathcal B(\mathcal H)$ (R3) | a | 2026-08-16 | +| (X5) | requiring both states faithful ([HS17]) or the first vector cyclic separating ([WIT18]) as the definition's domain | rejected as a *domain choice*; both remain variants under `## Definition` | **(X3) generality loss** — named pair $\rho=\mathrm{diag}(1,0)$, $\sigma=\mathrm{diag}(\tfrac12,\tfrac12)$ on $M_2(\mathbb C)$, relative entropy $\log 2$, $\rho$ not faithful; neither (D6) nor (D7) reaches it, and both sources concede the gap. Note the asymmetry: [WIT18] constrains only the first argument, [HS17] both | a | 2026-08-16 | +| (X6) | *claim*: [UME62] introduced the "relative entropy" | refuted **as a claim about the name**; upheld as a claim about the object | `grep -F "relative entropy"` returns **zero hits** in all three independent extractions of [UME62] (MinerU `source.txt`, `source.flat.txt`, and the pypdf PDF text layer); all occurrences of "relative" are the ordinary English adverbial. The paper's object is *information* $I(\cdot,\cdot)$; *entropy* is the one-argument $H(a)$. [VED02] says as much in the corpus: "this quantity was first considered by Umegaki (1962), but for consistency reasons I name it after von Neumann" | b | 2026-08-16 | +| (X7) | *claim*: [HIA18] misdescribes [UME62]'s hypothesis by attributing the definition to a **semifinite** algebra | refuted | [UME62]'s standing hypothesis is indeed finite class + σ-finite, so HIA18's sentence is not a transcription — but §1 asserts the semifinite extension of every theorem in the paper, and **footnote 5) extends the definition itself** to the semifinite case. Of the four semi-trace footnotes, three support the extension and only footnote 4) carves anything out, and that concerns the operator-entropy of $L^p$ elements, not $I(\cdot,\cdot)$. HIA18's sentence is a **defensible generalisation of a claim the source makes about itself**; the residual gap is *proof*, not scope, since UME62's extension is asserted ("can be shown by a little or simply modified proofs") with an unverified side condition on subalgebras | b | 2026-08-16 | +| (X8) | the regularised form $\lim_{\varepsilon\to0^+}D(\rho\|\sigma+\varepsilon\mathbb1)$ | equivalent | — ([KW20] proves it, (R18)) | a | 2026-08-16 | +| (X9) | monotonicity for sub-unital (non-unital) Schwarz maps | rejected | **(X1) separating object** — $\Phi:\mathbb C\to M_2(\mathbb C)$, $\Phi(\lambda)=\lambda\,\mathrm{diag}(0,1)$, with $\rho=\mathrm{diag}(\tfrac12,\tfrac12)$ and $\sigma=\mathrm{diag}(\tfrac9{10},\tfrac1{10})$: $D(\rho\circ\Phi\|\sigma\circ\Phi)=\tfrac12\log5\approx0.805>\tfrac12\log(25/9)\approx0.511=D(\rho\|\sigma)$. The statement is **false**, not open | b | 2026-08-16 | +| (X10) | base 2 versus natural logarithm | preference-only — no discriminator found | — | a | 2026-08-16 | +| (X11) | the symmetrised divergence $J(\sigma,\rho)=I(\sigma,\rho)+I(\rho,\sigma)$ | **not a candidate reading of this object** — [UME62] gives it a separate Definition 2 on a stricter domain ($a\sim b$) and it is symmetric | — | b | 2026-08-16 | + +## Prior art + +| System | Found | Relation to variants | How searched | Measured at | +|---|---|---|---|---| +| Mathlib | `InformationTheory.klDiv` on measures via `Measure.rnDeriv`/`llr`, valued in `ℝ≥0∞`, `⊤` unless absolutely continuous **and** the log-likelihood ratio is integrable, with a correction term for non-probability measures | the classical special case; shares the `+∞` convention of (D2)/(D8) and is incompatible with (D5); carries a *second* `⊤` branch (non-integrability) that no quantum variant has | directory listing, file read, two `lean_leansearch` queries | mathlib rev `5450b53e` | +| Mathlib | `InformationTheory.klFun x = x*log x + 1 - x`, `strictConvexOn_klFun`, `klDiv_eq_integral_klFun` | the commutative shadow of (D4) at $f(t)=t\log t$, affinely normalised so $f(1)=f'(1)=0$; a single instance, not a general $f$-divergence | file read | mathlib rev `5450b53e` | +| Mathlib | `Real.negMulLog`, `strictConcaveOn_negMulLog`, `strictConvexOn_mul_log`, `deriv2_mul_log`; `Real.binEntropy`, `Real.qaryEntropy` | the scalar backbone of every variant, real-variable only | grep, `lean_leanfinder` | mathlib rev `5450b53e` | +| Mathlib | `Analysis/InnerProductSpace/StandardSubspace.lean` — `StandardSubspace`, `IsCyclic`, `IsSeparating`, with a file TODO reading "Define the Tomita conjugation, prove Tomita's theorem, prove the KMS condition" | a precursor to the apparatus of (D3)/(D6)/(D7); the modular operator itself is absent | `grep "Tomita\|Takesaki\|Araki\|Umegaki"` — the only match in all of Mathlib | mathlib rev `5450b53e` | +| Mathlib | `CFC.log a := cfc Real.log a` with `log_exp`, `exp_log`, `log_pow` | the operator logarithm exists at C\*-generality. **The singular case is the point**: `cfc` returns a junk value when the function is not continuous on the spectrum, and `Real.log 0 = 0`, so `CFC.log` coincides with the support-restricted logarithm (D1)'s convention intends exactly when $0$ is *isolated* in the spectrum — always so in finite dimensions — and is junk when $0$ is non-isolated | read `ExpLog/Basic.lean` and the `cfc` definition | mathlib rev `5450b53e` | +| Mathlib | `CFC.log_monotoneOn` on strictly positive elements — (A9). Operator **concavity** of log appears only as a file TODO | (A9) present; (A7) not found | grep, file reads | mathlib rev `5450b53e` | +| Mathlib | `WStarAlgebra` (predual merely exists), `VonNeumannAlgebra H` with `commutant_commutant` — one file | the ambient object of (D1)–(D4) exists as a definition; could not find normal states, traces, $L^1(A)$, or the type classification, having searched `grep -rni "semifinite\|faithful normal\|normal state"` over Mathlib | grep, file read | mathlib rev `5450b53e` | +| Mathlib | `instLoewnerPartialOrder`, `Matrix.PosSemidef`/`PosDef`, `Matrix.trace`; positive linear maps `A →ₚ[ℂ] A₂`, `PositiveLinearMap.PreGNS`, completely positive maps `A₁ →CP A₂` | the order in which (C6) and the corpus's operator inequalities are stated, and the finite-dimensional data of (D8). Could not find a support-projection notion, a bundled `State`, or normality, having searched `grep -rn "IsState\|StateSpace"` and `lean_leansearch "state on a C-star algebra positive linear functional norm one"` | grep, `lean_leansearch` | mathlib rev `5450b53e` | +| Mathlib | could not find: any quantum or von Neumann relative entropy; von Neumann entropy; Shannon entropy of a distribution; Rényi/Hellinger/Pinsker/hypothesis testing; a general $f$-divergence; trace-class or Hilbert–Schmidt operators; non-commutative $L^p$, Haagerup $L^1$, standard form, or a Radon–Nikodym derivative for states; the modular or relative modular operator; support projections; Löwner's theorem; the operator Jensen inequality; Lieb concavity; Lieb–Ruskai/Uhlmann joint convexity; Kosaki's variational expression; Stinespring dilation; density matrices, channels or POVMs; an operator $x\log x$ | — | ~20 greps plus five `lean_leansearch`/`lean_leanfinder` queries, all recorded in the lane notes | mathlib rev `5450b53e` | +| this repository | `Matrix.relativeEntropy (ρ σ : DensityMatrix n) : EReal`, `QuantumSystem/Analysis/Entropy/RelativeEntropy.lean`, with the docstring citing Umegaki 1962; surrounding `relativeEntropy_nonneg`, `_eq_zero_iff`, `_channel_le`, `_channel_eq_iff_recoverable`, `_jointly_convex`, and `Analysis/Matrix/{LiebConcavity,Effros,Pinching}` | closest to **(D8)**, with two stated differences: the log base is $e$, not 2; and the second argument is a density matrix, not merely positive semi-definite. No regularised form (R18). Nothing for (D1)–(D4), (D6), (D7), (D9). **The `implemented-as` field of this note is `none` only because that field belongs to `math-review`, not to this skill; a declaration for the finite-dimensional case exists** | repository grep, file read | 2026-08-16 | +| Physlib (`leanprover-community/physlib`) | `QuantumInfo/Entropy/Relative.lean`: `qRelativeEnt (ρ σ : MState d) : ENNReal`, docstring "Also called the Umegaki quantum relative entropy", defined as the $\alpha=1$ case of a sandwiched Rényi family, natural log, `⊤` when supports fail to nest. Around it: `qRelativeEnt_joint_convexity`, `_additive`, `lowerSemicontinuous`, `Entropy/DPI.lean`, `Entropy/SSA.lean`, `Channels/Pinching.lean`, `ResourceTheory/SteinsLemma.lean`, and `TraceInequality/{LownerHeinzTheorem,JensenOperatorInequality,LiebAndoTrace,OperatorGeometricMean}` | **direct prior art**, (D8)-shaped and finite-dimensional. Its variational formula is for the *sandwiched Rényi* quantity, not Kosaki's (D9) for the Umegaki form. Covers, finite-dimensionally, the external edges Löwner–Heinz, operator Jensen, Lieb concavity, joint convexity, pinching, support projections | GitHub trees API, raw file reads | 2026-08-16 | +| Physlib | `PhyslibAlpha/QuantumMechanics/StinespringDilation.lean` — Kraus form and `QuantumChannel`, over a general ring; its own TODO notes a second, different Stinespring elsewhere in the repository | supplies (R20)'s Stinespring edge, finite-dimensional | trees API, raw file read | 2026-08-16 | +| Rocq — `infotheo` | `probability/divergence.v`: `div = \sum_(a in A) P a * log (P a / Q a)`, base 2, with `div_ge0`, `div0P` | the classical case on finite distributions; base 2 as in (D8), but **real-valued with no `+∞`** — dominance is a lemma hypothesis, not a case split. Could not find a quantum relative entropy in the library, having listed all 87 `.v` files and read the divergence file | trees API, raw reads | 2026-08-16 | +| Rocq — CoqQ | density matrices, quantum Hoare logic, `majorization.v`; the only entropy hits are `entropy_majority`/`majority_entropy_le` on real vectors | could not find a quantum relative entropy | trees API, greps of the three likeliest files | 2026-08-16 | +| Isabelle/HOL main library | `HOL-Probability.Information`: `KL_divergence b M N` via `entropy_density` and `RN_deriv`, parametric base | the classical case; **real-valued with no `+∞`**, absolute continuity as a lemma hypothesis | WebFetch of the library page | 2026-08-16 | +| Isabelle AFP | only *Source Coding Theorem* under probability theory; *Isabelle Marries Dirac* is matrix quantum computation. Could not find a quantum relative entropy | — | topic index page plus two web searches; **the AFP full-text search endpoint returned only the search form**, so this is not a full-text sweep | 2026-08-16 | +| Lean Zulip | **unreliable miss** — the domain-restricted search returned no pages from those domains at all, which indicts the search channel, not the archive | — | `WebSearch` with `allowed_domains` | 2026-08-16 | + +## Open questions + +- **Does the adopted form agree with (D1)/(D2) on a general semifinite von + Neumann algebra?** Nothing in this corpus proves it. Proved: agreement on + $\mathcal B(\mathcal H)$ (R3) and in finite dimensions (R14). Nearest general statement: (R17), + restricted to bounded relative Hamiltonians, written with a crossed-product + trace, and hedged by its own source. This sits exactly at the object's + definition and is the note's principal limitation. +- Is [UME62]'s asserted semifinite extension (X7) actually valid, including its + unverified side condition that $\tau$ restrict to a semi-trace on every + subalgebra used? +- Is [UME62]'s $I(a,b)=0\Rightarrow a=b$ true without the commutativity + hypothesis its Theorem 2 carries? (R8)(2) settles the *mathematics* — it is — + so this is a proof-technique gap in the 1962 paper, not a truth gap. +- Do (R10)(h4) and (h7) have a source other than Ohya–Petz? Both were verified in + finite dimensions during this extraction; neither is proved anywhere in the + corpus. +- Is [UME62]'s footnote 7) polarity as read here? MinerU dropped all four + footnotes, so the PDF text layer is the sole witness, its OCR is damaged, and + no page-image check was possible in this container. The reading adopted is + "**is** satisfied"; an earlier reading of the same line said "is not + necessarily satisfied". Both come from the same OCR. + +## Sources + +**Append-only.** + +| Key | Work | Status | Cache | Version | Tier reached | Retrieved | +|---|---|---|---|---|---|---| +| UME62 | H. Umegaki, *Conditional expectation in an operator algebra, IV (entropy and information)*, Kodai Math. Sem. Rep. **14** (1962) 59–85 | retrieved (converted) | `references/umegaki-1962-cond-exp-iv/` | published | b | 2026-08-16 | +| HIA18 | F. Hiai, *Quantum $f$-divergences in von Neumann algebras I. Standard $f$-divergences*, arXiv:1805.02050; J. Math. Phys. **59** (2018) 102202 | retrieved | `references/arxiv-1805.02050/` | arXiv | a | 2026-08-16 | +| VED02 | V. Vedral, *The role of relative entropy in quantum information theory*, arXiv:quant-ph/0102094; Rev. Mod. Phys. **74** (2002) 197 | retrieved | `references/arxiv-quant-ph-0102094/` | arXiv | a | 2026-08-16 | +| WIT18 | E. Witten, *Notes on some entanglement properties of quantum field theory*, arXiv:1803.04993 | retrieved | `references/arxiv-1803.04993/` | arXiv | a | 2026-08-16 | +| HS17 | S. Hollands, K. Sanders, *Entanglement measures and their properties in quantum field theory*, arXiv:1702.04924 | retrieved | `references/arxiv-1702.04924/` | arXiv | a | 2026-08-16 | +| KW20 | S. Khatri, M. M. Wilde, *Principles of Quantum Communication Theory: A Modern Approach*, arXiv:2011.04672 | retrieved | `references/arxiv-2011.04672/` | arXiv | a | 2026-08-16 | +| ARA76 | H. Araki, *Relative entropy of states of von Neumann algebras*, Publ. RIMS **11** (1976) 809–833 | not retrieved — tried Project Euclid's download endpoint (returns HTML), its `.full` article page (404), `kurims.kyoto-u.ac.jp/~prims/pdf/11-3/*.pdf` (404), the `ems.press` volume index (404) | — | — | c | 2026-08-16 | +| ARA77 | H. Araki, *Relative entropy for states of von Neumann algebras II*, Publ. RIMS **13** (1977) 173–192 | not retrieved — same routes as ARA76 | — | — | c | 2026-08-16 | +| KOS86 | H. Kosaki, *Relative entropy of states: a variational expression*, J. Operator Theory **16** (1986) 335–348 | not sought | — | — | c | 2026-08-16 | +| PET88 | D. Petz, *A variational expression for the relative entropy*, Comm. Math. Phys. **114** (1988) 345–349 | not sought | — | — | c | 2026-08-16 | +| OP93 | M. Ohya, D. Petz, *Quantum entropy and its use*, Springer 1993 | not sought | — | — | c | 2026-08-16 | +| LR99 | A. Lesniewski, M. B. Ruskai, *Monotone Riemannian metrics and relative entropy on noncommutative probability spaces*, J. Math. Phys. **40** (1999) 5702–5724 | not sought | — | — | c | 2026-08-16 | +| HAA75 | U. Haagerup, *The standard form of von Neumann algebras*, Math. Scand. **37** (1975) 271–283 | not sought | — | — | c | 2026-08-16 | + +## Not investigated + +- **The `[ext]` coverage gap.** These external edges appear in `## Results` and + were **not** checked against any library or formalization: the strict-convexity + fact (A8); the Lesniewski–Ruskai integral representation under (R6); Petz's + variational expression (R16); the tensor product of two finite-class von + Neumann algebras under (R11); Umegaki's own part III sufficiency criterion + under (R13); Borchers' modular-operator ordering and the Stone/Halmos graph + projection under (R16); Donald's and Araki's relative-Hamiltonian results under + (R17); the classical Kullback–Leibler inputs of (R7'); the Peierls–Bogoliubov + inequality as [VED02] imports it; the polar-decomposition lemma [VED02] takes + from Reed–Simon; and — named as unchecked by the prior-art lane itself — the + operator Schwarz inequality, the Gibbs variational principle, Klein's + inequality, Petz recovery beyond this repository's own lemma, Araki's + Radon–Nikodym cocycle, and the Connes cocycle of (D7). +- **Araki's own papers were never opened.** Every claim in this note about what + Araki assumed, defined or proved is a claim about how [HIA18], [HS17] and + [WIT18] *report* him. In particular, whether Araki's original definition + assumed faithfulness is not settled here: [HS17] attributes the faithful + version to him and [HIA18] attributes the total version to the same two papers. +- **No page-image check of [UME62] was possible.** `pdftoppm`, `pdftotext`, + `mutool` and `gs` are all absent from this container, so the UME62 rows rest on + a MinerU conversion cross-checked against the PDF's own OCR text layer — two + extractions, no image. MinerU dropped the paper's footnotes entirely, so every + footnote claim (including (X7)'s footnote 5) and the open question about + footnote 7) rests on the text layer alone, uncross-checked. +- **[KW20] was searched, not read.** 4.3 million characters were grepped and + jumped; its later chapters were not swept for further statements about this + object. Likewise unread: [HIA18]'s Lemmas 3.1–3.4 and §5 Rényi proofs, its + Appendix A/B derivations beyond the statements quoted, [WIT18]'s + $\Delta_D\ge\Delta_N$ section, and the achievability and strong-converse halves + of (R21). +- **Variants sighted and not pursued**: [UME62]'s $I(\cdot;B)$ relative to a + subalgebra; [HIA18]'s Rényi and max-relative entropies and the $\alpha\to1$ + characterisation (R10's neighbour), where a further definitional variant could + hide; [VED02]'s measured/asymptotic characterisation + $S(\sigma\|\rho)=\lim_N S_N$, which is arguably a definition in its own right; + the Haagerup $L^p$ route of (R17) as a source of further variants. +- **Prior art not swept**: Physlib's spectral-theory and unbounded-operator + files were listed but not opened; the AFP was not full-text searched; Mizar, + HOL Light, `QuantumLib`/SQIR and `mathcomp-analysis` were not searched at all; + the Lean Zulip result is an unreliable miss. +- **The unexamined base.** Everything above rests on a tier-(c) floor: the + closability of $S_{\rho,\sigma}$ and the identity + $\Delta_{\rho,\sigma}=J\Delta_{\sigma,\rho}^{-1}J$ — the two facts that make the + adopted form's relative modular operator exist and behave — are attested only + through [HIA18]'s citations to Araki, whose papers could not be obtained. So + is Haagerup's uniqueness of the standard form under (R2)(1), the + Lesniewski–Ruskai representation under (R6), and the whole of (R10). The + adopted form itself is therefore **(c)**, which is what `worst-tier` records. From 1e4e1e750d4f356f93bd678c2caba5d155440df1 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Mon, 17 Aug 2026 03:56:44 +0000 Subject: [PATCH 112/113] feat(math-extract): render quotes' own notation via self-contained per-span \gdef The prior fix (7f81394) established that no macro definition survives across math spans and moved quotes carrying a source's own macros into fenced code blocks. That's correct but throws away the point of writing $...$ in the first place: the quote shows as raw LaTeX instead of the notation the source intended, and a whole-quote code fence visually disrupts the surrounding prose. \gdef does carry within the span that defines it, though -- nothing has to survive anywhere for that. So the new default is a local, self-contained macro definition inside the same $...$ (or $$...$$) the quote already uses: $\gdef\lok#1{{\mathcal #1}}\lok{B}$ This renders exactly as the source intended, in every renderer tested (bare KaTeX, @vscode/markdown-it-katex), with no cross-span persistence required. Where one macro name means different things in different sources (HS17's \A = \mathfrak{A}, WIT18's \A = \mathcal{A}), each quote gets the definition belonging to its own source. This changes what "verbatim" certifies: the displayed span carries an audited \gdef prefix ahead of the unchanged quote text. That prefix is presentation, not content -- strip it before the quote check, and audit it against the source's own preamble (or mark "reconstructed" when that preamble is unrecoverable, as with KW20's private Book_KW class, or when the gap is a LaTeX primitive KaTeX doesn't implement, like \mbox). Fencing remains the fallback for macros that cannot be \gdef'd at all. check_render.py's scanner is rewritten to match: it now parses macro definitions with a proper balanced-brace scan (the previous regex silently mis-stripped nested bodies like \gdef\BH{{\cal B}({\cal H})}), judges each span for whether its OWN definitions satisfy its OWN uses, and flags only genuine problems -- a \newcommand/\renewcommand (never carries, even within its own span), a span that is bare definitions with nothing to use them (the old preamble pattern reborn one span at a time), or a command with no local \gdef and no KaTeX support at all. Verified against a deliberately broken regression file, with and without the node/katex pipeline available. --- .../math-extract/references/note-format.md | 87 +++++++--- .../math-extract/scripts/check_render.py | 157 ++++++++++++------ 2 files changed, 172 insertions(+), 72 deletions(-) diff --git a/.claude/skills/math-extract/references/note-format.md b/.claude/skills/math-extract/references/note-format.md index 116eb60..196fb85 100644 --- a/.claude/skills/math-extract/references/note-format.md +++ b/.claude/skills/math-extract/references/note-format.md @@ -37,10 +37,17 @@ revisions: --- <!-- -No macro preamble: quotes carrying a source's private macros go in fenced code -blocks, and everything the note says in its own voice is plain KaTeX. See -"Source macros" below before reintroducing one — \newcommand does not survive -from one math span to the next. +No document-level macro preamble: no definition form survives from one math +span to the next in the renderers this note has to work in (see "Source +macros" below). Everything the note says in its own voice is plain KaTeX. A +verbatim quote needing a source's own macro carries a local, self-contained +\gdef of exactly that macro, defined and used inside the same $...$ pair, e.g. +`$\gdef\lok#1{{\mathcal #1}}\lok{B}$` — audited against the catalogue below, +which is copied from the source's own preamble (or marked "reconstructed" when +the source's own macro table is unrecoverable). + +Source macro catalogue (name[arity] = body, source, file:line): + \lok[1] = {{\mathcal #1}} DL84, references/<slug-of-source>/raw/<file>.tex:144 --> # <Object, as a mathematician names it> @@ -62,9 +69,10 @@ from one math span to the next. **(D1) [DL84] §1** — tier (a) > <verbatim quote, in the source's language, unmodified, formulas in the -> source's own notation. If it carries the source's own macros, fence it: -> a ``` block inside the blockquote keeps the bytes exact and keeps every -> renderer from trying to typeset them.> +> source's own notation. If it carries the source's own macros, give each one +> a local \gdef inside the same $...$ it is used in — see "Source macros" +> below — so it renders as the source intended; fence it only if a macro +> cannot be \gdef'd at all.> [tr.] <optional translation, outside the quote, tier (b)> @@ -203,23 +211,54 @@ until a reader opens the note: > The practical consequence: **a note cannot define macros for itself.** Every > occurrence throws `Undefined control sequence`. -So there are exactly two ways to keep a source's macros out of a reader's face: - -1. **In the note's own voice, write plain KaTeX.** `\mathcal{A}`, `\mathrm{Tr}`, - `\operatorname{supp}`, `\varphi`. A source's private macro has no business in - a sentence the note is asserting — the note is not that source, and every such - import is a rendering failure waiting for a reader. -2. **Put anything verbatim that carries source macros into code.** A fenced - block inside the blockquote for a displayed quote, backticks for a fragment - inlined into a table cell. The bytes stay exactly as fetched, the quote check - greps them unchanged, and no renderer tries to typeset them. A quote that will - not render is still a quote, and showing it as source LaTeX is showing it as - what it is. - -When a source's macros are *unrecoverable* — a private `\documentclass` or -`\usepackage` absent from the arXiv package, as with KW20's `Book_KW` — that is -a fact about the source and belongs in `sources.md`, not a rendering problem to -solve in the note. +**In the note's own voice, always write plain KaTeX** — `\mathcal{A}`, +`\mathrm{Tr}`, `\operatorname{supp}`, `\varphi`. A source's private macro has no +business in a sentence the note itself is asserting; the note is not that +source, and every such import is a rendering failure waiting for a reader. + +**For a verbatim quote, define the macro where it is used.** A `\gdef` does not +survive to the *next* span, but it works perfectly *inside the span that +defines it* — nothing has to survive anywhere. Prepend the definition, copied +verbatim from the source's own preamble, immediately inside the same `$…$` (or +`$$…$$`) the quote already uses: + +``` +$\gdef\lok#1{{\mathcal #1}}\lok{B}$ +``` + +This renders exactly as the source intended — `\lok{B}` still reads as +`\mathcal{B}` — with no cross-span persistence required, so it works in every +renderer this file has had to distrust: VS Code's preview, bare KaTeX, GitHub's. +A span using several macros gets one `\gdef` per macro it actually uses, deduped +in first-use order; a span using none is untouched. Where one macro name means +different things in different sources — HS17's `\A` is `\mathfrak{A}`, WIT18's +is `\mathcal{A}` — inject the definition that belongs to *that quote's own +source*, never the other one, even though the raw name collides. + +This changes what "verbatim" certifies: the displayed span is no longer +byte-identical to the source at that exact point — it carries an audited +`\gdef` prefix ahead of the unchanged quote. That prefix is presentation, not +content: **strip it before running the quote check**, and audit the stripped +definition against the catalogue in the note's own opening comment (see below), +which in turn must be copied from the source's own preamble, not paraphrased — +exactly the discipline the old document-level preamble comment required, now +scoped per macro instead of per document. When a source's macros are +*unrecoverable* — a private `\documentclass` or `\usepackage` absent from the +arXiv package, as with KW20's `Book_KW` — inject a **reconstructed** definition +instead (ordinary mathematical usage, e.g. `\gdef\supp{\operatorname{supp}}`), +label it `reconstructed` in the catalogue, and record the source's +unrecoverability in `sources.md`. The same applies to a genuine LaTeX primitive +KaTeX simply does not implement (`\mbox`, reconstructed as `\mathrm`) — that is +a gap in the renderer, not a macro belonging to any source, but the fix is the +same local `\gdef`. + +**Fall back to code — a fenced block inside the blockquote, or backticks for a +fragment — only when a macro cannot be `\gdef`'d at all**: a `\newenvironment`, +a catcode change, or anything a single substitution macro cannot express. The +bytes stay exactly as fetched, the quote check greps them unchanged, and no +renderer tries to typeset them — but the quote then shows as raw source LaTeX +rather than the intended notation, so this is the fallback, not the first +move. Beyond macro names, the other way a note breaks a renderer is an argument that looks braced and is not: `\widetilde\mathcal U` and `\Delta_\mathcal U` are both diff --git a/.claude/skills/math-extract/scripts/check_render.py b/.claude/skills/math-extract/scripts/check_render.py index 8f5a279..1e695c1 100755 --- a/.claude/skills/math-extract/scripts/check_render.py +++ b/.claude/skills/math-extract/scripts/check_render.py @@ -5,26 +5,30 @@ """Render check for an extraction note. Every math span in `docs/math/<slug>.md` must render **on its own**, and that is -the part that bites: **a note cannot define macros for itself.** Measured through -`@vscode/markdown-it-katex`, the plugin VS Code's own Markdown preview uses, -`\\newcommand`, `\\gdef` and `\\global\\def` all fail to reach the next math -span — the plugin renders each span with fresh options, so nothing is carried. -(Bare KaTeX behaves slightly better: `\\gdef` survives when the caller passes a -shared `macros` object. No markdown previewer does.) - -So a note whose prose says `$\\A_\\U$` throws `Undefined control sequence` on -every occurrence, however carefully the preamble was written, and the reader sees -a wall of ParseErrors instead of the mathematics. This script is what stops that -reaching the tracked note. +the part that bites: **no macro definition survives from one math span to the +next.** Measured through `@vscode/markdown-it-katex`, the plugin VS Code's own +Markdown preview uses: `\\newcommand`, `\\gdef` and `\\global\\def` all fail to +reach the NEXT span — the plugin renders each span with fresh options, so +nothing is carried forward. + +`\\gdef` works fine *within the span that defines it*, though — nothing has to +survive anywhere for that. So the convention this checker enforces is: a +verbatim quote needing a source's own macro carries a local, self-contained +`\\gdef` of exactly that macro, defined and used inside the same `$...$` pair, +e.g. `$\\gdef\\lok#1{{\\mathcal #1}}\\lok{B}$`. That renders exactly as the +source intended, in every renderer, with no persistence required. A `\\gdef` +sitting in a span with nothing else to use it (the old document-level preamble, +reborn one span at a time) is exactly as broken as before, and is flagged the +same way. uv run .claude/skills/math-extract/scripts/check_render.py docs/math/<slug>.md Exit 0 clean, 1 on findings, 2 on a usage error. What counts as a math span: `$...$` inline and `$$`-delimited blocks, **outside -fenced code**. Fenced code is deliberately exempt — it is the sanctioned place -for a verbatim quote that carries its source's private macros, because the bytes -survive untouched and no renderer tries to typeset them. +fenced code**. Fenced code is exempt — it is the fallback for a macro that +cannot be `\\gdef`'d at all, because the bytes survive untouched there and no +renderer tries to typeset them. The allowlist in `references/katex-commands.txt` was generated by probing a real KaTeX build, one command at a time, and keeping only what actually rendered; it @@ -47,12 +51,19 @@ FIX_ORDER = """Fix by preference order: 1. In the note's OWN prose, write plain KaTeX (\\mathcal{A}, \\mathrm{Tr}, \\operatorname{supp}) — a source's private macro has no business there. - 2. Put a verbatim quote that carries source macros in a fenced code block, or - a short inlined fragment in `backticks`; the bytes stay exact and nothing - tries to typeset them. + 2. In a verbatim quote, give the macro a LOCAL \\gdef inside the same $...$ it + is used in: `$\\gdef\\lok#1{{\\mathcal #1}}\\lok{B}$`. This renders as the + source intended, with no cross-span persistence required, so it is the + default fix, not a fallback. Audit the body against the source's own + preamble (or mark it "reconstructed" when that preamble is unrecoverable) + in the note's opening-comment macro catalogue. 3. Brace any multi-token argument: \\widetilde{\\mathcal U}, \\Delta_{\\mathcal U}. - 4. There is no step 4. A macro preamble does not work in the pipeline VS Code - uses, whatever the definition form.""" + 4. Fence a quote (or backtick a fragment) only when a macro cannot be + \\gdef'd at all (a \\newenvironment, a catcode change) — this shows raw + source LaTeX instead of the intended notation, so it is the last resort. + 5. There is still no document-level macro preamble: no definition form + survives from one math span to the next in the renderers this note has + to work in, whatever the definition form.""" def real_render(note: Path) -> tuple[str, int]: @@ -81,10 +92,51 @@ def real_render(note: Path) -> tuple[str, int]: # `\foo`, or a single non-letter control symbol such as `\<`, `\{`, `\|`. COMMAND_RE = re.compile(r"\\[A-Za-z]+|\\[^A-Za-z\s]") -# A definition in the note's own macro preamble. -DEF_RE = re.compile(r"\\(?:gdef|gdef\s*|global\s*\\def|def|newcommand|renewcommand|providecommand)\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?") -LOCAL_DEF_RE = re.compile(r"\\(?:newcommand|renewcommand|providecommand)\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?") -GLOBAL_DEF_RE = re.compile(r"(?:\\gdef|\\global\s*\\def)\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?") +# The head of a macro definition: name, then zero or more #N parameters, then +# the opening brace of its body. The body itself is matched separately by +# counting braces, since it is frequently nested (`\gdef\BH{{\cal B}({\cal H})}`) +# and a single non-recursive regex cannot balance that in general. +DEF_HEAD_RE = re.compile( + r"\\(?:gdef|global\s*\\def|def|(?:new|renew|provide)command)" + r"\s*\{?(\\[A-Za-z]+|\\[^A-Za-z\s])\}?((?:#\d+)*)\s*\{" +) + + +def strip_defs(tex: str) -> tuple[str, set[str], bool]: + """Remove every `\\NAME(#n)*{body}` definition from `tex`. + + Returns (remaining_text, names_defined, is_local_form). A definition is + "local form" (\\newcommand/\\renewcommand/\\providecommand) if ANY match is + of that form -- those are the ones that never carry, full stop, and are + flagged regardless of where they appear. + """ + names: set[str] = set() + local_form = False + out = [] + i = 0 + n = len(tex) + while i < n: + m = DEF_HEAD_RE.match(tex, i) + if not m: + out.append(tex[i]) + i += 1 + continue + names.add(m.group(1)) + if re.match(r"\\(?:new|renew|provide)command", m.group(0)): + local_form = True + depth = 0 + k = m.end() - 1 # position of the opening '{' just matched + while True: + if tex[k] == "{": + depth += 1 + elif tex[k] == "}": + depth -= 1 + if depth == 0: + k += 1 + break + k += 1 + i = k + return "".join(out), names, local_form def math_spans(text: str) -> list[tuple[int, str, str]]: @@ -136,44 +188,53 @@ def main() -> int: text = note.read_text() spans = math_spans(text) - # Macros the note defines for itself, split by whether they actually carry. - globals_: set[str] = set() - locals_: dict[str, int] = {} - for lineno, _kind, tex in spans: - for m in GLOBAL_DEF_RE.finditer(tex): - globals_.add(m.group(1)) - for m in LOCAL_DEF_RE.finditer(tex): - locals_.setdefault(m.group(1), lineno) - findings: list[str] = [] - - for name, lineno in sorted({**locals_, **{g: 0 for g in globals_}}.items()): - findings.append( - f"{note}:{lineno or '?'}: `{name}` is defined inside the note. " - f"No definition form carries: measured through @vscode/markdown-it-katex, " - f"neither \\newcommand nor \\gdef nor \\global\\def survives to the next " - f"math span, because the plugin renders each span with fresh options" - ) - + local_form_lines: dict[str, int] = {} + empty_def_only_lines: list[int] = [] undefined: dict[str, list[int]] = {} + self_contained = 0 + for lineno, _kind, tex in spans: - body = GLOBAL_DEF_RE.sub("", LOCAL_DEF_RE.sub("", tex)) - for m in COMMAND_RE.finditer(body): + remaining, names, local_form = strip_defs(tex) + if names: + self_contained += 1 + if local_form: + for n in names: + local_form_lines.setdefault(n, lineno) + # A span whose ENTIRE content was definitions, with nothing left to use + # them, is the old preamble anti-pattern reborn one span at a time. + if names and not remaining.strip(): + empty_def_only_lines.append(lineno) + for m in COMMAND_RE.finditer(remaining): name = m.group(0) - if name in supported: + if name in supported or name in names: continue undefined.setdefault(name, []).append(lineno) + for name, lineno in sorted(local_form_lines.items()): + findings.append( + f"{note}:{lineno}: `{name}` is defined with \\newcommand/\\renewcommand/" + f"\\providecommand, which never carries even within its own span — use " + f"\\gdef instead (it works when defined and used inside the same $...$)" + ) + for lineno in empty_def_only_lines: + findings.append( + f"{note}:{lineno}: this span is only macro definitions, with nothing in " + f"the same span to use them — that is the old document-level-preamble " + f"pattern, one span at a time, and it does not carry to the NEXT span " + f"either. Move the definition into the span that actually uses the macro" + ) + for name, lines in sorted(undefined.items()): where = ", ".join(str(n) for n in lines[:6]) more = f" (+{len(lines) - 6} more)" if len(lines) > 6 else "" findings.append( - f"{note}: `{name}` is not a KaTeX command and is not \\gdef'd in this note " - f"— used at line(s) {where}{more}" + f"{note}: `{name}` is not a KaTeX command and has no local \\gdef in the " + f"same span — used at line(s) {where}{more}" ) - print(f"{len(spans)} math spans; {len(globals_) + len(locals_)} in-note macro " - f"definitions (none of which carry); {len(undefined)} undefined commands") + print(f"{len(spans)} math spans; {self_contained} carry a local macro " + f"definition; {len(undefined)} undefined commands") report, rc = real_render(note) print(report) From eb9256310572dcbc33e8c8a74c37d4e24cc32ea9 Mon Sep 17 00:00:00 2001 From: suzuki <casek2703@gmail.com> Date: Mon, 17 Aug 2026 03:56:59 +0000 Subject: [PATCH 113/113] docs(math): re-render quotes' own notation with self-contained \gdef Applies the new per-span local-macro convention (1e4e1e7) to the three notes that carried a source's own macros in verbatim quotes. - causal-index-set.md, split-inclusion.md: their document-level macro preambles never worked in the first place (measured: no definition form crosses a math-span boundary in the renderer VS Code's preview uses), so every quote using them was already broken -- this is what the user reported. Removed the preambles; every affected quote's own macro(s) are now defined locally, inside the same $...$ they're used in, so the quotes render exactly as their sources wrote them instead of throwing ParseError or falling back to inert code. Byte content of every quote is unchanged; verified programmatically by stripping the injected \gdef prefixes and diffing against the pre-edit text. - umegaki-relative-entropy.md: replaces the whole-quote code-fencing from the note's initial extraction with the same per-span technique, for the same reason -- fencing hid the notation instead of rendering it, and visually broke the quotes out of the surrounding prose. Two quotes with no macros at all (HIA18's plain-KaTeX F-1.1 definition, HS17's plain-KaTeX drel1 equation) are upgraded from unrendered plain text to live $$ blocks. VED02's \mbox and KW20's \Tr/\supp are reconstructed (not copied, since KW20's Book_KW class is unrecoverable; \mbox is a LaTeX primitive KaTeX doesn't implement), labelled as such. All five notes under docs/math/ pass `check_render.py` clean, both with and without the node/katex pipeline. --- docs/math/causal-index-set.md | 173 ++++++++++++-------------- docs/math/split-inclusion.md | 47 +++---- docs/math/umegaki-relative-entropy.md | 72 ++++++----- 3 files changed, 146 insertions(+), 146 deletions(-) diff --git a/docs/math/causal-index-set.md b/docs/math/causal-index-set.md index 0b1db69..89ff782 100644 --- a/docs/math/causal-index-set.md +++ b/docs/math/causal-index-set.md @@ -11,61 +11,54 @@ revisions: --- <!-- -Macros used by the verbatim quotes below, transcribed from each source's own -preamble so that the quotes render as their authors wrote them: - \cA \cB \cH \cK \cL \cO \cP \cS \cW \cX GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 - \p GLRV99, main.tex:127 - \2 \7 \al \alg \norm \ol \wt \Om HM06, references/arxiv-math-ph-0602036/raw/reconstruction.tex:136,138,143,26,27,141,135,149 - \A \C \K \O \R BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 - \calA \calK \frakM \gb \obj BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) - \lok \Seins KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144,135 - \mc NAA13, references/arxiv-1311.2717/raw/qlattice.tex:73 -NAME COLLISION, recorded rather than silently resolved: GLRV99 defines -\p as \pi (main.tex:127) and HM06 defines \p as \psi -(reconstruction.tex:148). The table below carries GLRV99's, because the only -quote in this note using \p is GLRV99's (R2). No HM06 quote here uses it. -\alg is defined identically by HM06 and NAA13, so one definition serves both. -\2 and \7 are single-digit control sequences; they are TeX-legal via \def and -are transcribed as their sources write them. A renderer that rejects them -raises a visible parse error, which is the intended failure mode — editing the -quote is not, because those bytes are what the quote check verifies. +No document-level macro preamble: measured through +@vscode/markdown-it-katex (the plugin VS Code's own Markdown preview uses), +no macro definition form -- \newcommand, \gdef, \global\def -- survives +from one math span to the next, so a preamble here would leave every quote +using it broken (see check_render.py / render_check.js). Instead, every +verbatim-quote math span that needs a source's own macro carries a local, +self-contained \gdef of exactly that macro, e.g. +`$\gdef\lok#1{{\mathcal #1}}\lok{B}$` -- defined and used inside the same +$...$ pair, so it renders correctly without any state surviving to the next +span. The \gdef prefix is presentation, not content: strip it before +comparing a quote's tex against source.flat.txt for the quote check, and +audit it against the source's own definition below. + +Source macro catalogue (name[arity] = body, source, file:line): + \2[1] = {{\mathcal #1}} (provenance: see prior revision / sources.md) + \7[1] = {{\mathbb #1}} (provenance: see prior revision / sources.md) + \A = {{\cal A}} BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 + \C = {{\cal C}} BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 + \K = {{\cal K}} BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 + \O = {{\cal O}} BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 + \Om = {\Omega} (provenance: see prior revision / sources.md) + \R = {{\cal R}} BGL93, references/arxiv-funct-an-9302008/raw/main.tex:58,64,72,77,81 + \Seins = {\mathsf{S}^1} KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144,135 + \al[1] = {{\mathfrak #1}} (provenance: see prior revision / sources.md) + \alg[1] = {\mathfrak{#1}} (provenance: see prior revision / sources.md) + \cA = {{\cal A}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cB = {{\cal B}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cH = {{\cal H}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cK = {{\cal K}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cL = {{\cal L}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cO = {{\cal O}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cP = {{\cal P}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cS = {{\cal S}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cW = {{\cal W}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \cX = {{\cal X}} GLRV99, references/arxiv-math-ph-9906019/raw/main.tex:69,70,76,79,80,83,85,88,92,93 + \calA = {{\mathcal A}} BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) + \calK = {{\mathcal K}} BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) + \frakM = {{\mathfrak{Man}}} BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) + \gb = {\boldsymbol{g}} BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) + \lok[1] = {{\mathcal #1}} KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144,135 + \mc[1] = {\mathcal{#1}} NAA13, references/arxiv-1311.2717/raw/qlattice.tex:73 + \norm[1] = {\| #1\|} (provenance: see prior revision / sources.md) + \obj = {\mbox{\rm Obj}} BFV01, references/arxiv-math-ph-0112041/raw/main.tex:7,26,31,89,82 (FIRST document body) + \ol[1] = {{\overline #1}} (provenance: see prior revision / sources.md) + \p = {\pi} GLRV99, main.tex:127 + \wt[1] = {{\tilde #1}} (provenance: see prior revision / sources.md) --> -$$ -\def\cA{{\cal A}} -\def\cB{{\cal B}} -\def\cH{{\cal H}} -\def\cK{{\cal K}} -\def\cL{{\cal L}} -\def\cO{{\cal O}} -\def\cP{{\cal P}} -\def\cS{{\cal S}} -\def\cW{{\cal W}} -\def\cX{{\cal X}} -\def\p{\pi} -\def\2#1{{\mathcal #1}} -\def\7#1{{\mathbb #1}} -\def\al#1{{\mathfrak #1}} -\newcommand{\alg}[1]{\mathfrak{#1}} -\newcommand{\norm}[1]{\| #1\|} -\def\ol#1{{\overline #1}} -\def\wt#1{{\tilde #1}} -\def\Om{\Omega} -\def\A{{\cal A}} -\def\C{{\cal C}} -\def\K{{\cal K}} -\def\O{{\cal O}} -\def\R{{\cal R}} -\newcommand{\calA}{{\mathcal A}} -\newcommand{\calK}{{\mathcal K}} -\newcommand{\frakM}{{\mathfrak{Man}}} -\newcommand{\gb}{\boldsymbol{g}} -\newcommand{\obj}{\mbox{\rm Obj}} -\newcommand{\lok}[1]{{\mathcal #1}} -\newcommand{\Seins}{\mathsf{S}^1} -\newcommand{\mc}[1]{\mathcal{#1}} -$$ - # Causal index set of a Haag–Kastler net ## What this object is for @@ -111,7 +104,7 @@ independence theorem applies to a given pair of regions. **(D1) [GLRV99] §3.1, `source.txt` 1214–1226** — tier (a) — the abstract form -> The causal structure enters in the form of the relation $\perp$ of causal disjointness, defined in Ch.\ 2, and here to be considered as a relation on the ordered set $\cal{K}$, satisfying \begin{description} \item{$a)$} $\cO_1\perp\cO_2\Rightarrow\cO_2\perp\cO_1$. \item{$b)$} $\cO_1\subset\cO_2$ and $\cO_2\perp\cO_3 \Rightarrow\cO_1\perp\cO_3$. \item{$c)$} Given $\cO_1\in\cK$, there exists an $\cO_2\in\cK$ such that $\cO_1\perp\cO_2$. \end{description} We write $\cO^\perp:=\{\cO_1\in\cK:\cO_1\perp\cO\}$. +> The causal structure enters in the form of the relation $\perp$ of causal disjointness, defined in Ch.\ 2, and here to be considered as a relation on the ordered set $\cal{K}$, satisfying \begin{description} \item{$a)$} $\gdef\cO{{\cal O}}\cO_1\perp\cO_2\Rightarrow\cO_2\perp\cO_1$. \item{$b)$} $\gdef\cO{{\cal O}}\cO_1\subset\cO_2$ and $\gdef\cO{{\cal O}}\cO_2\perp\cO_3 \Rightarrow\cO_1\perp\cO_3$. \item{$c)$} Given $\gdef\cO{{\cal O}}\gdef\cK{{\cal K}}\cO_1\in\cK$, there exists an $\gdef\cO{{\cal O}}\gdef\cK{{\cal K}}\cO_2\in\cK$ such that $\gdef\cO{{\cal O}}\cO_1\perp\cO_2$. \end{description} We write $\gdef\cO{{\cal O}}\gdef\cK{{\cal K}}\cO^\perp:=\{\cO_1\in\cK:\cO_1\perp\cO\}$. Restated at the head of the Appendix to Ch. 3 with the gloss that b) says `$\cal{O}^\perp$ is a sieve of $\cal{K}$`. Here `𝒪^⊥` is a **subset of 𝒦**, not @@ -125,16 +118,16 @@ fourth condition appears later in the same chapter and is recorded as (D5′). **(D2) [GLRV99] §2.1 and §3.1** — tier (a) — regular diamonds -> A set of the form $\cO = {\rm int}\,D(G)$ is a regular diamond provided $\cO^\perp$ is non-void and +> A set of the form $\gdef\cO{{\cal O}}\cO = {\rm int}\,D(G)$ is a regular diamond provided $\gdef\cO{{\cal O}}\cO^\perp$ is non-void and with (i) `Ḡ` compact and contractible to a point in `G`, `G` open in an acausal Cauchy surface `C`; (ii) `∂G` a locally flat, two-sided topological submanifold of `C`, smooth near points of each connected component. Then -`We let $\cK$ denote the set of regular diamonds in $M$, ordered under inclusion.` +`We let $\gdef\cK{{\cal K}}\cK$ denote the set of regular diamonds in $M$, ordered under inclusion.` Non-void causal complement is **in the definition**, which is how axiom c) is secured. GLRV99 declines double cones and says why: -> For these reasons, we have chosen to use the collection $\cK$ of regular diamonds rather than the collection of double cones whose causal complement has non-empty interior as an index set in a globally hyperbolic spacetime. +> For these reasons, we have chosen to use the collection $\gdef\cK{{\cal K}}\cK$ of regular diamonds rather than the collection of double cones whose causal complement has non-empty interior as an index set in a globally hyperbolic spacetime. `differs from (D6)/(D10) by:` a Cauchy-surface base with compactness, contractibility and a two-sidedness condition, plus `𝒪^⊥ ≠ ∅`. Note the source @@ -164,7 +157,7 @@ Complement of the **closure** of the causal hull, hence automatically open. **(D5) [GLRV99] Appendix to Ch. 3** — tier (a) — the two derived relations -> There are two derived binary relations $\tilde\perp$ and $\hat\perp$ defined by supplementing $\cO_1\perp\cO_2$ by requiring that there exists an $\cO_3\in\cal{K}$ such that $$\cO_1\perp\cO_3,\,\,\cO_2\perp\cO_3$$ or such that $$\cO_1,\,\,\cO_2\subset\cO_3,$$ respectively. These relations automatically satisfy a) and b) but c) remains to be checked and will not prove to be a problem in our applications to curved spacetime. The operation of passing from $\perp$ to $\tilde\perp$ or $\hat\perp$ is idempotent and if $\cal{K}$ is directed, all three relations coincide. +> There are two derived binary relations $\tilde\perp$ and $\hat\perp$ defined by supplementing $\gdef\cO{{\cal O}}\cO_1\perp\cO_2$ by requiring that there exists an $\gdef\cO{{\cal O}}\cO_3\in\cal{K}$ such that $$\gdef\cO{{\cal O}}\cO_1\perp\cO_3,\,\,\cO_2\perp\cO_3$$ or such that $$\gdef\cO{{\cal O}}\cO_1,\,\,\cO_2\subset\cO_3,$$ respectively. These relations automatically satisfy a) and b) but c) remains to be checked and will not prove to be a problem in our applications to curved spacetime. The operation of passing from $\perp$ to $\tilde\perp$ or $\hat\perp$ is idempotent and if $\cal{K}$ is directed, all three relations coincide. So `O₁ ⊥̃ O₂` demands a common ⊥-partner and `O₁ ⊥̂ O₂` a common upper bound. Both are **purely order/⊥-theoretic**: neither mentions closures or distance. @@ -173,7 +166,7 @@ The whole ⊥/⊥̃/⊥̂ distinction is the price of dropping directedness — **(D5′) [GLRV99] Ch. 3, before Theorem 3.13, `source.txt` 1878–1882** — tier (a) — the corpus's only collar-shaped condition on 𝒦 itself -> In fact, the following result is valid for a directed set $\cal{K}$ with a binary relation $\perp$ such that given $\cal{O}\in\cal{K}$, there exists $\cO_1,\cO_2\in\cal{K}$ with $\cO,\cO_1\subset\cO_2$ and $\cO\perp\cO_1$. This condition is related to our use of the Borchers Property. +> In fact, the following result is valid for a directed set $\cal{K}$ with a binary relation $\perp$ such that given $\cal{O}\in\cal{K}$, there exists $\gdef\cO{{\cal O}}\cO_1,\cO_2\in\cal{K}$ with $\gdef\cO{{\cal O}}\cO,\cO_1\subset\cO_2$ and $\gdef\cO{{\cal O}}\cO\perp\cO_1$. This condition is related to our use of the Borchers Property. For every `O` there are `O₁, O₂` with `O ⊆ O₂`, `O₁ ⊆ O₂` and `O ⊥ O₁` — in the vocabulary of (D5), **every `O` has an `O₁` with `O ⊥̂ O₁`**, i.e. axiom c) @@ -186,7 +179,7 @@ kind or is topological ((D8), (D9)). **No source compares the two shapes.** **(D6) [HM06] §2.1** — tier (a) — open double cones in Minkowski -> An open \emph{double cone} in Minkowski spacetime is the intersection of the causal future of a point $x$ with the causal past of a point $y$ to the future of $x$. Let $\2K$ be the set of open double cones in Minkowski spacetime +> An open \emph{double cone} in Minkowski spacetime is the intersection of the causal future of a point $x$ with the causal past of a point $y$ to the future of $x$. Let $\gdef\2#1{{\mathcal #1}}\2K$ be the set of open double cones in Minkowski spacetime No poset axioms are stated; the order is inclusion, used silently. **HM06 never defines "spacelike separated"** — it is an undefined primitive from the @@ -204,7 +197,7 @@ A translation-buffer condition; **requires a translation group**. **(D8) [HM06] §3.3** — tier (a) — strongly spacelike separated -> Two double cones $O_1$ and $O_2$ are said to be \emph{strongly spacelike separated} just in case there are double cones $\wt O_i$ such that $\ol O_i\subseteq \wt O_i$, and $\wt O_1,\wt O_2$ are spacelike. +> Two double cones $O_1$ and $O_2$ are said to be \emph{strongly spacelike separated} just in case there are double cones $\gdef\wt#1{{\tilde #1}}\wt O_i$ such that $\gdef\ol#1{{\overline #1}}\gdef\wt#1{{\tilde #1}}\ol O_i\subseteq \wt O_i$, and $\gdef\wt#1{{\tilde #1}}\wt O_1,\wt O_2$ are spacelike. with the ordering claim @@ -220,14 +213,14 @@ relation. **(D9) [HM06] §2.4** — tier (a) — the separation carrying the split property -> the \emph{funnel property} if for any double cones $O_1,O_2$ with $\ol O_1$ contained in $O_2$, the pair $(\al R(O_1),\al R(O_2))$ is a split inclusion. +> the \emph{funnel property} if for any double cones $O_1,O_2$ with $\gdef\ol#1{{\overline #1}}\ol O_1$ contained in $O_2$, the pair $\gdef\al#1{{\mathfrak #1}}(\al R(O_1),\al R(O_2))$ is a split inclusion. The relation is `closure(O₁) ⊆ O₂`. **HM06 gives it no name and no symbol.** Purely topological: no causal structure, no metric, no positive distance. **(D10) [NAA13] §1.2** — tier (a) — double cones, recorded as causally complete -> As the basic regions we consider \emph{double cones}\index{double cone} $\mc{O}$, defined as the intersection of (the interior of) a forward and backward light-cone. Note that a double cone is causally complete: $\mc{O} = \mc{O}''$, where a prime $'$ denotes taking the causal complement. +> As the basic regions we consider \emph{double cones}\index{double cone} $\gdef\mc#1{\mathcal{#1}}\mc{O}$, defined as the intersection of (the interior of) a forward and backward light-cone. Note that a double cone is causally complete: $\gdef\mc#1{\mathcal{#1}}\mc{O} = \mc{O}''$, where a prime $'$ denotes taking the causal complement. `differs from (D6) by:` the same family, presented as an intersection of cones rather than through two points, **plus the causal-completeness observation HM06 @@ -236,9 +229,9 @@ as an observation, not as a membership condition — contrast (D19). **(D11) [NAA13] §2.4** — tier (a) — the lattice index set, with `∅` a member -> Let $\Gamma$ be as above. We will write $\mc{P}(\Gamma)$ for the set of all subsets of $\Gamma$. Similarly, $\mc{P}_f(\Gamma)$ is the subset of all \emph{finite} subsets of $\Gamma$. +> Let $\Gamma$ be as above. We will write $\gdef\mc#1{\mathcal{#1}}\mc{P}(\Gamma)$ for the set of all subsets of $\Gamma$. Similarly, $\gdef\mc#1{\mathcal{#1}}\mc{P}_f(\Gamma)$ is the subset of all \emph{finite} subsets of $\Gamma$. -> For convenience we will set $\alg{A}(\emptyset) = \mathbb{C} I$, since multiples of the identity are contained in $\alg{A}(\Lambda)$ for all $\Lambda \in \mc{P}_f(\Gamma)$. +> For convenience we will set $\gdef\alg#1{\mathfrak{#1}}\alg{A}(\emptyset) = \mathbb{C} I$, since multiples of the identity are contained in $\gdef\alg#1{\mathfrak{#1}}\alg{A}(\Lambda)$ for all $\gdef\mc#1{\mathcal{#1}}\Lambda \in \mc{P}_f(\Gamma)$. Finite subsets of a countable Γ, ordered by inclusion, ⊥ = plain disjointness. **Directed**, with a **least element ∅**, a distributive lattice, and its @@ -248,17 +241,17 @@ causal disjointness by "its Euclidean counterpart, disjointness". Because **(D12) [BGL93] §1, Prop. 1.3** — tier (a) — two index sets in one paper -> In the following we shall consider the family $\tilde\K$ of the subregions of $\tilde M$ which are images of double cones in $M$ under conformal transformations in $\tilde\C$. +> In the following we shall consider the family $\gdef\K{{\cal K}}\tilde\K$ of the subregions of $\tilde M$ which are images of double cones in $M$ under conformal transformations in $\gdef\C{{\cal C}}\tilde\C$. -> All elements of $\tilde\K$ are open contractible precompact submanifolds of $\tilde M$. They are a fundamental set of neighborhoods for $\tilde M$. +> All elements of $\gdef\K{{\cal K}}\tilde\K$ are open contractible precompact submanifolds of $\tilde M$. They are a fundamental set of neighborhoods for $\tilde M$. -> The space-like complement $\O'$ of a region $\O\in\tilde\K$ belong to $\tilde\K$. +> The space-like complement $\gdef\O{{\cal O}}\O'$ of a region $\gdef\O{{\cal O}}\gdef\K{{\cal K}}\O\in\tilde\K$ belong to $\gdef\K{{\cal K}}\tilde\K$. -> The family $\tilde\K$ is not a net, in fact the union of a region and of its causal complement is not contained in any region of $\tilde\K$. +> The family $\gdef\K{{\cal K}}\tilde\K$ is not a net, in fact the union of a region and of its causal complement is not contained in any region of $\gdef\K{{\cal K}}\tilde\K$. and, for the same paper's other index set, -> Since the family $\K$ is a direct set, the map $\O\to\A(\O)$ is indeed a net and the quasilocal $C^*$-algebra $\A_0$ is defined as the direct limit of the local algebras. +> Since the family $\gdef\K{{\cal K}}\K$ is a direct set, the map $\gdef\O{{\cal O}}\gdef\A{{\cal A}}\O\to\A(\O)$ is indeed a net and the quasilocal $C^*$-algebra $\gdef\A{{\cal A}}\A_0$ is defined as the direct limit of the local algebras. **`𝒦̃` is the corpus's only index set literally closed under the causal complement**, so on it `𝒪 ↦ 𝒪′` is an *operation*; on every other index set it @@ -272,7 +265,7 @@ and neither remarks on it. **(D14) [KOE03] §2** — tier (a) — proper intervals of the circle -> The localisation regions are open, non-dense intervals contained in the circle, called the {\em proper intervals}. A connected, open subset $I$ of $\Seins$ is a proper interval, denoted by $I\Subset\Seins$, if its {\em causal complement} $I':= \Seins\setminus\overline{I}$ is not the empty set. +> The localisation regions are open, non-dense intervals contained in the circle, called the {\em proper intervals}. A connected, open subset $I$ of $\gdef\Seins{\mathsf{S}^1}\Seins$ is a proper interval, denoted by $\gdef\Seins{\mathsf{S}^1}I\Subset\Seins$, if its {\em causal complement} $\gdef\Seins{\mathsf{S}^1}I':= \Seins\setminus\overline{I}$ is not the empty set. Membership requires connected, open, non-dense, and `I′ ≠ ∅` — as in (D2) and unlike (D6)/(D10). Locality is stated as `{\em Locality\label{ax:loc}:} For $I_1\subset I_2'$,` @@ -280,24 +273,24 @@ so **the primitive is the operation `I ↦ I′`** and ⊥ is derived, the rever (D1). Interchangeable only because 𝒦 is closed under `′` here. The index set is not directed and the source draws the terminological consequence: -> The set of proper intervals in $\Seins$ is not directed with respect to the partial order defined by inclusion and thus is not a net in the proper sense of the word. +> The set of proper intervals in $\gdef\Seins{\mathsf{S}^1}\Seins$ is not directed with respect to the partial order defined by inclusion and thus is not a net in the proper sense of the word. **(D15) [KOE03] §1.3** — tier (a) — the chiral split separation -> a chiral net $\lok{B}$ has the split property, if for any pair $I_{1,2}$ of proper intervals satisfying $\overline{I_1}\subset I_2$ there is a type $I$ factor $\lok{M}$ interpolating between $\lok{B}(I_1)$ and $\lok{B}(I_2)$ +> a chiral net $\gdef\lok#1{{\mathcal #1}}\lok{B}$ has the split property, if for any pair $I_{1,2}$ of proper intervals satisfying $\overline{I_1}\subset I_2$ there is a type $I$ factor $\gdef\lok#1{{\mathcal #1}}\lok{M}$ interpolating between $\gdef\lok#1{{\mathcal #1}}\lok{B}(I_1)$ and $\gdef\lok#1{{\mathcal #1}}\lok{B}(I_2)$ `differs from (D9) by:` **nothing mathematical** — two traditions, one relation, and neither names it or gives it a symbol. KOE03 also takes the one step in the corpus connecting the topological and order-theoretic collar families: -> we conclude that there is $I_3\Subset\Seins$ satisfying $I_1\cup I_2' \subset I_3$ +> we conclude that there is $\gdef\Seins{\mathsf{S}^1}I_3\Subset\Seins$ satisfying $I_1\cup I_2' \subset I_3$ i.e. `Ī₁ ⊂ I₂` yields a common upper bound for `I₁` and `I₂′`, which with `I₁ ∩ I₂′ = ∅` says exactly `I₁ ⊥̂ I₂′`. **(D16) [BFV01] §2.4, first document body** — tier (a) literal / (b) as intended -> We denote by $\calK(M,\gb)$ the set of all subsets in $M$ which are relatively compact and contain with each pair of points $x$ and $y$ also all $\gb$-causal curves in $M$ connecting $x$ and $y$ (cf.\ condition $(ii)$ in the definition of $\frakM$). +> We denote by $\gdef\calK{{\mathcal K}}\gdef\gb{\boldsymbol{g}}\calK(M,\gb)$ the set of all subsets in $M$ which are relatively compact and contain with each pair of points $x$ and $y$ also all $\gdef\gb{\boldsymbol{g}}\gb$-causal curves in $M$ connecting $x$ and $y$ (cf.\ condition $(ii)$ in the definition of $\gdef\frakM{{\mathfrak{Man}}}\frakM$). Two conditions only: **relatively compact** and **causally convex**. Read literally, `∅`, singletons and spacelike point-pairs are members. The next @@ -335,7 +328,7 @@ Same buffer idea, two different relations. **(D19) [GLRV99] Appendix Ch. 3 and §4.2** — tier (a) — an index set that depends on the net -> We choose $\cL$ to be the set of non-empty causally closed subsets $\cS$ of $M$ with non-empty causal complements such that for the given net $\cA$ $\tilde\perp$--duality holds either for $\cS$ or for $\cS^\perp$. +> We choose $\gdef\cL{{\cal L}}\cL$ to be the set of non-empty causally closed subsets $\gdef\cS{{\cal S}}\cS$ of $M$ with non-empty causal complements such that for the given net $\gdef\cA{{\cal A}}\cA$ $\tilde\perp$--duality holds either for $\gdef\cS{{\cal S}}\cS$ or for $\gdef\cS{{\cal S}}\cS^\perp$. > This choice has the disadvantage of depending on the theory under consideration but it allows a smooth treatment of endomorphisms. @@ -345,7 +338,7 @@ records it as an observation. **(D20) [GLRV99] Ch. 5** — tier (a) — diamonds together with wedges -> Now we consider a net $\cO \mapsto\cA(\cO)$ of von~Neumann algebras indexed by elements $\cO \in \cK \cup \cW$ where $\cK$ is the set of regular diamonds and $\cW$ is a set of wedges with the properties discussed in the previous section +> Now we consider a net $\gdef\cO{{\cal O}}\gdef\cA{{\cal A}}\cO \mapsto\cA(\cO)$ of von~Neumann algebras indexed by elements $\gdef\cO{{\cal O}}\gdef\cK{{\cal K}}\gdef\cW{{\cal W}}\cO \in \cK \cup \cW$ where $\gdef\cK{{\cal K}}\cK$ is the set of regular diamonds and $\gdef\cW{{\cal W}}\cW$ is a set of wedges with the properties discussed in the previous section The corpus's only index set containing **unbounded** elements as first-class members, and the only one that is not a single geometric family. A form that @@ -462,7 +455,7 @@ empty causal complement. So the two forms are `ordered-under-(T)`, neither - Source: [GLRV99] §1.1 · tier (a) · **asserted** - Verbatim: - > If $\cK$ is directed, then one can form the ``quasilocal algebra'', i.e.\ the smallest $C^*$-algebra containing all the local algebras $\cA(\cO)$. It is the norm closure of the union of the local algebras, $\overline{\bigcup_{\cO}\cA(\cO)}$. In the generic case where $\cK$ is not directed, this possibility is denied to us. + > If $\gdef\cK{{\cal K}}\cK$ is directed, then one can form the ``quasilocal algebra'', i.e.\ the smallest $C^*$-algebra containing all the local algebras $\gdef\cA{{\cal A}}\gdef\cO{{\cal O}}\cA(\cO)$. It is the norm closure of the union of the local algebras, $\gdef\cO{{\cal O}}\gdef\cA{{\cal A}}\overline{\bigcup_{\cO}\cA(\cO)}$. In the generic case where $\gdef\cK{{\cal K}}\cK$ is not directed, this possibility is denied to us. - Depends on: (A1); [ext: the C\*-inductive-limit construction — the norm closure of an upward-directed union of C\*-subalgebras of a common ambient algebra is a C\*-algebra and is the smallest one containing them all. tier (d), not retrieved] - This is why GLRV99's superselection apparatus is cohomological rather than algebraic. @@ -474,7 +467,7 @@ For a representation family, the dual net is `𝒜_π^d(𝒪) := ⋂_{𝒪₁ - Source: [GLRV99] §1.1 · tier (a) · **asserted** - Verbatim: - > This property is stronger than locality but not as strong as Haag duality which demands that $\p_{\cO}(\cA(\cO))'' = \cA_{\p}^d(\cO)$ for all $\cO \in \cK$. + > This property is stronger than locality but not as strong as Haag duality which demands that $\gdef\p{\pi}\gdef\cO{{\cal O}}\gdef\cA{{\cal A}}\p_{\cO}(\cA(\cO))'' = \cA_{\p}^d(\cO)$ for all $\gdef\cO{{\cal O}}\gdef\cK{{\cal K}}\cO \in \cK$. - Depends on: (R7); the availability of `𝒪^⊥` as an index set, i.e. (D1) ### (R3) [GLRV99] Lemma 2.1 — the regular diamonds absorb any point of the causal complement @@ -500,7 +493,7 @@ satisfies `𝒪 ∪ {p} ⊂ 𝒪₁`. - Source: [GLRV99] Lemma 3A.1, Cor. 3A.2 · tier (a) · **proved in source** (3A.1); **asserted** (3A.2) - Verbatim: - > Let $\cal{P}$ be a base for the topology of a space $M$ and ordered under inclusion and suppose the elements of $\cal{P}$ are open, (non-empty) and path--connected. Then an open subset $X$ of $M$ is path--connected if and only if $\cP_X$:=$\{\cO\in\cP:\cO\subset X\}$ is connected. + > Let $\cal{P}$ be a base for the topology of a space $M$ and ordered under inclusion and suppose the elements of $\cal{P}$ are open, (non-empty) and path--connected. Then an open subset $X$ of $M$ is path--connected if and only if $\gdef\cP{{\cal P}}\cP_X$:=$\gdef\cO{{\cal O}}\gdef\cP{{\cal P}}\{\cO\in\cP:\cO\subset X\}$ is connected. - Depends on: (A6); (A7) - The bridge lemma of the whole apparatus: every connectedness claim GLRV99 makes about the *poset* is obtained by applying this to a topological one. @@ -508,7 +501,7 @@ satisfies `𝒪 ∪ {p} ⊂ 𝒪₁`. - Source: [GLRV99] §3.1 · tier (a) · **proved in source** as a two-step derivation - Verbatim: - > By virtue of Lemma 3A.1, we know that $\cal{K}$ is connected and, see Lemma 2.2, that $\cO^\perp$ is connected except when $M$ is two dimensional with a non--compact Cauchy surface. + > By virtue of Lemma 3A.1, we know that $\cal{K}$ is connected and, see Lemma 2.2, that $\gdef\cO{{\cal O}}\cO^\perp$ is connected except when $M$ is two dimensional with a non--compact Cauchy surface. - Depends on: (R4); (R5); (A6); (A2a) ### (R7) The dual-net operation is an antitone Galois-type map @@ -518,7 +511,7 @@ implies `𝒜^dd` local. - Source: [GLRV99] §3.2 · tier (a) · **proved in source** - Verbatim: - > is the largest net local relative to $\cA^d$, $\cA\subset\cA^{dd}$. However $\cA\subset\cB$ implies $\cB^d\subset\cA^d$, so that $\cA^d=\cA^{ddd}$. A net $\cA$ is said to be {\it local} if $\cA\subset\cA^d$ and then $\cA^{dd}\subset\cA^d=\cA^{ddd}$ so that $\cA^{dd}$ is local, too. + > is the largest net local relative to $\gdef\cA{{\cal A}}\cA^d$, $\gdef\cA{{\cal A}}\cA\subset\cA^{dd}$. However $\gdef\cA{{\cal A}}\gdef\cB{{\cal B}}\cA\subset\cB$ implies $\gdef\cB{{\cal B}}\gdef\cA{{\cal A}}\cB^d\subset\cA^d$, so that $\gdef\cA{{\cal A}}\cA^d=\cA^{ddd}$. A net $\gdef\cA{{\cal A}}\cA$ is said to be {\it local} if $\gdef\cA{{\cal A}}\cA\subset\cA^d$ and then $\gdef\cA{{\cal A}}\cA^{dd}\subset\cA^d=\cA^{ddd}$ so that $\gdef\cA{{\cal A}}\cA^{dd}$ is local, too. - Depends on: (D1) a), b), c) — GLRV99 notes relative locality satisfies their analogues - Proof route: (1) `𝒜^d` is the largest net relatively local to `𝒜` [the formula]; (2) `𝒜 ⊂ 𝒜^dd` [step 1]; (3) `d` is order reversing, so `𝒜^d = 𝒜^ddd` [steps 1–2]; (4) locality propagates [step 3]. - The algebra-side shadow of the ⊥-Galois connection on 𝒦; the index-set version is (R9). @@ -527,7 +520,7 @@ implies `𝒜^dd` local. - Source: [GLRV99] Thm 3A.7 · tier (a) · **proved in source** - Verbatim: - > If each $\cal{O}^\perp$ is connected, every object $\pi$ of {\rm Rep}$^\perp\cA$ admits a unique extension to an object of {\rm Rep}$^\perp\cA^{dd}$. Furthermore there is a canonical isomorphism of $W^*$--categories {\rm Rep}$^\perp\cA$ and {\rm Rep}$^\perp\cA^{dd}$. + > If each $\cal{O}^\perp$ is connected, every object $\pi$ of {\rm Rep}$\gdef\cA{{\cal A}}^\perp\cA$ admits a unique extension to an object of {\rm Rep}$\gdef\cA{{\cal A}}^\perp\cA^{dd}$. Furthermore there is a canonical isomorphism of $W^*$--categories {\rm Rep}$\gdef\cA{{\cal A}}^\perp\cA$ and {\rm Rep}$\gdef\cA{{\cal A}}^\perp\cA^{dd}$. - Depends on: (A3); (R7); [GLRV99] Lemma 3A.5; [GLRV99] Thm 3A.6 - The printed proof cites "Lemma 3.A.4" where Lemma 3A.5 is needed — see `## Not investigated`. @@ -591,7 +584,7 @@ poset still has two components. - Source: [GLRV99] §3.1 · tier (a) · **asserted** - Verbatim: - > may not be directed although it will be in cases of interest. However, when $M$ is globally hyperbolic with a compact Cauchy surface, $\cK$ will never be directed and we shall meet problems akin to those on the circle. + > may not be directed although it will be in cases of interest. However, when $M$ is globally hyperbolic with a compact Cauchy surface, $\gdef\cK{{\cal K}}\cK$ will never be directed and we shall meet problems akin to those on the circle. - Depends on: (D2)'s `𝒪^⊥ ≠ ∅` clause — the unstated reason is that a diamond over the whole compact Cauchy surface would have empty causal complement - This makes (R1)'s negative half bite, and is why (R15)'s compact case is open. @@ -599,7 +592,7 @@ poset still has two components. - Source: [GLRV99] §5.2 · tier (a) · **proved in source** - Verbatim: - > Under the above assumptions, the net satisfies duality for the relation $\hat\perp$, namely $$ \cA(\cO)=\cap_{\cO_1\hat\perp\cO}\cA(\cO_1)' $$ + > Under the above assumptions, the net satisfies duality for the relation $\hat\perp$, namely $$\gdef\cA{{\cal A}}\gdef\cO{{\cal O}} \cA(\cO)=\cap_{\cO_1\hat\perp\cO}\cA(\cO_1)' $$ - Depends on: (R3); additivity of the net; (A17) - Proof route: (1) Lemma 2.1 gives, for each point of `𝒪₁`, regions witnessing `𝒪 ⊥̂ 𝒪_x` [(R3)]; (2) additivity and duality collapse the two intersections [additivity, (A17)]. - **The only place in the corpus where (R3) does real work in the main line**, and the justification for GLRV99's remark that the two notions of duality coincide for additive nets over regular diamonds. @@ -629,7 +622,7 @@ non-directedness can in many cases be circumvented. - Source: [HM06] §2.4 · tier (a) · **asserted** - Verbatim: - > Then if $O_1,O_2$ are double cones such that the closure $\ol{O}_1$ of $O_1$ is contained in $O_2$, then the pair $(\alg{R}(O_1),\alg{R}(O_2))$ is a standard inclusion of von Neumann algebras. + > Then if $O_1,O_2$ are double cones such that the closure $\gdef\ol#1{{\overline #1}}\ol{O}_1$ of $O_1$ is contained in $O_2$, then the pair $\gdef\alg#1{\mathfrak{#1}}(\alg{R}(O_1),\alg{R}(O_2))$ is a standard inclusion of von Neumann algebras. - Depends on: (A5); (D9) - **The clearest instance in the corpus of a theorem whose only geometric content is a relation on 𝒦.** The unstated intermediate step — that `Ō₁ ⊂ 𝒪₂` makes `𝒪₁′ ∩ 𝒪₂` contain a region — is itself a claim about 𝒦 that no source proves; it is exactly the collar clause, and the Ordering theorem above is its proof under (T). @@ -673,7 +666,7 @@ non-directedness can in many cases be circumvented. - Source: [HM06] §3.3 · tier (a) · **proved in source** - Depends on: `ℛ(W)` and `ℛ(W′)` being type III₁ factors; HM06's remark that a factor and its commutant have the same type -- HM06's own type III₁ proposition carries the escape clause `Then either $\al R=\7C I$ or $\al R$ is a type III$_1$ factor.`, so every argument of the shape "split for all pairs ⇒ type I ⇒ contradiction" silently assumes the local algebras are not the scalars. +- HM06's own type III₁ proposition carries the escape clause `Then either $\gdef\al#1{{\mathfrak #1}}\gdef\7#1{{\mathbb #1}}\al R=\7C I$ or $\gdef\al#1{{\mathfrak #1}}\al R$ is a type III$_1$ factor.`, so every argument of the shape "split for all pairs ⇒ type I ⇒ contradiction" silently assumes the local algebras are not the scalars. ### (R28) The funnel property upgrades to the split property for strictly spacelike separated pairs @@ -723,7 +716,7 @@ non-directedness can in many cases be circumvented. - Source: [BGL93] §3 assumption (b) · tier (a) · it is an **assumption**, not a result - Verbatim: - > \item{$(b)$} Distal split property holds, i.e there exist two regions $\O_1\subset \O'_2$ in $M$ such that $\R(\O_1)$ and $\R(\O_2)$ generates a $W^*$-tensor product. + > \item{$(b)$} Distal split property holds, i.e there exist two regions $\gdef\O{{\cal O}}\O_1\subset \O'_2$ in $M$ such that $\gdef\R{{\cal R}}\gdef\O{{\cal O}}\R(\O_1)$ and $\gdef\R{{\cal R}}\gdef\O{{\cal O}}\R(\O_2)$ generates a $W^*$-tensor product. - **It imposes no relation on 𝒦 at all** — one split pair anywhere suffices — and is therefore strictly weaker than the funnel property, not a metric strengthening of the separation relation. It upgrades to the universal form under a **transitively acting symmetry group and `d > 2`**. ### (R37) The distal split property forces uniqueness of the covariant representation @@ -944,14 +937,14 @@ translation. |---|---|---|---|---|---| | (X15) | the collar clause and the closure form `Ō₁ ⊆ O₂` as *the* separation relation for the split property | rejected (both, as the single adopted relation) | **(X1) separating object**, both directions — collar without closure: internally tangent double cones `O₂ = {|x₀|+\|x⃗\| < 1}`, `O₁ = {|x₀|+\|x⃗−c\| < 1/2}`, `c = (1/2,0,0)`, with collar `O₃ = {|x₀|+\|x⃗+c\| < 1/8}`, using the verified criterion that `D(B(a,r))` and `D(B(b,s))` are spacelike iff `\|a−b\| ≥ r+s`; closure without collar: `Λ₁ = Λ₂ = {0}` in `𝒫_f(ℤ)`, and (non-degenerately) `O = (−ε,ε)×Σ ⊂ O₂ = (−2ε,2ε)×Σ` over a compact Cauchy surface Σ. **(X5) conditional equivalence** — under (T) the closure form is strictly stronger; see the Ordering theorem | a/b | 2026-08-15 | | (X18) | the causal complement as an **operation into 𝒦**, `O₁ ⊥ O₂ ⟺ O₂ ≤ O₁^⊥` | rejected | **(X1) separating object** — a double cone in Minkowski: the double cones spacelike to it have no maximum (translate away, then dilate inside `O′`). `𝒦̃` and the proper intervals of `S¹` do support the operation | a | 2026-08-15 | -| (X18′) | the complement as a **sieve-valued** operation `O ↦ {O₁ : O₁ ⊥ O}` | equivalent | — ([GLRV99] writes exactly this: `We write $\cO^\perp:=\{\cO_1\in\cK:\cO_1\perp\cO\}$.`) | a | 2026-08-15 | +| (X18′) | the complement as a **sieve-valued** operation `O ↦ {O₁ : O₁ ⊥ O}` | equivalent | — ([GLRV99] writes exactly this: `We write $\gdef\cO{{\cal O}}\gdef\cK{{\cal K}}\cO^\perp:=\{\cO_1\in\cK:\cO_1\perp\cO\}$.`) | a | 2026-08-15 | | (X19) | causal completeness `O = O″` as an axiom | rejected | **(X1) separating object** — the 3-element antichain `{A,B,C}` with `⊥ = {(A,B),(B,A),(A,C),(C,A)}` satisfies a), b), c) while `B^⊥⊥ = {B,C} ⊋ ↓B`. Geometric realisation: a spacelike disc and its domain of dependence share a causal complement | — | 2026-08-15 | | (X24) | [BGL93]'s *distal split property* as a phrasing of the separation relation | rejected | **(X5) conditional equivalence** — as written it is an existential over one pair of regions and constrains 𝒦 not at all; it upgrades to the universal form only under a transitively acting symmetry group **and** `d > 2` | a | 2026-08-15 | | (X25) | c) with the quantifiers swapped | rejected | **(X2) degeneracy** — forces a self-orthogonal element; false on double cones, true on `𝒫_f(Γ)` via `∅` | — | 2026-08-15 | | (X26) | "∃ one region ⊥ to all *others*" | rejected | **(X1) separating object** — the 2-element antichain `{A,B}` with `A ⊥ B`: the `≠`-form holds, the `∀`-including-self form fails | — | 2026-08-15 | | (X27) | b) with the inclusion reversed (anti-heredity) | rejected | **(X1) separating object** — false in every geometric model. *The parenthetical claim that with a top element it collapses to everything-⊥-everything is itself refuted*: witness `{A, B ≤ T}` with `⊥ = {(A,B),(B,A)} ∪ {(T,X),(X,T)} ∪ {(T,T)}`, where `A ⊥̸ A` | — | 2026-08-15 | | (X28) | one collar for all nested pairs | rejected | **(X1) separating object** — double cones: the collar must lie inside arbitrarily small outer regions | — | 2026-08-15 | -| (X32) | dropping the collar clause, leaving `O₁ ≤ O₂` | rejected | **(X2) degeneracy** — the split property becomes `𝒜(O) ⊆ 𝒩 ⊆ 𝒜(O)`, forcing every local algebra type I, contradicting the type III₁ structure — with [HM06]'s escape clause `Then either $\al R=\7C I$ or $\al R$ is a type III$_1$ factor.` attached | a/c | 2026-08-15 | +| (X32) | dropping the collar clause, leaving `O₁ ≤ O₂` | rejected | **(X2) degeneracy** — the split property becomes `𝒜(O) ⊆ 𝒩 ⊆ 𝒜(O)`, forcing every local algebra type I, contradicting the type III₁ structure — with [HM06]'s escape clause `Then either $\gdef\al#1{{\mathfrak #1}}\gdef\7#1{{\mathbb #1}}\al R=\7C I$ or $\gdef\al#1{{\mathfrak #1}}\al R$ is a type III$_1$ factor.` attached | a/c | 2026-08-15 | | (X9) | *claim*: [BFV01]'s `𝒦(M,ḡ)` is not an instance of the adopted form, witnessed by `∅`, `{x}`, `{x,y}` and a time-slab | refuted as stated | read literally `∅ ∈ 𝒦(M,ḡ)`, and BFV01's ⊥ is vacuously true against `∅`, so **c) holds everywhere via `∅`** and three of the four witnesses show only that BFV01's regions need not be open or connected. What survives: under the reading forced by BFV01's own `obj(𝔐)` sentence, c) fails at a time-slab around a compact Cauchy surface — **one witness, conditional on a reading BFV01 never states** | a | 2026-08-15 | | (X7) | *claim*: the lattice index set is excluded by c) | refuted as stated — re-scoped | **[NAA13]'s own `𝒫_f(Γ)` contains `∅`** and fixes `𝒜(∅) = ℂI`, so c) holds even for finite Γ. The claim is about a variant with `∅` removed, not about the corpus's lattice index set | a | 2026-08-15 | | (X6) | *claim*: the adopted form excludes chains | refuted as applied | the derivation uses **irreflexivity**, which is independent of a), b), c) — witness (H1)'s bottom-element model. The form is not credited with it | — | 2026-08-15 | diff --git a/docs/math/split-inclusion.md b/docs/math/split-inclusion.md index 9c1da76..beb1cdb 100644 --- a/docs/math/split-inclusion.md +++ b/docs/math/split-inclusion.md @@ -13,25 +13,26 @@ revisions: --- <!-- -Macros used by the verbatim quotes below, transcribed from each source's own -preamble so that the quotes render as their authors wrote them: - \lok KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144 - \A HS17, references/arxiv-1702.04924/raw/main.tex:151 - \H HS17, main.tex:196 — \renewcommand, not \newcommand: \H is the - Hungarian-umlaut accent in KaTeX's own macro table, which is why the - source redefines it too - \bC HS17, main.tex:97 -The definitions are scoped to this file: the renderer resets its macro table -per document, so a later note may transcribe the same names differently. +No document-level macro preamble: measured through +@vscode/markdown-it-katex (the plugin VS Code's own Markdown preview uses), +no macro definition form -- \newcommand, \gdef, \global\def -- survives +from one math span to the next, so a preamble here would leave every quote +using it broken (see check_render.py / render_check.js). Instead, every +verbatim-quote math span that needs a source's own macro carries a local, +self-contained \gdef of exactly that macro, e.g. +`$\gdef\lok#1{{\mathcal #1}}\lok{B}$` -- defined and used inside the same +$...$ pair, so it renders correctly without any state surviving to the next +span. The \gdef prefix is presentation, not content: strip it before +comparing a quote's tex against source.flat.txt for the quote check, and +audit it against the source's own definition below. + +Source macro catalogue (name[arity] = body, source, file:line): + \A = {\mathfrak{A}} HS17, references/arxiv-1702.04924/raw/main.tex:151 + \H = {\mathcal{H}} HS17, main.tex:196 — \renewcommand, not \newcommand: \H is the Hungarian-umlaut accent in KaTeX's own macro table, which is why the source redefines it too + \bC = {{\mathbb C}} HS17, main.tex:97 + \lok[1] = {{\mathcal #1}} KOE03, references/arxiv-math-ph-0308031/raw/mathphkoediss.tex:144 --> -$$ -\newcommand{\lok}[1]{{\mathcal #1}} -\newcommand{\A}{\mathfrak{A}} -\renewcommand{\H}{\mathcal{H}} -\def\bC{{\mathbb C}} -$$ - # Split inclusion of von Neumann algebras ## What this object is for @@ -63,7 +64,7 @@ level and only then specialises to nets. **(D1) [KOE03] §2.2 ("Split property for chiral subnets"), eq. `eq:splitprop`, source.txt 1697–1707** — tier (a) — net-level, nested form -> a chiral net $\lok{B}$ has the split property, if for any pair $I_{1,2}$ of proper intervals satisfying $\overline{I_1}\subset I_2$ there is a type $I$ factor $\lok{M}$ interpolating between $\lok{B}(I_1)$ and $\lok{B}(I_2)$ +> a chiral net $\gdef\lok#1{{\mathcal #1}}\lok{B}$ has the split property, if for any pair $I_{1,2}$ of proper intervals satisfying $\overline{I_1}\subset I_2$ there is a type $I$ factor $\gdef\lok#1{{\mathcal #1}}\lok{M}$ interpolating between $\gdef\lok#1{{\mathcal #1}}\lok{B}(I_1)$ and $\gdef\lok#1{{\mathcal #1}}\lok{B}(I_2)$ with the display Λ: 𝔅(I₁) ⊂ 𝔐 ⊂ 𝔅(I₂), Ī₁ ⊂ I₂ ⋐ S¹. A net-level property, quantified over all pairs of proper intervals with closure containment, @@ -76,7 +77,7 @@ property." **(D2) [HS17] §2, displayed definition, source.txt 985–993** — tier (a) — statistical independence -> The algebras $\A_A$ and $\A_B$ are said to be statistically independent iff there is an isomorphism of the v. Neumann algebras $\A_A\vee\A_B \simeq \A_A\otimes\A_B$. +> The algebras $\gdef\A{\mathfrak{A}}\A_A$ and $\gdef\A{\mathfrak{A}}\A_B$ are said to be statistically independent iff there is an isomorphism of the v. Neumann algebras $\gdef\A{\mathfrak{A}}\A_A\vee\A_B \simeq \A_A\otimes\A_B$. For two commuting von Neumann algebras on a common ℋ, with ∨ and ⊗ defined at the definition site and the notion pinned as "$W^*$-independence in the product @@ -92,7 +93,7 @@ separating for 𝔄_A ∨ 𝔄_B (written inside the definitional paragraph as " is typically a vector…"), there is a unitary W: ℋ → ℋ⊗ℋ with WaW\* = π_A(a)⊗1, WbW\* = 1⊗π_B(b); setting 𝔑 = W\*(𝔅(ℋ_A)⊗1)W gives 𝔄_A ⊂ 𝔑 ⊂ 𝔄_B′, -> which is also called the ``split''. The split and the unitary $W$ are unique (for given $|\Psi \rangle \in\H$) if we require that +> which is also called the ``split''. The split and the unitary $W$ are unique (for given $\gdef\H{\mathcal{H}}|\Psi \rangle \in\H$) if we require that W\*(|Ψ⟩⊗|Ψ⟩) lies in the natural cone of |Ψ⟩ for 𝔄_A ⊗ 𝔄_B. 𝔑 depends on the chosen |Ψ⟩. @@ -216,7 +217,7 @@ has the split property (is nuclear). - Source: [KOE03] `prop:subsplit`, source.txt 1748–1782 · tier (a) · **proved in source** - Verbatim: - > Let $\lok{A}\subset\lok{B}$ be a chiral subnet. If $\lok{B}$ has the split property (is nuclear), then $\lok{A}$ has the split property (is nuclear). + > Let $\gdef\lok#1{{\mathcal #1}}\lok{A}\subset\lok{B}$ be a chiral subnet. If $\gdef\lok#1{{\mathcal #1}}\lok{B}$ has the split property (is nuclear), then $\gdef\lok#1{{\mathcal #1}}\lok{A}$ has the split property (is nuclear). - Proof route: restrict 𝔄 to its vacuum subrepresentation; by the dB74 criterion it suffices to produce a faithful normal product state on 𝔄(I₁)e_𝔄 ∨ 𝔄(I₂′)e_𝔄; modular covariance (A15) makes A ↦ Ae_𝔄 an @@ -335,7 +336,7 @@ normalisation, 𝔑 = 𝔑_A ⊗ 𝔑_B an intermediate type I subfactor pair. - Source: [HS17] remark after `Thm:dominance` · tier (a) for the assertion · **asserted, no proof, no citation in HS17** - Verbatim: - > The existence of many such intermediate type I subfactors exhausting $\A$ is guaranteed by the split property. + > The existence of many such intermediate type I subfactors exhausting $\gdef\A{\mathfrak{A}}\A$ is guaranteed by the split property. - Refutation status: half-grounded. [DL84]'s introduction states > the interpolation by a chain of type I factors $N_{d}$ , $d$ a diadic rational (Th. 8.3; that section not converted) — "many" in a precise sense, tier (b), @@ -424,7 +425,7 @@ vectors, hence standard vectors for (A, B) form a dense set. HS17 asserts (source.txt 991, tier (a)): -> When $\A_A$ and $\A_B$ are finite dimensional and $\A_A\cap\A_B=\bC 1$, then the algebras are always statistically independent. +> When $\gdef\A{\mathfrak{A}}\A_A$ and $\gdef\A{\mathfrak{A}}\A_B$ are finite dimensional and $\gdef\A{\mathfrak{A}}\gdef\bC{{\mathbb C}}\A_A\cap\A_B=\bC 1$, then the algebras are always statistically independent. **Refuted as literally stated** — see (X10) in the rejected/refuted table. It holds for commuting finite-dimensional *factors* (then the join is naturally diff --git a/docs/math/umegaki-relative-entropy.md b/docs/math/umegaki-relative-entropy.md index f68fef0..d07ef91 100644 --- a/docs/math/umegaki-relative-entropy.md +++ b/docs/math/umegaki-relative-entropy.md @@ -10,18 +10,25 @@ revisions: --- <!-- -No macro preamble. Every verbatim quote that carries a source's private macros -(\S, \U, \A, \a from WIT18; \Tr, \supp from KW20's unavailable Book_KW class) -is placed inside a fenced code block, so the bytes stay exactly as fetched and no -renderer tries to typeset them. Everything the note says in its own voice is -written in plain KaTeX. - -Do not reintroduce a `$$\newcommand{...}$$` block here: measured against -katex 0.18.4, \newcommand does NOT survive from one math span to the next -- not -even when the renderer passes a shared `macros` object, because \newcommand is a -local definition. Such a block leaves every later use of the macro throwing -`Undefined control sequence`. Only \gdef carries, and only into renderers that -share macro state at all. `scripts/check_render.py` enforces this. +No document-level macro preamble: measured through @vscode/markdown-it-katex +(the plugin VS Code's own Markdown preview uses), no macro definition form -- +\newcommand, \gdef, \global\def -- survives from one math span to the next, so +a preamble here would leave every quote using it broken (see +check_render.py / render_check.js). Instead, every verbatim-quote math span +that needs a source's own macro (\S, \U, \A, \a from WIT18; \A from HS17, +whose own \A = \mathfrak{A}, NOT WIT18's \mathcal{A}; \< \> from HIA18; \mbox, +the LaTeX primitive KaTeX does not implement, reconstructed as \mathrm; \Tr, +\supp from KW20's unavailable Book_KW class, likewise reconstructed) carries a +local, self-contained \gdef of exactly that macro, e.g. +`$\gdef\lok#1{{\mathcal #1}}\lok{B}$` -- defined and used inside the same +$...$ pair, so it renders correctly without any state surviving to the next +span. The \gdef prefix is presentation, not content: strip it before +comparing a quote's tex against source.flat.txt for the quote check, and +audit it against the source's own definition (or, where marked +"reconstructed", against ordinary mathematical usage, since the source's own +macro table is unrecoverable). + +Everything the note says in its own voice is written in plain KaTeX. --> # Umegaki relative entropy @@ -121,12 +128,12 @@ the corpus remarks on the finite/semifinite difference. **(D2) [HIA18] §1, eq. (F-1.1)** — tier (a) for HIA18's restatement, tier (c) as a claim about what [UME62] says -> ``` +> $$ > D(\rho\|\sigma):=\begin{cases} > \tau(d_\rho(\log d_\rho-\log d_\sigma)) & \text{if $s(\rho)\le s(\sigma)$}, \\ > +\infty & \text{otherwise}, > \end{cases} -> ``` +> $$ introduced by @@ -148,14 +155,15 @@ itself, not a transcription of its standing hypothesis. **(D3) [HIA18] §1, eq. (F-1.2)** — tier (a) for the restatement, tier (c) for the attribution to Araki, whose papers were not obtained -> ``` +> $$ +> \gdef\<{\langle}\gdef\>{\rangle} > D(\rho\|\sigma):=\begin{cases} > -\<\xi_\rho,(\log\Delta_{\sigma,\rho})\xi_\rho\> > =\<\xi_\sigma,(\Delta_{\rho,\sigma}\log\Delta_{\rho,\sigma})\xi_\sigma\> > & \text{if $s(\rho)\le s(\sigma)$}, \\ > +\infty & \text{otherwise}, > \end{cases} -> ``` +> $$ preceded by @@ -189,10 +197,11 @@ necessarily states) and $f$ convex on $(0,\infty)$: > We then introduce the {\it standard $f$-divergence} $S_f(\rho\|\sigma)$ of $\rho,\sigma$ by -> ``` +> $$ +> \gdef\<{\langle}\gdef\>{\rangle} > S_f(\rho\|\sigma):=\<\xi_\sigma,f(\Delta_{\rho,\sigma})\xi_\sigma\> > +f(0^+)\sigma(1-s_M(\rho))+f'(+\infty)\rho(1-s_M(\sigma)). -> ``` +> $$ with $f(\Delta_{\rho,\sigma}):=\int_{(0,+\infty)}f(t)\,dE_{\rho,\sigma}(t)$ — the spectral integral over the **open** interval, the endpoints carried by the two @@ -221,9 +230,10 @@ tier (a) > {\bf Definition}. {\em The von Neumann relative entropy} between > the two states $\sigma$ and $\rho$ is defined as -> ``` +> $$ +> \gdef\mbox#1{\mathrm{#1}} > S_N(\sigma ||\rho) = \mbox{Tr} \sigma (\ln \sigma - \ln \rho) \;\; . -> ``` +> $$ Explicit natural logarithm. **No support condition and no $+\infty$ branch at all**; the singular case is not discussed anywhere in the paper. The attribution @@ -242,16 +252,15 @@ exponent). **(D6) [WIT18] §"Relative Entropy In Quantum Field Theory", eq. (onorf)** — tier (a) for WIT18's statements, tier (c) as a claim about Araki -> \S_{\Psi|\Phi}(\U)= -\la\Psi|\log \Delta_{\Psi|\Phi}|\Psi\ra. +> $$\gdef\S{{\mathcal S}}\gdef\U{{\mathcal U}}\gdef\la{\langle}\gdef\ra{\rangle} +> \S_{\Psi|\Phi}(\U)= -\la\Psi|\log \Delta_{\Psi|\Phi}|\Psi\ra.$$ with $\Delta_{\Psi|\Phi}:=S^\dagger_{\Psi|\Phi}S_{\Psi|\Phi}$ and $S_{\Psi|\Phi}\,a|\Psi\rangle=a^\dagger|\Phi\rangle$; $\Psi$ must be cyclic and separating for $\mathcal A_{\mathcal U}$, while $\Phi$ may be any state. The singular case is a consequence rather than a stipulation: -> ``` -> For example, $\S_{\Psi|\Phi}(\U)$ may be $+\infty$ if $\Delta_{\Psi|\Phi}$ has a zero eigenvalue, which will occur if $\Phi$ is not separating for $\A_\U$. -> ``` +> For example, $\gdef\S{{\mathcal S}}\gdef\U{{\mathcal U}}\S_{\Psi|\Phi}(\U)$ may be $+\infty$ if $\Delta_{\Psi|\Phi}$ has a zero eigenvalue, which will occur if $\Phi$ is not separating for $\gdef\A{{\mathcal A}}\gdef\U{{\mathcal U}}\A_\U$. `differs from (D3):` the subscript convention on $S$ and $\Delta$ is reversed (C2), and the first argument must carry a cyclic separating vector. @@ -261,16 +270,14 @@ finite-dimensional case — see (R13). **(D7) [HS17], the Definition of the relative entropy, eq. (drel1)** — tier (a) for HS17's statements, tier (c) as a claim about Araki -> H(\omega, \omega') = \langle \Omega | \log \Delta_{\omega, \omega'} \ \Omega\rangle +> $$H(\omega, \omega') = \langle \Omega | \log \Delta_{\omega, \omega'} \ \Omega\rangle$$ together with the Connes-cocycle expression $\lim_{t\to0}\omega([D\omega:D\omega']_t-1)/(it)$ as part of the same definition — a **third** equivalent expression, present in no other corpus source. Standing hypotheses: -> ``` -> One assumes to be given two faithful, normal states $\omega, \omega'$ on a v. Neumann algebra $\A$ in standard form. -> ``` +> One assumes to be given two faithful, normal states $\omega, \omega'$ on a v. Neumann algebra $\gdef\A{\mathfrak{A}}\A$ in standard form. and three stipulations the others do not make: an explicit two-parameter rescaling rule @@ -296,9 +303,10 @@ the asymmetry is in the definition's own hypothesis, not a later remark: > the \textit{quantum relative entropy of $\rho$ and $\sigma$}, denoted by $D(\rho\Vert\sigma)$, is defined as -> ``` +> $$ +> \gdef\Tr{\mathrm{Tr}\,}\gdef\supp{\operatorname{supp}} > D(\rho\Vert\sigma)=\left\{\begin{array}{l l} \Tr[\rho(\log_2 \rho-\log_2\sigma)] & \text{if }\supp(\rho)\subseteq\supp(\sigma),\\ +\infty & \text{otherwise}. \end{array}\right. -> ``` +> $$ with $0\log_2 0=0$, base 2 uniformly, finite dimensions throughout, and the asymmetry stated deliberately: @@ -795,9 +803,7 @@ the same state on $\mathcal A_{\mathcal U}$. - **Do not merge this equality case with (R8)(2)'s $\rho=\sigma$.** They agree: $\Phi=a'\Psi$ is exactly the condition that the two vectors give the same state. - Verbatim: - > ``` - > An important elementary property is that $\S_{\Psi|\Phi}(\U)$ is always non-negative, and vanishes precisely if $\Phi=\a'\Psi$ - > ``` + > An important elementary property is that $\gdef\S{{\mathcal S}}\gdef\U{{\mathcal U}}\S_{\Psi|\Phi}(\U)$ is always non-negative, and vanishes precisely if $\gdef\a{{\sf a}}\Phi=\a'\Psi$ ### (R16) Monotonicity under shrinking the region