diff --git a/Graphon.lean b/Graphon.lean index ddf5012..752af38 100644 --- a/Graphon.lean +++ b/Graphon.lean @@ -44,8 +44,10 @@ import Graphon.RelRankCoding import Graphon.RelRankRepresentation import Graphon.RelRankInjectionInvariance import Graphon.RelLatentGeometry +import Graphon.RelObservationGeometry import Graphon.RelPooledLatents import Graphon.RelPooledExtension +import Graphon.RelPooledAcceptance import Graphon.RelSingletonPeel import Graphon.RelFixingAlgebra import Graphon.RelRankAlgebra @@ -246,7 +248,7 @@ in Lean 4 using Mathlib. * `Graphon.ForMathlib.CountableFactorLift` — step 3 of the step-approximation programme, signature-free: **lifting a countable-factor joint law to the carriers**. Given factor maps `q₁, q₂` into countable spaces with measurable singletons (explicit hypotheses — no hidden discrete instances) and a joint law `lam` on the factor product whose marginals are the pushed carrier measures, `countableFactorLift` couples the carriers by mixing normalized cell restrictions with weights `lam {(i,j)}`. Both carrier marginals are exact (`countableFactorLift_map_fst/snd`), the lift is a probability measure whenever a carrier is, and the acceptance test is the exact atomwise round-trip `countableFactorLift_map_prodMap`: pushing back through `Prod.map q₁ q₂` recovers `lam` on the nose. **Null cells are annihilated, never divided by**: marginal compatibility forces `lam` to vanish on any cell with a null fiber (the guards), so normalization only ever cancels against positive mass — regressed on a genuinely mixed example with one positive coin cell and one annihilated null cell. Cost transport across the lift and the triangle assembly are later units * `Graphon.ForMathlib.CondExpRepresentable` — **upstream candidate** (signature-free, Mathlib-only imports): conditioning is insensitive to replacing a σ-algebra by one that represents it **modulo the measure**. Given `m₂ ≤ m₁` and an eventwise representative in `m₂` for every `m₁`-set, `condExp_eq_condExp_of_ae_representable` gives `μ[f | m₁] =ᵐ μ[f | m₂]`, and `iCondIndepFun_congr_of_ae_representable` transfers mutual conditional independence between the two. This is the recurring R4 situation where an abstractly defined conditioning algebra has a concrete factor-map realization that generates it only eventwise: no σ-algebra equality is available or claimed, but everything conditional expectation can see transfers. **The proof deliberately does not lift the hypothesis from sets to functions** — Mathlib's `EventuallyMeasurable` warns that eventual measurability is strictly weaker than a.e. equality to a measurable function and leaves the equivalence a TODO, so that route would mean redoing simple-function approximation. Instead the uniqueness argument runs in the other direction: `μ[f | m₂]` is the *candidate* at `m₁`, already `m₁`-strongly measurable since `m₂ ≤ m₁` is raw, and its set integrals over `m₁`-sets are computed by moving to an `m₂` representative. The conditional-expectation statement needs only `[IsFiniteMeasure μ]`; the standard Borel hypothesis on the `iCondIndepFun` corollary is forced by Mathlib defining `iCondIndepFun` through `condExpKernel`, not by the argument * `Graphon.ForMathlib.CondIndepRefine` — signature-free, Mathlib-only imports: **refining the conditioning of mutual conditional independence**. `iCondIndep_of_condIndep_iSup`: a family mutually conditionally independent given `m'` stays so given any larger `m₂ ≥ m'` that is conditionally independent of the family's join given `m'`. The engine is a private projection identity `μ⟦E | m₂⟧ =ᵐ μ⟦E | m'⟧` for join-events `E`, proved by uniqueness of conditional expectation at `m₂` with candidate `μ⟦E | m'⟧`, the pull-out property, and the product identity of conditional independence; it stays private until a second consumer pins down its natural generality -* `Graphon.ForMathlib.CondIndepSup` — signature-free, Mathlib-only imports: two closure properties of conditional independence. `CondIndep.sup_right`: joining the conditioning algebra to one side is free — `m₁ ⊥⊥ m₂ ∣ m'` gives `m₁ ⊥⊥ (m' ⊔ m₂) ∣ m'`, via the π-system `{e ∩ f}` generating the join and the indicator pull-out `condExp_indicator`. `CondIndepFun.congr`: `CondIndepFun` respects a.e. equality of the functions — the conditional analogue of `IndepFun.congr`, absent from Mathlib; it is what lets a variable only a.e. equal to a conditioning-measurable one be absorbed into a side +* `Graphon.ForMathlib.CondIndepSup` — signature-free, Mathlib-only imports: three closure properties of conditional independence. `CondIndep.sup_right`: joining the conditioning algebra to one side is free — `m₁ ⊥⊥ m₂ ∣ m'` gives `m₁ ⊥⊥ (m' ⊔ m₂) ∣ m'`, via the π-system `{e ∩ f}` generating the join and the indicator pull-out `condExp_indicator`. `CondIndepFun.congr`: `CondIndepFun` respects a.e. equality of the functions — the conditional analogue of `IndepFun.congr`, absent from Mathlib; it is what lets a variable only a.e. equal to a conditioning-measurable one be absorbed into a side. `CondIndepFun.congr_cond`: the conditioning σ-algebra may be replaced by an equal one, the dependent `≤` proof moving by proof irrelevance once the equality is substituted — needed wherever a conditioning map is reindexed, and consumed by the rank-one coupling and screening arguments and by the pooled screening transport * `Graphon.ForMathlib.RelativeFactorCoupling` — **upstream candidate** (signature-free, Mathlib-only imports): the **relatively independent joining over a common factor**, `relativeFactorCoupling μ ν q r = (condDistrib id q μ ×ₖ condDistrib id r ν) ∘ₘ μ.map q`, for measurable `q : Ω → Z`, `r : Ξ → Z` with `ν.map r = μ.map q`. Both sides are disintegrated over `Z` and the fibres multiplied independently; the independent product `μ.prod ν` would not identify the factors, and an arbitrary coupling that did could still let each side see more of the other. The engine is `map_condDistrib_id`, **fibre concentration**: pushing `condDistrib id q μ` through `q` is the deterministic identity kernel, i.e. conditioning on `q` pins down `q`. From it: both marginals, the common-factor identity `q ∘ Prod.fst =ᵐ r ∘ Prod.snd` (proved from the two fibre-concentration statements, one per side — equality of the factor *marginals* says nothing about the joint), and `condIndepFun_fst_snd_relativeFactorCoupling`, conditional independence of the two coordinates given `comap (q ∘ Prod.fst)`. The conditioning is deliberately on that variable, defined on the coupling space, rather than on the disintegration variable `∘ₘ` integrates out: only the former is visible to consumers, who see the coupling and not its construction. No σ-algebra equality `σ(q ∘ fst) = σ(snd)` is claimed — the latent may carry strictly more than the factor, as `U` carries more than `1_{U < p}`; what conditional independence excludes is that the surplus says anything further about the first coordinate. `map_prodMap_relativeFactorCoupling_two_sided` is the general symmetry: measure-preserving maps on both spaces shifting the two factors by one `e` give invariance under `Prod.map T U`, with the factor-law pushforward identity derived from the commuting square rather than assumed * `Graphon.ForMathlib.UnitIntervalMap` — Mathlib-only packaging of its standard-Borel kernel representation as a measure-preserving map from `[0,1]`, with atomic and mixed-law regressions; this is a prescribed-pushforward theorem, not pointwise surjectivity * `Graphon.UniformFactorCoupling` — R4 converse piece 3 (#107): the uniform specialization of the joining above, `exists_relativeFactorCoupling_uniform01`. The only uniform-specific input is `Measure.exists_measurable_map_eq_uniform01` (#140), which supplies the coding map `f : ℝ → Z` matching the two factor laws; everything after is generic. It runs in the direction `Graphon.KernelRandomization` does not — that module manufactures a variable with a prescribed law *out of* a uniform, whereas here a uniform is manufactured *alongside* an already-given variable — and it is reusable at every rank, so it replaces a port of an external de Finetti package with the narrow transfer step the recursion actually needs @@ -261,8 +263,10 @@ in Lean 4 using Mathlib. * `Graphon.RelSingletonPeel` — R4 converse piece 3 (#107): `iCondIndepFun_of_fixingAlgebra_singleton`, mutual conditional independence at rank one for **any** vertex-indexed family measurable for its own singleton fixing algebra. Basis-free; the coherent-basis exact layers and the raw relation blocks are both instances. Fails above rank one because equal-rank supports can meet * `Graphon.RelRankRepresentation` — R4 converse piece 3 (#107): the **specification** a rank-`n` joint representation must satisfy — coupling primitive, both marginals, joint relabeling invariance, local recovery, rank-truncated screening. **Interface only; no existence theorem at any rank.** Independent of `CoherentBasis`. See the module header for the design rationale and the two acceptance tests * `Graphon.RelLatentGeometry` — R4 converse (#107), law-free: **carrier-parametric latent geometry**. Supports of cardinality below the working rank over an arbitrary sortwise carrier, the latent cube they index, its i.i.d. uniform source, the action of a **full** sortwise permutation family with identity/composition laws and exact source invariance, restriction along a sortwise embedding of carriers, and the naturality laws — including the honest moved-window form, since a permutation crossing the image of an embedding does not commute with restriction along it. The action is by the full family deliberately: finite support is a property of a particular carrier's automorphisms, not of latent cubes, so a finitely supported subgroup is obtained by restricting this action rather than the reverse. `RankLatentIndex` is now a compatibility alias for the core at `Vinfinite S` — definitionally, with no downstream change +* `Graphon.RelObservationGeometry` — R4 converse (#107): the **observation layer over an arbitrary carrier** — local latents, blocks of raw relation coordinates, and the rank-truncated remainder. The `Vinfinite`-indexed originals are compatibility aliases, so pooled recovery and screening instantiate this core rather than duplicating it. **The three do not transport equally, and the difference is truth rather than proof effort**: `localLatentsOver` and `blockMapOver` are local — they read only coordinates supported inside a given finite set — and admit naturality along an arbitrary sortwise **embedding**; `restObservationOver` is global, ranging over *every* rank-`≤ n` coordinate of the ambient carrier other than the one at `A`, so along an embedding into a larger carrier the target remainder sees coordinates the source cannot and an embedding-level commuting law would be **false**. It transports only along a carrier **equivalence** — for the pooled setting, the canonical `poolVertexEquiv` * `Graphon.RelPooledLatents` — R4 converse (#107), stage 1 of the pooled-latent extension gate: the core instantiated at `PoolVertex S`. `PooledRankLatentIndex`/`PooledRankLatentSpace`/`pooledRankLatentSource`; `pooledRankLatentRelabel`, the action of the **full mixed** pooled family `∀ s, Equiv.Perm (PoolVertex S s)` — permutations moving vertices between halves included — with its identity and composition laws and exact source invariance; and `restrictOriginalLatents`, the measurable restriction to latents indexed by original supports, whose codomain is the rank-`n` cube itself because the index type is the carrier-parametric one. Naturality is stated in the **honest moved-window form** valid for every pooled permutation, with the commuting square available only as the split corollary. Law-free: no `RankRepresentation`, recovery, screening, or coupling appears, and those enter at later stages of the gate * `Graphon.RelPooledExtension` — R4 converse (#107), stage 2 of the pooled-latent extension gate: **the pooled rank extension**. `PooledRankExtension C` carries exactly three fields — the joint law on the pooled structure space times the pooled latent cube, its exact restriction to `C.P` along the two original restrictions, and invariance under the **full** pooled permutation family (mixed permutations included, the load-bearing quantifier). **No independence field**: an independent pool would recreate the defect of the rejected factor coupling. `RankRepresentation.pooledExtension` is the cheap constructor, and both of its laws are `map_prodMap_restrict_self` in disguise — writing `pv` for `poolVertexEquiv` and `ov` for `originalVertex`, the transport is `comap pv` on structures and restriction along `pv` on latents; `restrictOriginal ∘ transport` is `comap (pv ∘ ov)` with `pv ∘ ov` a **self-injection** of the original carrier, and `relabel ρ ∘ transport = transport ∘ relabel κ` for the conjugate `κ = pv ∘ ρ ∘ pv⁻¹`, a **permutation** of it. The structure deliberately carries **no mixed-window field**: the joint mixed-window marginal, and current-rank recovery and screening on mixed pooled supports, are separate derived consequences of the three fields rather than part of the primitive, and nothing route-specific belongs here +* `Graphon.RelPooledAcceptance` — R4 converse (#107), stage 3 of the pooled-latent extension gate, organizing result: **the joint restriction theorem**. For *every* sortwise embedding `e : ∀ s, Vinfinite S s ↪ PoolVertex S s`, restricting a pooled rank extension jointly — structure and latents along the same embedding — returns the representation exactly: `Q.law.map (Prod.map (RelStructure.restrict e) (latentRestrictOver e n)) = C.P`. Being **joint** is the point: it recovers the `(X, U_{