Zulip Chat Archive

Stream: Is there code for X?

Topic: comap f (c • μ) = c • comap f μ


Kevin Buzzard (May 20 2025 at 12:00):

I want that pullback of a measure commutes with scalar multiplication. I thought it would be rfl but in fact I went down a deep hole and I am still not entirely out of it; there is one sorry left. @Sébastien Gouëzel you warned me that it wouldn't be easy. I have no energy to figure out how NullMeasurableSet works but I learnt a fair bit about the basics of the measure theory part of mathlib today, which was interesting. What I want is the last lemma in this code; am I making a meal of this? I don't know the tricks for this part of the library but I'm quite pleased I got this far, even if it did take up all my FLT time for today :-)

import Mathlib

open scoped NNReal ENNReal

-- I need 0 < c to deal with ι empty,
lemma ENNReal.iInf_smul {ι : Sort*} {c : 0} (hc : 0 < c) (f : ι  0)  :
     i, c  f i = c    i, f i := by
  apply le_antisymm
  · rw [ inv_smul_le_iff_of_pos hc]
    refine le_iInf (fun i  ?_)
    rw [inv_smul_le_iff_of_pos hc]
    exact iInf_le_of_le i le_rfl
  · refine le_iInf (fun i  ?_)
    rw [smul_le_smul_iff_of_pos_left hc]
    exact iInf_le_of_le i le_rfl

namespace MeasureTheory

@[simp] -- should this be `simp`?
lemma OuterMeasure.comap_smul_ennreal {X Y : Type*} [MeasurableSpace X] [MeasurableSpace Y]
    {f : X  Y} {c : 0}
    {μ : OuterMeasure Y} : comap f (c  μ) = c  comap f μ := rfl

@[simp] -- should this be `simp`?
lemma OuterMeasure.comap_smul_nnreal {X Y : Type*} [MeasurableSpace X] [MeasurableSpace Y]
    {f : X  Y} {c : 0}
    {μ : OuterMeasure Y} : comap f (c  μ) = c  comap f μ := rfl

lemma OuterMeasure.caratheodory_le_smul {X : Type*} (μ : OuterMeasure X) {c : 0} :
    μ.caratheodory  (c  μ).caratheodory := by
  intro s hs
  rw [OuterMeasure.isCaratheodory_iff] at hs 
  peel hs with t h
  simp [h]

lemma OuterMeasure.toMeasure_smul {X : Type*} [ms : MeasurableSpace X] {c : 0}
    (μ : OuterMeasure X) ( : ms  μ.caratheodory) :
    (c  μ).toMeasure (.trans μ.caratheodory_le_smul) = c  μ.toMeasure  := by
  obtain rfl | hc := eq_zero_or_pos c; · simp
  ext s hs
  simp only [Measure.smul_apply, Measure.nnreal_smul_coe_apply]
  change  _, _ = _ *  _, _
  unfold extend
  simp only [coe_smul, Pi.smul_apply, ENNReal.iInf_smul hc, ENNReal.tsum_const_smul]
  rfl

namespace Measure

open scoped NNReal

lemma const_smul_ae_of_ae {X : Type*} [MeasurableSpace X] {μ : Measure X} {s t : Set X} (c : 0)
    (hst : t =ᶠ[ae μ] s) : t =ᶠ[ae (c  μ)] s := by
  rw [ae_eq_set] at hst 
  simp [hst]

lemma nullMeasurableSet_smul_of_nullMeasurableSet {X : Type*} [MeasurableSpace X]
    {μ : Measure X} (c : 0) {s : Set X} (h : NullMeasurableSet s μ) :
    NullMeasurableSet s (c  μ) := by
  -- is `exists_measurable_superset_ae_eq` an iff for NullMeasurableSet?
  -- It says `NullMeasurableSet s μ → ∃ t ⊇ s, MeasurableSet t ∧ t =ᶠ[ae μ] s`
  -- If not then the approach below won't work.
  obtain t, ht := h.exists_measurable_superset_ae_eq
  have ht' : t  s  MeasurableSet t  t =ᶠ[ae (c  μ)] s := by
    peel ht
    exact const_smul_ae_of_ae c this
  /-
  ht' : t ⊇ s ∧ MeasurableSet t ∧ t =ᶠ[ae (c • μ)] s
  ⊢ NullMeasurableSet s (c • μ)
  -/
  sorry

lemma nullMeasurableSet_smul_iff_nullMeasurableSet {X : Type*} [MeasurableSpace X]
    {μ : Measure X} {c : 0} (hc : 0 < c) {s : Set X} :
    NullMeasurableSet s (c  μ)  NullMeasurableSet s μ := by
  refine ⟨?_, nullMeasurableSet_smul_of_nullMeasurableSet c
  intro h
  apply nullMeasurableSet_smul_of_nullMeasurableSet c⁻¹ at h
  rwa [smul_smul, inv_mul_cancel₀ hc.ne', one_smul] at h

lemma comap_smul {X Y : Type*} [MeasurableSpace X] [MeasurableSpace Y] {f : X  Y} {c : 0}
    {μ : Measure Y} : comap f (c  μ) = c  comap f μ := by
  obtain rfl | hc := eq_zero_or_pos c; · simp
  by_cases h : Function.Injective f   (s : Set X), MeasurableSet s  NullMeasurableSet (f '' s) μ
  · unfold comap
    rw [dif_pos h]
    have h' : Function.Injective f 
         (s : Set X), MeasurableSet s  NullMeasurableSet (f '' s) (c  μ) := by
      refine h.1, ?_⟩
      replace h := h.2
      peel h with s hs h
      rwa [nullMeasurableSet_smul_iff_nullMeasurableSet hc]
    rw [dif_pos h']
    simp only [smul_toOuterMeasure, LinearMap.map_smul_of_tower]
    rw [OuterMeasure.toMeasure_smul]
  · have h' : ¬ (Function.Injective f 
         (s : Set X), MeasurableSet s  NullMeasurableSet (f '' s) (c  μ)) := by
      contrapose! h
      refine h.1, ?_⟩
      replace h := h.2
      peel h with s hs h
      rwa [nullMeasurableSet_smul_iff_nullMeasurableSet hc] at h
    unfold comap
    rw [dif_neg h, dif_neg h']
    simp

Rémy Degenne (May 20 2025 at 12:14):

lemma nullMeasurableSet_smul_of_nullMeasurableSet {X : Type*} [MeasurableSpace X]
    {μ : Measure X} (c : 0) {s : Set X} (h : NullMeasurableSet s μ) :
    NullMeasurableSet s (c  μ) :=
  NullMeasurableSet.mono_ac h (AbsolutelyContinuous.rfl.smul_left c)

Kevin Buzzard (May 20 2025 at 12:15):

I rather suspect that you can golf a lot of the above lemmas :-) (or even convince me that they're not needed!)

Rémy Degenne (May 20 2025 at 12:15):

Yes, I am currently golfing :)

Kevin Buzzard (May 20 2025 at 12:18):

I hope that at least my beginner attempt makes your life easier! The only result which really had some "Lean content" was OuterMeasure.toMeasure_smul where at the end I removed the unfold OuterMeasure.toMeasure Measure.ofMeasurable inducedOuterMeasure extend OuterMeasure.ofFunction and replaced it with a change, and then I had to battle through moving the smul across binders. Everything else was kind of intro, apply, exact, or in the API.

Rémy Degenne (May 20 2025 at 12:20):

import Mathlib

open scoped NNReal ENNReal

namespace MeasureTheory

lemma NullMeasurableSet.smul_measure {X : Type*} [MeasurableSpace X]
    {μ : Measure X} (c : 0) {s : Set X} (h : NullMeasurableSet s μ) :
    NullMeasurableSet s (c  μ) :=
  NullMeasurableSet.mono_ac h (Measure.AbsolutelyContinuous.rfl.smul_left c)

lemma nullMeasurableSet_smul_iff_nullMeasurableSet {X : Type*} [MeasurableSpace X]
    {μ : Measure X} {c : 0} (hc : 0 < c) {s : Set X} :
    NullMeasurableSet s (c  μ)  NullMeasurableSet s μ := by
  refine ⟨?_, NullMeasurableSet.smul_measure c
  intro h
  apply NullMeasurableSet.smul_measure c⁻¹ at h
  rwa [smul_smul, inv_mul_cancel₀ hc.ne', one_smul] at h

namespace Measure

lemma comap_smul {X Y : Type*} [MeasurableSpace X] [MeasurableSpace Y] {f : X  Y} {c : 0}
    {μ : Measure Y} : comap f (c  μ) = c  comap f μ := by
  obtain rfl | hc := eq_zero_or_pos c; · simp
  by_cases h : Function.Injective f   (s : Set X), MeasurableSet s  NullMeasurableSet (f '' s) μ
  · ext s hs
    rw [comap_apply₀ f _ h.1 _ hs.nullMeasurableSet, smul_apply, smul_apply,
      comap_apply₀ f μ h.1 h.2 hs.nullMeasurableSet]
    simpa [nullMeasurableSet_smul_iff_nullMeasurableSet hc] using h.2
  · have h' : ¬ (Function.Injective f 
         (s : Set X), MeasurableSet s  NullMeasurableSet (f '' s) (c  μ)) := by
      contrapose! h
      simpa [nullMeasurableSet_smul_iff_nullMeasurableSet hc] using h
    simp [comap, dif_neg h, dif_neg h']

end Measure

end MeasureTheory

(edited for better names)

Rémy Degenne (May 20 2025 at 12:21):

I kept only the results that are used for comap_smul

Kevin Buzzard (May 20 2025 at 12:23):

Thanks so much!

Kevin Buzzard (May 20 2025 at 12:59):

The simpa trick works without having to use contrapose! at the end:

  · have h' : ¬ (Function.Injective f 
         (s : Set X), MeasurableSet s  NullMeasurableSet (f '' s) (c  μ)) := by
      simpa [nullMeasurableSet_smul_iff_nullMeasurableSet hc] using h

Are you PRing it or am I?

Rémy Degenne (May 20 2025 at 13:27):

I'll PR it.
A remark about the code above: we have a lot of API about measures now, so any time you unpack definitions so much that an OuterMeasure appears, you probably unpacked too much.

Sébastien Gouëzel (May 20 2025 at 13:30):

If you PR it, can you do it for c : ENNReal instead of just NNReal?

Rémy Degenne (May 20 2025 at 13:53):

#25052

Kevin Buzzard (May 20 2025 at 15:55):

Many thanks! I have switched to map for the main definition of FLT now I understand that it's much easier to work with, but there is still one key calculation where I need to use comaps so I will need this and perhaps more; it's the first thing on my job list tomorrow to figure out exactly what, if anything, more I need from comaps.

Kevin Buzzard (May 20 2025 at 17:23):

Actually I know already that I need these:

open Topology in
@[to_additive]
lemma isHaarMeasure_comap_of_isOpenEmbedding {G H : Type*}
    [Group G] [TopologicalSpace G] [MeasurableSpace G] [BorelSpace G]
    [Group H] [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H]
    {φ : G →* H} ( : IsOpenEmbedding φ) (μ : Measure H) [IsHaarMeasure μ] :
    IsHaarMeasure (comap φ μ) := by
  sorry -- issue FLT#507

open Topology in
lemma regular_comap_of_isOpenEmbedding {G H : Type*}
    [TopologicalSpace G] [MeasurableSpace G] [BorelSpace G]
    [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H]
    {φ : G  H} ( : IsOpenEmbedding φ) (μ : Measure H) [Regular μ] : Regular (comap φ μ) := by
  sorry -- issue FLT#513

and my plan was to just do them from first principles (or persuade someone else to do them)

Eric Wieser (May 20 2025 at 17:27):

@Yaël Dillies, do I remember correctly that I asked for this result in a PR of yours?

Yaël Dillies (May 20 2025 at 17:51):

It was #20204

David Ledvinka (May 21 2025 at 10:34):

Kevin Buzzard said:

Actually I know already that I need these:

open Topology in
@[to_additive]
lemma isHaarMeasure_comap_of_isOpenEmbedding {G H : Type*}
    [Group G] [TopologicalSpace G] [MeasurableSpace G] [BorelSpace G]
    [Group H] [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H]
    {φ : G →* H} ( : IsOpenEmbedding φ) (μ : Measure H) [IsHaarMeasure μ] :
    IsHaarMeasure (comap φ μ) := by
  sorry -- issue FLT#507

open Topology in
lemma regular_comap_of_isOpenEmbedding {G H : Type*}
    [TopologicalSpace G] [MeasurableSpace G] [BorelSpace G]
    [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H]
    {φ : G  H} ( : IsOpenEmbedding φ) (μ : Measure H) [Regular μ] : Regular (comap φ μ) := by
  sorry -- issue FLT#513

and my plan was to just do them from first principles (or persuade someone else to do them)

I have a proof of the first one but I need the additional assumptions
[MeasurableMul G] [MeasurableMul H]

David Ledvinka (May 21 2025 at 10:44):

Technically I think [MeasurableMul G] should follow from [MeasurableMul H] and the fact that φ is an open embedding.

David Ledvinka (May 21 2025 at 11:08):

open Topology in
@[to_additive]
lemma isHaarMeasure_comap_of_isOpenEmbedding {G H : Type*}
    [Group G] [TopologicalSpace G] [MeasurableSpace G] [BorelSpace G] [MeasurableMul G]
    [Group H] [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H] [MeasurableMul H]
    {φ : G →* H} ( : IsOpenEmbedding φ) (μ : Measure H) [IsHaarMeasure μ] :
    IsHaarMeasure (comap φ μ) :=
  { map_mul_left_eq_self := by
      intro g
      ext s hs
      rw [map_apply (by fun_prop) hs]
      repeat rw [MeasurableEmbedding.comap_apply .measurableEmbedding]
      have : φ '' ((fun x  g * x) ⁻¹' s) = (fun x  φ g * x) ⁻¹' (φ '' s) := by
        ext
        constructor
        · intro h
          obtain y, hy, rfl := h
          use g * y, hy
          simp
        · intro h
          obtain y, yins, hy := h
          use g⁻¹ * y
          constructor
          · simp [yins]
          · simp [hy]
      rw [this,  map_apply (by fun_prop), map_mul_left_eq_self]
      exact .measurableEmbedding.measurableSet_image.mpr hs
    lt_top_of_isCompact := by
      intro K hK
      rw [MeasurableEmbedding.comap_apply .measurableEmbedding]
      exact IsFiniteMeasureOnCompacts.lt_top_of_isCompact (hK.image .continuous)
    open_pos := by
      intro U hU Une
      rw [MeasurableEmbedding.comap_apply .measurableEmbedding]
      exact IsOpenPosMeasure.open_pos _ (.isOpen_iff_image_isOpen.mp hU) (Une.image φ)
  }

Kevin Buzzard (May 21 2025 at 11:53):

Oh you can definitely have [IsTopologicalGroup G] and [IsTopologicalGroup H]! This gives that multiplication is continuous and hence measurable! In all the applications they're topological groups.

Please feel free to make a PR to FLT: add in the topological group hypotheses (or less, if you want). The relevant file is https://github.com/ImperialCollegeLondon/FLT/blob/main/FLT/HaarMeasure/HaarChar/AddEquiv.lean . Thanks so much!

Kevin Buzzard (May 21 2025 at 11:56):

I can PR it for you but please feel free to take the opportunity of being a contributor to the FLT project. If you don't want this then that's also fine, I'll just PR it myself :-)

David Ledvinka (May 21 2025 at 22:27):

Is there a github permissions thread for FLT? I don't have permission to create a branch and the CONTRIBUTING.md doesn't seem to mention it.

David Ledvinka (May 22 2025 at 00:45):

Have a proof of the second as well

Ruben Van de Velde (May 22 2025 at 03:24):

You can submit from a fork

Kevin Buzzard (May 22 2025 at 05:17):

Yes please make a branch not called main and PR from a fork. Also feel free to claim the relevant issues on GitHub so nobody else works on them. Many thanks for contributing to FLT!


Last updated: Dec 20 2025 at 21:32 UTC