From cf75af3324267ee37d21e09f5458a7a263eb8963 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 9 Sep 2026 16:19:21 +0200 Subject: [PATCH 01/39] pulling moritz/louis proofs from workshop repo --- Polyhedral.lean | 1 + .../Cone/Pointed/Finite/Face/KreinMilman.lean | 233 +++--------------- .../ConvexSpace/Polytope/KreinMilman.lean | 94 +++++++ .../ConvexSpace/Set/Homogenization.lean | 23 +- .../AffineSpace/Homogenization/Basic.lean | 19 ++ 5 files changed, 175 insertions(+), 195 deletions(-) create mode 100644 Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean diff --git a/Polyhedral.lean b/Polyhedral.lean index ca634446..532d25f6 100644 --- a/Polyhedral.lean +++ b/Polyhedral.lean @@ -56,6 +56,7 @@ public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polyhedron.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Basic public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Face public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Homogenization +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.KreinMilman public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Pointwise public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Prod diff --git a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Finite/Face/KreinMilman.lean b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Finite/Face/KreinMilman.lean index 5ba34f43..0ec1d5fd 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Finite/Face/KreinMilman.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Finite/Face/KreinMilman.lean @@ -1,19 +1,22 @@ /- -Copyright (c) 2025 Olivia Röhrig, Martin Winter. All rights reserved. +Copyright (c) 2026 Moritz Firsching. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig, Martin Winter +Authors: Moritz Firsching -/ module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Finite.Face.Basic +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Homogenization +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.KreinMilman /-! In this file we prove the Krein-Milman theorem for FG cones: every finitely generated cone is spanned by its rays, that is, by the finite set of its 1-dimensional faces. -TODO: aspects of the proof are rather cumbersome since the atoms of the face lattice are rays -rather than points. We therefore intend to perform the proof on the polytope side and -transfer it here using homogenization. --/ +The theorem is derived from the Krein-Milman theorem for polytopes +(`IsPolytope.krein_milman`): a salient FG cone admits a linear functional that is positive on +all of its nonzero elements, the slice of the cone at weight one is a polytope, and the cone +is the homogenization of that slice, so its rays are the homogenizations of the vertices of +the slice. -/ @[expose] public section @@ -23,159 +26,21 @@ variable {R M : Type*} section Field -variable [Field R] [LinearOrder R] [IsOrderedRing R] +variable [Field R] [LinearOrder R] [IsStrictOrderedRing R] variable [AddCommGroup M] [Module R M] -variable {C F F₁ F₂ : PointedCone R M} - -section opt - -/- The minimum of `f/g` on a cone. -/ -def opt (C : PointedCone R M) (f g : M →ₗ[R] R) : PointedCone R M where - carrier := {x ∈ C | ∀ y ∈ C, f x * g y ≤ f y * g x} - add_mem' := by - intro a b ha hb - simp only [Set.mem_ofPred_eq, map_add] at * - refine ⟨C.add_mem ha.1 hb.1, ?_⟩ - intro y hy - rw [add_mul, mul_add] - exact add_le_add (ha.2 y hy) (hb.2 y hy) - zero_mem' := by simp only [Set.mem_ofPred_eq, zero_mem, map_zero, zero_mul, mul_zero, le_refl, - implies_true, and_self] - smul_mem' := by - intro a x hx - refine ⟨C.smul_mem a.2 hx.1, ?_⟩ - intro y hy - by_cases! h : a ≤ 0 - · simp [nonpos_iff_eq_zero.mp h] - simp only [LinearMap.map_smul_of_tower, Algebra.smul_mul_assoc, Algebra.mul_smul_comm] - exact (smul_le_smul_iff_of_pos_left h).mpr <| hx.2 y hy - --- TODO: the proof was modified after features changed and needs golfing: --- * `Salient.of_le_positive` was hacked in. --- * `mem_positive'` was hacked in to recover the previous form of `hg`. -lemma IsFaceOf.of_opt (C : PointedCone R M) (f g : M →ₗ[R] R) (hCg : C ≤ g.positive) : - (C.opt f g).IsFaceOf C := by - have hg : ∀ x ∈ C, 0 ≤ g x ∧ (g x = 0 → x = 0) := -- hacked in to recover `hg` - fun _ hx => g.mem_positive'.mp (hCg hx) - refine ⟨fun _ hx ↦ hx.1, ?_⟩ - intro x y a hx hy ha ⟨h2, h⟩ - by_cases! x_ne_0 : x = 0 - · rw [x_ne_0]; exact zero_mem (C.opt f g) - by_cases! t_ne_0 : a • x + y = 0 - · exfalso - have hC' := Salient.of_le_positive hCg - exact (smul_ne_zero (ne_of_gt ha) x_ne_0) <| - hC' (a • x) (C.smul_mem (le_of_lt ha) hx) y hy t_ne_0 - refine ⟨hx, fun z hz ↦ ?_⟩ - have : g x > 0 := lt_of_le_of_ne (hg _ hx).1 (fun h ↦ x_ne_0 <| (hg _ hx).2 (Eq.symm h)) - have t1 := h x hx - have t2 := h y hy - have t4 := (mul_le_mul_iff_of_pos_left this).mpr <| (h z hz) - simp only [map_add, map_smul, smul_eq_mul] at t1 t2 t4 - have local_lemma : ∀ {a b c d e : R}, e > 0 → a ≤ b → c ≤ d → e * a + c = e * b + d → a = b := - fun _ _ _ _ ↦ by nlinarith - have t3 : (a * f x + f y) * g x = f x * (a * g x + g y) := local_lemma ha t1 t2 (by ring) - have : a * g x + g y > 0 := by - simpa only [gt_iff_lt, map_add, map_smul, smul_eq_mul] using - lt_of_le_of_ne (hg _ h2).1 (fun h ↦ t_ne_0 <| (hg _ h2).2 (Eq.symm h)) - apply (mul_le_mul_iff_of_pos_left this).mp - nth_rw 3 [mul_comm] at t3 - rw [← mul_assoc, ← t3] - linarith - -lemma FG.exists_ne_zero_mem_opt (C : PointedCone R M) (hC : C.FG) (hC0 : C ≠ ⊥) (f g : M →ₗ[R] R) - (hCg : C ≤ g.positive) : ∃ x, x ≠ 0 ∧ x ∈ C.opt f g := by classical - have hg : ∀ x ∈ C, 0 ≤ g x ∧ (g x = 0 → x = 0) := -- hacked in to recover `hg` - fun _ hx => g.mem_positive'.mp (hCg hx) - obtain ⟨s, hs⟩ := hC - have hs0 : ∃ z ∈ s, z ≠ 0 := by - by_contra hs0 - push Not at hs0 - exact hC0 <| by rw [← hs]; exact Submodule.span_eq_bot.mpr hs0 - have hg_pos : ∀ {z : M}, z ∈ C → z ≠ 0 → 0 < g z := by - intro z hz hz0 - exact lt_of_le_of_ne (hg _ hz).1 (fun h ↦ hz0 <| (hg _ hz).2 (Eq.symm h)) - let s0 : Finset M := s.filter fun z => z ≠ 0 - have hs0_ne : s0.Nonempty := by - rcases hs0 with ⟨z, hzs, hz0⟩ - exact ⟨z, by simp [s0, hzs, hz0]⟩ - obtain ⟨x, hx0, hxmin⟩ := Finset.exists_min_image s0 (fun z => f z / g z) hs0_ne - have hxs : x ∈ s := (Finset.mem_filter.mp hx0).1 - have hx_ne_0 : x ≠ 0 := (Finset.mem_filter.mp hx0).2 - have hxC : x ∈ C := by rw [← hs]; exact subset_hull hxs - have hgx : 0 < g x := hg_pos hxC hx_ne_0 - have hgen : ∀ z ∈ s, f x * g z ≤ f z * g x := by - intro z hzs - by_cases hz0 : z = 0 - · simp [hz0] - have hzC : z ∈ C := by rw [← hs]; exact subset_hull hzs - have hgz : 0 < g z := hg_pos hzC hz0 - have hz0' : z ∈ s0 := by simp [s0, hzs, hz0] - exact (div_le_div_iff₀ hgx hgz).1 (hxmin _ hz0') - refine ⟨x, hx_ne_0, ?_⟩ - refine ⟨hxC, ?_⟩ - intro y hy - rw [← hs] at hy - induction hy using Submodule.span_induction with - | mem z hz => exact hgen z hz - | zero => - simp - | add y z _ _ hy hz => - simpa [map_add, add_mul, mul_add] using add_le_add hy hz - | smul a y _ hy => - have hy' := mul_le_mul_of_nonneg_left hy a.2 - simp only [LinearMap.map_smul_of_tower, Algebra.mul_smul_comm, Algebra.smul_mul_assoc, - ge_iff_le] - exact hy' - -lemma FG.opt_neq_bot (C : PointedCone R M) (hC : C.FG) (hC0 : C ≠ ⊥) (f g : M →ₗ[R] R) - (hCg : C ≤ g.positive) : C.opt f g ≠ ⊥ := by - rcases FG.exists_ne_zero_mem_opt C hC hC0 f g hCg with ⟨x, hx0, hxopt⟩ - exact fun hbot => hx0 <| by simpa [hbot] using hxopt - -end opt +variable {C : PointedCone R M} -/- For every ray `x` of the span of a set `s`, there is a member of `s` that also spans the ray. -/ -lemma IsFaceOf.hull_ray {s : Set M} {x : M} (hx : x ≠ 0) - (hspan : (R ∙₊ x).IsFaceOf (hull R s)) : ∃ y ∈ s, ∃ c : R, 0 < c ∧ y = c • x := by - have h := hspan.hull_inter_face_hull_inf_face - have ⟨y, hy, hy0⟩ : ∃ w ∈ s ∩ (R ∙₊ x), w ≠ 0 := by - by_contra H - absurd hx - push Not at H - simp only [← Set.mem_singleton_iff] at H - simpa [h] using Submodule.span_mono (R := {c : R // 0 ≤ c}) H - simp only [Set.mem_inter_iff, SetLike.mem_coe, Submodule.mem_span_singleton, - Subtype.exists] at hy - obtain ⟨hys, a, ha, rfl⟩ := hy - exact ⟨_, hys, a, lt_of_le_of_ne ha (fun h => hy0 (by simp [← h])), rfl⟩ +open Convexity ConvexSet Affine Affine.IsHomogenization -open Module in /-- Krein-Milman theorem: every finitely generated cone is spanned by its rays, that is, by the finite set of its 1-dimensional faces. -/ lemma FG.krein_milman (hfg : C.FG) (hsal : C.Salient) : ∃ s : Finset M, hull R s = C ∧ ∀ x ∈ s, (R ∙₊ x).IsFaceOf C := by classical - let ⟨s, hs⟩ := hfg - by_cases hs' : s = ∅ - · exact ⟨∅, by simp [← hs, hs']⟩ - by_contra! h - let t := s.filter fun x => (R ∙₊ x).IsFaceOf C - specialize h t - have hts : t ⊆ s := by simp [t] - have hst : ¬(s : Set M) ⊆ hull R (t : Set M) := by - by_contra h' - have h' := Submodule.span_mono (R := {c : R // 0 ≤ c}) h' - have h'' := Submodule.span_mono (R := {c : R // 0 ≤ c}) hts - simp only [Submodule.span_coe_eq_restrictScalars, Submodule.restrictScalars_self] at h' - rw [← le_antisymm h' h'', hs] at h - simp [t, and_assoc] at h - obtain ⟨x, hxs, hxt⟩ := Set.not_subset.mp hst - have hx : x ∈ C := by - rw [← hs] - exact subset_hull hxs - obtain ⟨f, hf, hf'⟩ := FG.farkas (Dual.eval R M) hxt + by_cases hbot : C = ⊥ + · exact ⟨∅, by simp [hbot]⟩ + -- a linear functional that is positive on all nonzero elements of `C` obtain ⟨g, hg, hgker⟩ := IsExposedFaceOf.lineal hfg have hker : C ⊓ g.ker = ⊥ := by rw [← hgker] @@ -188,50 +53,30 @@ lemma FG.krein_milman (hfg : C.FG) (hsal : C.Salient) : have : y ∈ C ⊓ g.ker := ⟨hy, hgy⟩ rw [hker] at this simpa using this - simp only [Dual.eval_apply] at hf hf' - let F := C.opt f g - have hF : F.IsFaceOf C := IsFaceOf.of_opt C f g hgC - have hC0 : C ≠ ⊥ := by - intro hC0 - have : x = 0 := by simpa [hC0] using hx - exact hxt (by simp [this]) - have hF' := opt_neq_bot C hfg hC0 f g hgC - have hFsal := Salient.of_le_salient hsal hF.le - obtain ⟨r, hr0, hrF⟩ := exists_ray (hF.fg hfg) hF' hFsal - have hr := IsFaceOf.trans hrF hF - rw [← hs] at hr - obtain ⟨w, hws, c, hc', h⟩ := hr.hull_ray hr0 - simp only [SetLike.mem_coe] at hws - have hc0 := (ne_of_lt hc').symm - have hrw : r = c⁻¹ • w := by - subst h hs - simp [smul_smul, hc0] - rw [hrw] at hr - rw [hull_singleton_smul_eq (inv_pos.mpr hc')] at hr - have hwt : w ∈ t := by - simpa [Finset.mem_filter, t] using ⟨hws, hs ▸ hr⟩ - have hwF : r ∈ F := by - have : r ∈ hull R {r} := by simp - exact hrF.le this - have hwF : w ∈ F := by - rw [h] - exact F.smul_mem (le_of_lt hc') hwF - simp only [opt, Submodule.mem_mk, AddSubmonoid.mem_mk, AddSubsemigroup.mem_mk, Set.mem_ofPred_eq, - F] at hwF - have hgw : 0 < g w := by - have hw0 : w ≠ 0 := by - rw [h] - exact smul_ne_zero hc0 hr0 - by_contra! h - have hgw := g.mem_positive'.mp (hgC hwF.1) - have hgw' := le_antisymm hgw.1 h - have := hgw.2 hgw'.symm - absurd hxt - contradiction - have hwF := hwF.2 x hx - have : 0 ≤ f w * g x := mul_nonneg (hf' w hwt) (g.mem_positive'.mp (hgC hx)).1 - have : f x * g w < 0 := mul_neg_of_neg_of_pos hf hgw - linarith + -- the weight-one slice of `C` is nonempty + obtain ⟨y, hyC, hy0⟩ := Submodule.exists_mem_ne_zero_of_ne_bot hbot + have hgy : 0 < g y := by + obtain ⟨h1, h2⟩ := LinearMap.mem_positive'.mp (hgC hyC) + exact lt_of_le_of_ne h1 fun h => hy0 (h2 h.symm) + have : Nonempty g.weightOneHyperplane := + ⟨⟨(g y)⁻¹ • y, by simp [inv_mul_cancel₀ hgy.ne', LinearMap.weightOneHyperplane]⟩⟩ + -- view `C` as the homogenization of its weight-one slice + let : ConvexSpace R M := ConvexSpace.ofModule + let := ConvexSpace.ofAddTorsor (R := R) (P := g.weightOneHyperplane) + have hCP : ConvexSet.homogenize M (ConvexSet.dehomogenize g.weightOneHyperplane C) = C := + homogenize_dehomogenize_of_le_positive hgC + -- the slice is a polytope; apply the Krein-Milman theorem for polytopes + have hP : IsPolytope R ((ConvexSet.dehomogenize g.weightOneHyperplane C : ConvexSet R _) : + Set g.weightOneHyperplane) := by + rw [IsPolytope.iff_homogenize_fg (W := M), hCP] + exact hfg + obtain ⟨s, hs, hface⟩ := IsPolytope.krein_milman hP + refine ⟨s.image (IsHomogenization.ofWeight g).ofPoint, ?_, ?_⟩ + · rw [Finset.coe_image, hull_image_ofPoint_eq_homogenize_convexHull, hs, hCP] + · intro x hx + obtain ⟨q, hq, rfl⟩ := Finset.mem_image.mp hx + have h := homogenize_isFaceOf (W := M) (hface q hq) + rwa [homogenize_singleton, hCP] at h end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean new file mode 100644 index 00000000..c6dd069e --- /dev/null +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean @@ -0,0 +1,94 @@ +/- +Copyright (c) 2026 Mortiz Firschinggit , Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mortiz Firsching +-/ +module + +public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Finite.Face.Basic +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Module +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Basic +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Homogenization + +/-! In this file we prove the Krein-Milman theorem for polytopes: every polytope is the convex +hull of its vertices, that is, of the finite set of points whose singletons are faces. + +The proof is independent of the Krein-Milman theorem for FG cones +(`PointedCone.FG.krein_milman`); the cone version is instead derived from the present theorem +by slicing a salient cone at weight one. The key step here shows that a generator outside the +convex hull of the remaining generators spans a singleton face; this is obtained from the +cone-side lemma `PointedCone.span_singleton_isFaceOf_sup_singleton_of_not_mem` via +homogenization. -/ + +@[expose] public section + +variable {R V A : Type*} + +open Convexity ConvexSet Affine Affine.IsHomogenization PointedCone + +section Field + +variable [Field R] [LinearOrder R] [IsStrictOrderedRing R] [ConvexSpace R A] +variable [AddCommGroup V] [Module R V] +variable [AddTorsor V A] [IsAffineConvexSpace R V A] + +variable {P : ConvexSet R A} + +include V in +/-- If a point `x` does not lie in the convex hull of a set `s`, then the singleton of `x` is +a face of the convex hull of `insert x s`. -/ +lemma IsFaceOf.singleton_convexHull_insert {s : Set A} {x : A} + (hx : x ∉ ConvexSet.convexHull R s) : + IsFaceOf {x} (ConvexSet.convexHull R (insert x s)) := by + let W := Homogenization R A + let : ConvexSpace R W := ConvexSpace.ofModule + let : IsModuleConvexSpace R W := IsModuleConvexSpace.ofModule + let hom : IsHomogenization R A W := IsHomogenization.canonical R A + have hhom : homogenize W (ConvexSet.convexHull R (insert x s)) = + PointedCone.hull R (hom.ofPoint '' s) ⊔ (R ∙₊ hom.ofPoint x) := by + rw [← hull_image_ofPoint_eq_homogenize_convexHull (W := W), Set.image_insert_eq, hull_insert, + sup_comm] + have hnot : hom.ofPoint x ∉ PointedCone.hull R (hom.ofPoint '' s) := by + rw [hull_image_ofPoint_eq_homogenize_convexHull (W := W)] + exact fun h => hx ((ofPoint_mem_homogenize_iff_mem W x _).mp h) + have hsal : (PointedCone.hull R (hom.ofPoint '' s) ⊔ (R ∙₊ hom.ofPoint x)).Salient := + hhom ▸ homogenize_salient + have hface := span_singleton_isFaceOf_sup_singleton_of_not_mem hnot hsal + rw [← hhom] at hface + have h := dehomogenize_isFaceOf A hface + rwa [dehomogenize_homogenize, dehomogenize_hull_singleton_ofPoint] at h + +include V +/-- Krein-Milman theorem for polytopes: every polytope is the convex hull of its vertices, +that is, of the finite set of points whose singletons are faces. -/ +theorem IsPolytope.krein_milman (hP : IsPolytope R (P : Set A)) : + ∃ s : Finset A, ConvexSet.convexHull R (s : Set A) = P ∧ ∀ x ∈ s, IsFaceOf {x} P := by + classical + suffices h : ∀ t : Finset A, ∀ P : ConvexSet R A, ConvexSet.convexHull R (t : Set A) = P → + ∃ s : Finset A, ConvexSet.convexHull R (s : Set A) = P ∧ ∀ x ∈ s, IsFaceOf {x} P by + obtain ⟨t, ht⟩ := hP + exact h t P (SetLike.ext' ht.symm) + intro t + induction t using Finset.strongInduction with + | _ t ih => + intro P hP + by_cases hex : ∃ x ∈ t, x ∈ ConvexSet.convexHull R ((t.erase x : Finset A) : Set A) + · -- a redundant generator can be dropped and the induction hypothesis applies + obtain ⟨x, hxt, hx⟩ := hex + refine ih (t.erase x) (Finset.erase_ssubset hxt) P ?_ + rw [← hP] + apply SetLike.ext' + refine subset_antisymm + (convexHull_mono (Finset.coe_subset.mpr (Finset.erase_subset x t))) ?_ + refine (IsConvexSet.convexHull_subset_iff IsConvexSet.convexHull).mpr ?_ + intro y hy + rcases eq_or_ne y x with rfl | hne + · exact hx + · exact subset_convexHull_self (Finset.mem_coe.mpr (Finset.mem_erase.mpr ⟨hne, hy⟩)) + · -- otherwise every generator is a vertex + push Not at hex + refine ⟨t, hP, fun x hxt => ?_⟩ + have h := IsFaceOf.singleton_convexHull_insert (hex x hxt) + rwa [← Finset.coe_insert, Finset.insert_erase hxt, hP] at h + +end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 3da7d2c8..590d2274 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -152,7 +152,13 @@ variable [IsModuleConvexSpace R W] variable [hom : Affine.IsHomogenization R A W] -omit [IsModuleConvexSpace R W] in +omit [IsModuleConvexSpace R W] [ConvexSpace R W] [IsAffineConvexSpace R V A] in +@[simp] lemma homogenize_singleton (p : A) : + homogenize W ({p} : ConvexSet R A) = R ∙₊ hom.ofPoint p := by + have h : (({p} : ConvexSet R A) : Set A) = {p} := rfl + rw [homogenize, h, Set.image_singleton] + +omit [IsModuleConvexSpace R W] [ConvexSpace R W] [IsAffineConvexSpace R V A] in /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ lemma homogenize_top : homogenize W (⊤ : ConvexSet R A) = hom.weight.positive := by rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton hom.weight one_pos, @@ -165,6 +171,21 @@ lemma smul_pos_of_mem_homogenize {P : ConvexSet R A} {x} (h : x ∈ homogenize W (mem_hull_iff_mem_pos_smul_of_convex_nonzero (P.isConvexSet.image hom.ofPoint.isAffineMap) hx).mp h +@[simp] lemma dehomogenize_hull_singleton_ofPoint (p : A) : + dehomogenize A (R ∙₊ hom.ofPoint p) = ({p} : ConvexSet R A) := by + ext q + constructor + · intro hq + have hq' : hom.ofPoint q ∈ R ∙₊ hom.ofPoint p := hq + simp only [Submodule.mem_span_singleton, Subtype.exists, Nonneg.mk_smul, exists_prop] at hq' + obtain ⟨c, -, hc⟩ := hq' + have hw := congrArg hom.weight hc + simp only [map_smul, hom.weight_one, smul_eq_mul, mul_one] at hw + rw [hw, one_smul] at hc + exact hom.ofPoint_injective hc ▸ rfl + · rintro rfl + exact subset_hull rfl + -- TODO: This lemma should be proven for general sets (homogenizing to SubMulAction) and then -- applied here as a special case. variable (W) in diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index 3b585afd..3ee79ef5 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -64,6 +64,25 @@ noncomputable instance IsHomogenization.canonical : simp · exact fun hx ↦ (Homogenization.weight_eq_one_iff.mp hx).imp fun _ hp ↦ hp.symm +section weightOneHyperplane + +/-- The weight-one affine hyperplane of a linear functional. -/ +def _root_.LinearMap.weightOneHyperplane (g : W →ₗ[R] R) : AffineSubspace R W := + AffineSubspace.comap g.toAffineMap (affineSpan R {(1 : R)}) + +/-- A module is a homogenization of the weight-one hyperplane of any linear functional, +provided that hyperplane is nonempty. -/ +instance IsHomogenization.ofWeight (g : W →ₗ[R] R) [Nonempty (g.weightOneHyperplane)] : + IsHomogenization R (g.weightOneHyperplane) W where + ofPoint := g.weightOneHyperplane.subtype + ofPoint_injective := g.weightOneHyperplane.subtype_injective + weight := g + ofPoint_range_eq_preimage_weight_one := by + rw [AffineSubspace.coe_subtype, Subtype.range_coe] + simp [LinearMap.weightOneHyperplane] + +end weightOneHyperplane + namespace IsHomogenization variable [hom : IsHomogenization R A W] From f1bb7d6fff34dfe651d423050cf0f35978422f68 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 9 Sep 2026 18:00:54 +0200 Subject: [PATCH 02/39] making IsHomogenization a struct --- .../Convex/ConvexSpace/Homogenization.lean | 5 +- .../Convex/ConvexSpace/Polytope/Face.lean | 19 +- .../ConvexSpace/Polytope/Homogenization.lean | 16 +- .../ConvexSpace/Set/Face/Homogenization.lean | 28 +-- .../ConvexSpace/Set/Homogenization.lean | 99 +++++---- .../AffineSpace/Homogenization/Basic.lean | 27 ++- .../AffineSpace/Homogenization/Set.lean | 188 +++++++++--------- 7 files changed, 189 insertions(+), 193 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean index a09a861c..1c67ff1c 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean @@ -24,7 +24,7 @@ variable {R : Type*} [Ring R] [PartialOrder R] [IsStrictOrderedRing R] variable {V : Type*} [AddCommGroup V] [Module R V] variable {A : Type*} [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable {W : Type*} [AddCommGroup W] [Module R W] [ConvexSpace R W] -variable [hom : Affine.IsHomogenization R A W] +variable {hom : Affine.IsHomogenization R A W} section Module @@ -75,9 +75,10 @@ theorem preimage_hull_eq_convexHull_preimage {s : Set W} (hs : s ⊆ Set.range h rw [hom.ofPoint.isAffineMap.image_convexHull, Set.image_preimage_eq_iff.mpr hs] exact (hull R s).isConvexSet.convexHull_subset_iff.mpr subset_hull +variable (hom) in /-- The homogenization embedding of the convex hull of a set is contained in the hull of the embedding of the set. -/ -theorem preimage_hull_eq_convexHull_preimagke {s : Set A} : +theorem image_hull_eq_convexHull_image {s : Set A} : hom.ofPoint '' Convexity.convexHull R s ⊆ hull R (hom.ofPoint '' s) := by apply Set.image_subset_iff.mp rw [hom.ofPoint.isAffineMap.image_convexHull] diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 518a7dbe..0bc19c89 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -32,11 +32,9 @@ include V in /-- Faces of polytopes are polytopes. -/ theorem IsPolytope.face_isPolytope (hC : IsPolytope R (C : Set A)) (hF : IsFaceOf F C) : IsPolytope R (F : Set A) := by - let W := Homogenization R A - let : ConvexSpace R W := ConvexSpace.ofModule - have homC := IsPolytope.homogenize_fg (W := W) hC - have homF := IsHomogenization.homogenize_isFaceOf (W := W) hF - have := PointedCone.IsFaceOf.fg homC homF + let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule + have homF := (IsHomogenization.canonical R A).homogenize_isFaceOf hF + have := PointedCone.IsFaceOf.fg (IsPolytope.homogenize_fg _ hC) homF convert FG.dehomogenize_isPolytope this (fun _ a b ↦ weight_pos_of_mem_homogenize a b) simp [dehomogenize_homogenize] @@ -52,13 +50,12 @@ This is private since it does not yet have the correct grading (off-by-one). -/ private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polytope R A) : GradeOrder ℕ (Face (P : ConvexSet R A)) := by - let W := Homogenization R A - letI : ConvexSpace R W := ConvexSpace.ofModule - have : PointedCone.FG (homogenize W (P : ConvexSet R A)) := - IsPolytope.homogenize_fg (W := W) P.isPolytope + let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule + have : PointedCone.FG (homogenize _ (P : ConvexSet R A)) := + IsPolytope.homogenize_fg (IsHomogenization.canonical R A) P.isPolytope let := PointedCone.FG.gradeOrder_finrank this - refine GradeOrder.liftRight (β := (homogenize W (P : ConvexSet R A)).Face) _ - IsHomogenization.Face.homogenizeIso.strictMono ?_ + refine GradeOrder.liftRight _ + (IsHomogenization.Face.homogenizeIso (IsHomogenization.canonical R A) _).strictMono ?_ exact fun x y ↦ (apply_covBy_apply_iff _).mpr end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean index 1f1930d8..dc8afffa 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean @@ -28,16 +28,16 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) open PointedCone /-- The homogenization of a polytope is a finitely generated cone. -/ theorem IsPolytope.homogenize_fg {C : ConvexSet R A} (hCfg : IsPolytope R (C : Set A)) : - (homogenize W C).FG := by + (homogenize hom C).FG := by obtain ⟨t, ht⟩ := hCfg have : C = ⟨convexHull R t, IsConvexSet.convexHull⟩ := SetLike.ext' ht - have := congrArg (ConvexSet.homogenize W) this + have := congrArg (ConvexSet.homogenize hom) this rw [this] use t.map ⟨_, hom.ofPoint_injective⟩ simp only [Finset.coe_map, Function.Embedding.coeFn_mk, homogenize, @@ -47,8 +47,8 @@ theorem IsPolytope.homogenize_fg {C : ConvexSet R A} (hCfg : IsPolytope R (C : S /-- A convex set is a polytope iff its homogenization is a finitely generated cone. -/ theorem IsPolytope.iff_homogenize_fg {C : ConvexSet R A} : - IsPolytope R (C : Set A) ↔ (homogenize W C).FG := by classical - refine ⟨homogenize_fg, fun hfg ↦ ?_⟩ + IsPolytope R (C : Set A) ↔ (homogenize hom C).FG := by classical + refine ⟨homogenize_fg _, fun hfg ↦ ?_⟩ -- get cone generators that lie in the embedding of A obtain ⟨g, hg, hs⟩ := homogenize_fg_ofPoint_range hfg -- un-embed them @@ -80,13 +80,13 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable [hom : IsHomogenization R A W] +variable {hom : IsHomogenization R A W} open Pointwise Submodule in /-- Dehomogenizing a finitely generated positive cone yields a polytope. -/ theorem FG.dehomogenize_isPolytope {C : PointedCone R W} (h : C.FG) - (hc : C ≤ hom.weight.positive) : IsPolytope R (dehomogenize A C : Set A) := by - rw [IsPolytope.iff_homogenize_fg (W := W)] + (hc : C ≤ hom.weight.positive) : IsPolytope R (dehomogenize hom C : Set A) := by + rw [IsPolytope.iff_homogenize_fg hom] simpa [homogenize_dehomogenize_of_le_positive hc] end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean index 77cff520..1febd22a 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean @@ -28,8 +28,9 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable [hom : Affine.IsHomogenization R A W] +variable (hom : Affine.IsHomogenization R A W) +variable {hom} in /-- If the homogenization of a point `q` is a positive combination of the homogenization of two other points, then `q` lies in the open segment between them. -/ theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} @@ -48,11 +49,11 @@ theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} /-- If `F` is a face of `P`, then the homogenization of `F` is a face of the homogenization of `P`. -/ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : - (F.homogenize W).IsFaceOf (P.homogenize W) where - le := homogenizeOrderHom.monotone' he.le + (F.homogenize hom).IsFaceOf (P.homogenize hom) where + le := (homogenizeOrderHom hom).monotone' he.le mem_of_smul_add_mem := by intro v w a hv hw ha hvw - have hhom : (P.homogenize W).Salient := homogenize_salient + have hhom := homogenize_salient hom P by_cases hnf : (F : Set A).Nonempty · have cF := F.isConvexSet.image hom.ofPoint.isAffineMap apply (Set.ext_iff.mp (PointedCone.hull_eq_smul (hnf.image _) cF) _).mpr @@ -72,11 +73,11 @@ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : obtain ⟨rv, rv0, _, ⟨p', pp, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hv hv0 have : a • (rv • hom.ofPoint p') + (rw • hom.ofPoint q') ≠ 0 := by intro hc - exact (smul_ne_zero rw0.ne.symm (ofPoint_ne_zero q')) <| + exact (smul_ne_zero rw0.ne.symm (hom.ofPoint_ne_zero q')) <| hhom _ hw _ (PointedCone.smul_mem _ ha.le hv) (by simpa [add_comm] using hc) obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := smul_pos_of_mem_homogenize hvw this have := he.left_mem_of_mem_openSegment pp qq qqp ?_ - · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem ofPoint this⟩ + · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem hom.ofPoint this⟩ rw [← smul_assoc _ rv] at pdp exact pos_combo_openSegment (smul_pos ha rv0) rw0 rvw0 pdp.symm · have := not_nonempty_iff_eq_empty.mp hnf @@ -89,11 +90,10 @@ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : rw [this] exact PointedCone.smul_mem _ (by positivity) hw) (add_neg_cancel v) -variable (A) in /-- If `F` is a face of `C`, then the dehomogenization of `F` is a face of the dehomogenization of `C`. -/ theorem dehomogenize_isFaceOf {F C : PointedCone R W} (hf : F.IsFaceOf C) : - (ConvexSet.dehomogenize A F).IsFaceOf (ConvexSet.dehomogenize A C) where + (ConvexSet.dehomogenize hom F).IsFaceOf (ConvexSet.dehomogenize hom C) where le := preimage_mono (fun _ x ↦ hf.le x) left_mem_of_mem_openSegment := by rintro x hx y hy z hz ⟨a, b, ha, hb, hab, hzo⟩ @@ -107,16 +107,16 @@ its homogenization cone. This isomorphism is used to translate results between face lattices of cones and face lattices of convex sets. -/ -def Face.homogenizeIso {P : ConvexSet R A} : - Face P ≃o PointedCone.Face (P.homogenize W) where +def Face.homogenizeIso (P : ConvexSet R A) : + Face P ≃o PointedCone.Face (P.homogenize hom) where toFun F := ⟨_, hom.homogenize_isFaceOf F.isFaceOf⟩ - invFun F := ⟨dehomogenize A F.toSubmodule, - by simpa [dehomogenize_homogenize] using dehomogenize_isFaceOf A F.isFaceOf⟩ + invFun F := ⟨dehomogenize hom F.toSubmodule, + by simpa [dehomogenize_homogenize hom] using dehomogenize_isFaceOf hom F.isFaceOf⟩ map_rel_iff' := by intro a b refine ⟨fun h x xm ↦ ?_, fun h _ xm ↦ span_mono (image_mono h) xm⟩ - refine (ofPoint_mem_homogenize_iff_mem W x b.toConvexSet).mp (h ?_) - exact (ofPoint_mem_homogenize_iff_mem W x a.toConvexSet).mpr xm + refine (ofPoint_mem_homogenize_iff_mem _ x b.toConvexSet).mp (h ?_) + exact (ofPoint_mem_homogenize_iff_mem _ x a.toConvexSet).mpr xm left_inv _ := by simp [dehomogenize_homogenize] right_inv F := by have := homogenize_dehomogenize_of_le_positive diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 3da7d2c8..c289677b 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -31,50 +31,52 @@ variable [AddCommGroup V] [Module R V] variable [AddCommGroup W] [Module R W] variable [AddTorsor V A] [ConvexSpace R A] -variable [hom : Affine.IsHomogenization R A W] +variable (hom : Affine.IsHomogenization R A W) -variable (W) in /-- The homogenization cone of a convex set in an affine space. -/ def homogenize (P : ConvexSet R A) : PointedCone R W := hull R (hom.ofPoint '' P) lemma homogenize_mono {K₁ K₂ : ConvexSet R A} (h : K₁ ≤ K₂) : - K₁.homogenize W ≤ K₂.homogenize W := Submodule.span_mono <| Set.image_mono h + K₁.homogenize hom ≤ K₂.homogenize hom := Submodule.span_mono <| Set.image_mono h -lemma homogenize_monotone : Monotone (homogenize W : ConvexSet R A → PointedCone R W) := - fun _ _ => homogenize_mono +lemma homogenize_monotone : Monotone (homogenize hom : ConvexSet R A → PointedCone R W) := + fun _ _ => homogenize_mono _ /-- Homogenization from convex set to convex cones as an order homomorphism. -/ def homogenizeOrderHom : ConvexSet R A →o PointedCone R W where - toFun := homogenize W - monotone' := homogenize_monotone + toFun := homogenize hom + monotone' := homogenize_monotone _ -lemma homogenize_bot : homogenize W (⊥ : ConvexSet R A) = ⊥ := by +lemma homogenize_bot : homogenize hom (⊥ : ConvexSet R A) = ⊥ := by simp [homogenize, Bot.bot] -/- NOTE: `homogenize_top`, stating `homogenize W (⊤ : ConvexSet R A) = hom.weight.positive`, +/- NOTE: `homogenize_top`, stating `homogenize hom (⊤ : ConvexSet R A) = hom.weight.positive`, only holds over linearly ordered fields and is proven in the `Field` section below. Over a general ordered ring it fails: for `R = ℤ[ε]` with `ε` a positive infinitesimal, the point `(1, ε)` lies in `weight.positive` but not in the cone hull of the weight-one hyperplane, since all nonnegative coefficients bounded by `ε` lie in the ideal `(ε)`. -/ lemma homogenize_le_weight_positive (K : ConvexSet R A) : - homogenize W K ≤ hom.weight.positive := by + homogenize hom K ≤ hom.weight.positive := by exact LinearMap.hull_le_positive_of_subset_preimage_singleton one_pos fun _ ↦ by rintro ⟨x, -, rfl⟩ simp [hom.weight_one] -lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize W P) (hx : x ≠ 0) : - 0 < hom.weight x := homogenize_le_weight_positive P h hx +variable {hom} in +lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize hom P) (hx : x ≠ 0) : + 0 < hom.weight x := homogenize_le_weight_positive _ P h hx -lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ homogenize W P) : +variable {hom} in +lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ homogenize hom P) : 0 ≤ hom.weight x := - (LinearMap.mem_positive'.mp (homogenize_le_weight_positive (W := W) P h)).1 + (LinearMap.mem_positive'.mp (homogenize_le_weight_positive _ P h)).1 -lemma homogenize_salient {K : ConvexSet R A} : PointedCone.Salient (homogenize W K) := - Salient.of_le_salient hom.weight.positive_salient (homogenize_le_weight_positive K) +lemma homogenize_salient (K : ConvexSet R A) : PointedCone.Salient (homogenize hom K) := + Salient.of_le_salient hom.weight.positive_salient (homogenize_le_weight_positive _ K) -theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize W C).FG) : - ∃ g : Finset W, PointedCone.hull R g = homogenize W C ∧ +variable {hom} in +theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize hom C).FG) : + ∃ g : Finset W, PointedCone.hull R g = homogenize hom C ∧ (g : Set W) ⊆ Set.range hom.ofPoint := by obtain ⟨g, hg⟩ := h -- express each generator as a positive combo of stuff in the embedding of C @@ -98,30 +100,27 @@ section Module variable [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] -variable (A) in def dehomogenize (C : PointedCone R W) : ConvexSet R A := ⟨_, C.isConvexSet.preimage hom.ofPoint.isAffineMap⟩ alias _root_.PointedCone.dehomogenize := dehomogenize -lemma dehomogenize_bot : dehomogenize A (⊥ : PointedCone R W) = ⊥ := sorry +lemma dehomogenize_bot : dehomogenize hom (⊥ : PointedCone R W) = ⊥ := sorry -lemma dehomogenize_top : dehomogenize A (⊤ : PointedCone R W) = ⊤ := sorry +lemma dehomogenize_top : dehomogenize hom (⊤ : PointedCone R W) = ⊤ := sorry -lemma dehomogenize_weight_positive : dehomogenize A hom.weight.positive = ⊤ := sorry +lemma dehomogenize_weight_positive : dehomogenize hom hom.weight.positive = ⊤ := sorry -variable (A) in lemma dehomogenize_mono {C₁ C₂ : PointedCone R W} (h : C₁ ≤ C₂) : - dehomogenize A C₁ ≤ dehomogenize A C₂ := Set.preimage_mono <| Set.preimage_mono h + dehomogenize hom C₁ ≤ dehomogenize hom C₂ := Set.preimage_mono <| Set.preimage_mono h -- Q: why Set.preimage_mono twice? -variable (A) in -lemma dehomogenize_monotone : Monotone (dehomogenize A : PointedCone R W → ConvexSet R A) := - fun _ _ => dehomogenize_mono A +lemma dehomogenize_monotone : Monotone (dehomogenize hom : PointedCone R W → ConvexSet R A) := + fun _ _ => dehomogenize_mono _ -- This lemma is just `Set.image_preimage_eq_inter_range` in disguise. It is likely not needed. lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : - hom.ofPoint '' dehomogenize A C = (C : Set W) ∩ hom.ofPoint.range := by + hom.ofPoint '' dehomogenize hom C = (C : Set W) ∩ hom.ofPoint.range := by ext x simp only [Set.mem_image, SetLike.mem_coe, Set.mem_inter_iff, AffineMap.mem_range] constructor @@ -134,7 +133,7 @@ lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : /-- The preimage of the conic hull of a set in the homogenization plane is the convex hull of the preimage of the set. -/ theorem hull_image_ofPoint_eq_homogenize_convexHull {s : Set A} : - hull R (hom.ofPoint '' s) = homogenize W (ConvexSet.convexHull R s) := by + hull R (hom.ofPoint '' s) = homogenize hom (ConvexSet.convexHull R s) := by simp [homogenize, ConvexSet.convexHull, hom.ofPoint.isAffineMap.image_convexHull] end Module @@ -145,31 +144,30 @@ section Field variable [Field R] [LinearOrder R] [IsOrderedRing R] variable [AddCommGroup V] [Module R V] -variable [AddCommGroup W] [Module R W] [ConvexSpace R W] -variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] - -variable [IsModuleConvexSpace R W] +variable [AddCommGroup W] [Module R W] +variable [AddTorsor V A] [ConvexSpace R A] -variable [hom : Affine.IsHomogenization R A W] +variable (hom : Affine.IsHomogenization R A W) -omit [IsModuleConvexSpace R W] in /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ -lemma homogenize_top : homogenize W (⊤ : ConvexSet R A) = hom.weight.positive := by +lemma homogenize_top : homogenize hom (⊤ : ConvexSet R A) = hom.weight.positive := by rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton hom.weight one_pos, ← hom.ofPoint_range_eq_preimage_weight_one] congr! with x simp -lemma smul_pos_of_mem_homogenize {P : ConvexSet R A} {x} (h : x ∈ homogenize W P) (hx : x ≠ 0) : +variable [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] + +variable {hom} in +lemma smul_pos_of_mem_homogenize {P : ConvexSet R A} {x} (h : x ∈ homogenize hom P) (hx : x ≠ 0) : x ∈ Set.Ioi (0 : R) • hom.ofPoint '' (P : Set A) := (mem_hull_iff_mem_pos_smul_of_convex_nonzero (P.isConvexSet.image hom.ofPoint.isAffineMap) hx).mp h -- TODO: This lemma should be proven for general sets (homogenizing to SubMulAction) and then -- applied here as a special case. -variable (W) in lemma ofPoint_mem_homogenize_iff_mem (x : A) (P : ConvexSet R A) : - hom.ofPoint x ∈ homogenize W P ↔ x ∈ P := by + hom.ofPoint x ∈ homogenize hom P ↔ x ∈ P := by refine ⟨fun h ↦ ?_, fun h ↦ mem_span_of_mem (Set.mem_image_of_mem hom.ofPoint h)⟩ obtain ⟨_, _, h'⟩ := smul_pos_of_mem_homogenize (Set.mem_preimage.mpr h) (hom.ofPoint_ne_zero x) obtain ⟨_, ⟨_, _, hyy'⟩, hy'⟩ := Set.mem_smul_set.mp h' @@ -181,19 +179,20 @@ lemma ofPoint_mem_homogenize_iff_mem (x : A) (P : ConvexSet R A) : /-- Dehomogenizing the homogenization of a convex set yields the same set again. -/ @[simp] theorem dehomogenize_homogenize (P : ConvexSet R A) : - dehomogenize A (homogenize W P) = P := by + dehomogenize hom (homogenize hom P) = P := by ext x; exact ofPoint_mem_homogenize_iff_mem _ _ _ -lemma homogenize_injective : Function.Injective (homogenize (hom := hom) W) := by +lemma homogenize_injective : Function.Injective (homogenize hom) := by intro P Q h - have hh := congr_arg (ConvexSet.dehomogenize A) h + have hh := congr_arg (ConvexSet.dehomogenize hom) h simp [dehomogenize_homogenize] at hh assumption +variable {hom} in /-- If the entire cone save the origin are at positive weight, homogenizing the dehomogenization of the homogenize yields the cone again. -/ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} - (hC : C ≤ hom.weight.positive) : homogenize W (dehomogenize A C) = C := by + (hC : C ≤ hom.weight.positive) : homogenize hom (dehomogenize hom C) = C := by by_cases hbot : C = ⊥ · simp [hbot, homogenize, dehomogenize] · apply SetLike.ext' @@ -212,19 +211,19 @@ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} · exact C.isConvexSet.inter hom.ofPoint.range_isConvexSet lemma homogenize_mono_iff {K₁ K₂ : ConvexSet R A} : - K₁.homogenize W ≤ K₂.homogenize W ↔ K₁ ≤ K₂ where - mp h := by simpa using dehomogenize_mono A h - mpr := homogenize_mono + K₁.homogenize hom ≤ K₂.homogenize hom ↔ K₁ ≤ K₂ where + mp h := by simpa using dehomogenize_mono hom h + mpr := homogenize_mono _ -- Issue #66 /-- The lattice of convex sets is isomorphic to the lattice of convex sub-cones of the positive cone. -/ def homogenizeOrderEquiv : ConvexSet R A ≃o Set.Iic hom.weight.positive where - toFun K := ⟨_, K.homogenize_le_weight_positive⟩ - invFun C := dehomogenize A C.1 - left_inv K := dehomogenize_homogenize K + toFun K := ⟨_, K.homogenize_le_weight_positive _⟩ + invFun C := dehomogenize hom C.1 + left_inv K := dehomogenize_homogenize _ K right_inv C := by dsimp; congr; exact homogenize_dehomogenize_of_le_positive C.2 - map_rel_iff' := homogenize_mono_iff + map_rel_iff' := homogenize_mono_iff _ end Field diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index 3b585afd..5f2a6fd0 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -44,7 +44,7 @@ variable (R A W) in weight-1 hyperplane under a given linear weight map. Follows Definition 4.2 in [Gallier2011GeometricMethods] https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -class IsHomogenization where +structure IsHomogenization where ofPoint : A →ᵃ[R] W ofPoint_injective : Injective ofPoint weight : W →ₗ[R] R @@ -52,7 +52,7 @@ class IsHomogenization where variable (R A) in /-- The canonical homogenization is a homogenization. -/ -noncomputable instance IsHomogenization.canonical : +noncomputable def IsHomogenization.canonical : IsHomogenization R A (Homogenization R A) where ofPoint := Homogenization.ofPoint ofPoint_injective := Homogenization.ofPoint_injective @@ -66,7 +66,7 @@ noncomputable instance IsHomogenization.canonical : namespace IsHomogenization -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) abbrev ofVector := hom.ofPoint.linear @@ -85,7 +85,7 @@ theorem ofVector_range_eq_weight_ker : hom.ofVector.range = hom.weight.ker := by constructor · rintro ⟨a, b, hab⟩ simp only [Set.mem_preimage, Set.mem_singleton_iff] at hh - simp [← hab, map_sub, (hh (ofPoint b)).mp ⟨b, rfl⟩, (hh (ofPoint a)).mp ⟨a, rfl⟩] + simp [← hab, map_sub, (hh (hom.ofPoint b)).mp ⟨b, rfl⟩, (hh (hom.ofPoint a)).mp ⟨a, rfl⟩] · intro h have ha := Set.mem_preimage.mp <| (hh (hom.ofPoint a₀)).mp (by simp) obtain ⟨b, hb⟩ : x + hom.ofPoint a₀ ∈ (Set.range hom.ofPoint) := by @@ -101,7 +101,7 @@ variable [Nontrivial R] in theorem ofPoint_ne_zero (x : A) : hom.ofPoint x ≠ (0 : W) := by intro hn have := congrArg hom.weight hn - simp [weight_one x] at this + simp [hom.weight_one x] at this /-- The homogenization of a point in `V` has weight 0. -/ lemma weight_zero (v : V) : hom.weight (hom.ofVector v) = 0 := by @@ -113,7 +113,7 @@ theorem span_range_ofPoint : span R (Set.range hom.ofPoint) = ⊤ := by -- projecting x to weight 0 along a₀ gives sth in the span of image of ofPoint have hlin : x - hom.weight x • hom.ofPoint a₀ ∈ Submodule.span R hom.ofPoint.range := by obtain ⟨v, hv⟩ : x - hom.weight x • hom.ofPoint a₀ ∈ hom.ofVector.range := by - simp [ofVector_range_eq_weight_ker, weight_one a₀] + simp [ofVector_range_eq_weight_ker, hom.weight_one a₀] have : hom.ofVector v = hom.ofPoint (v +ᵥ a₀) - hom.ofPoint a₀ := by simp rw [← hv, this] apply Submodule.sub_mem <;> apply Submodule.subset_span @@ -122,7 +122,6 @@ theorem span_range_ofPoint : span R (Set.range hom.ofPoint) = ⊤ := by simpa using Submodule.add_mem _ hlin <| smul_mem _ (hom.weight x) (subset_span ⟨a₀, rfl⟩) -variable (hom) in /-- The canonical linear map from `Homogenization R A` to any homogenization `W` of `A`. -/ noncomputable def ofCanonical : Homogenization R A →ₗ[R] W := Homogenization.lift hom.ofPoint @@ -147,7 +146,7 @@ theorem ofCanonical_bijective : Bijective hom.ofCanonical := by · rw [injective_iff_map_eq_zero] intro x hx have hw : Homogenization.weight x = 0 := by - rw [← weight_ofCanonical (W := W) x, hx, map_zero] + rw [← hom.weight_ofCanonical x, hx, map_zero] obtain ⟨v, rfl⟩ := Homogenization.weight_eq_zero_iff.mp hw rw [ofCanonical_ofVector, map_eq_zero_iff _ hom.ofVector_injective] at hx simp [hx] @@ -176,7 +175,7 @@ theorem canonEquiv_canonical_ofPoint : theorem weight_canonEquiv : Homogenization.weight ∘ hom.canonEquiv = hom.weight := by ext x - rw [Function.comp_apply, ← weight_ofCanonical (W := W) (hom.canonEquiv x), + rw [Function.comp_apply, ← hom.weight_ofCanonical (hom.canonEquiv x), ofCanonical_canonEquiv] -- proving the universal property using the equiv @@ -199,9 +198,9 @@ noncomputable def ofVectorRangeEquiv : V ≃ₗ[R] hom.ofVector.range := { map_add' v w := by simp map_smul' r v := by simp invFun := - (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr ofPoint_injective)).invFun + (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr hom.ofPoint_injective)).invFun left_inv := - (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr ofPoint_injective)).left_inv + (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr hom.ofPoint_injective)).left_inv right_inv v' := by simp } @@ -211,9 +210,9 @@ public noncomputable def ofPointRangeEquiv : A ≃ᵃ[R] hom.ofPoint.range := ⟨hom.ofPoint.rangeRestrict_injective_iff.mpr hom.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ lemma apply_ofPointRangeEquiv_symm (x : hom.ofPoint.range) : - hom.ofPoint (ofPointRangeEquiv.symm x) = x := by - rw [← ofPointRangeEquiv.right_inv x] - congr; exact ofPointRangeEquiv.symm_apply_apply _ + hom.ofPoint (hom.ofPointRangeEquiv.symm x) = x := by + rw [← hom.ofPointRangeEquiv.right_inv x] + congr; exact hom.ofPointRangeEquiv.symm_apply_apply _ end IsHomogenization diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index 21ad49f3..91afe4e1 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -34,84 +34,84 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) variable {x : A} {s : Set A} -variable (R W) in def homogenize (s : Set A) : SubMulAction₀ R≥0 W := R≥0 ∙ (hom.ofPoint '' s) -- potential notations for homogenization: `R≥0 ∙[W] s` or `R ∙₊[W] s` -- -- /- Note that the character `∙` U+2219 used below is different from the scalar multiplication -- character `•` U+2022. -/ --- /-- Notation for the homogenizationof a set `s`, short for `homogenize R W s`. -/ --- scoped notation:70 R:70 " ∙[" W "] " s:70 => homogenize R W s +-- /-- Notation for the homogenizationof a set `s`, short for `homogenize hom s`. -/ +-- scoped notation:70 R:70 " ∙[" W "] " s:70 => homogenize hom s lemma mem_homogenize {s : Set A} {x : W} : - x ∈ homogenize R W s ↔ x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize hom s ↔ x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by simp [homogenize, mem_smulSet] -lemma mem_homogenize_iff_exist_lt_zero {s : Set A} {x : W} (hx : x ∈ homogenize R W s) : +variable {hom} in +lemma mem_homogenize_iff_exist_lt_zero {s : Set A} {x : W} (hx : x ∈ homogenize hom s) : x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 < r ∧ x = r • hom.ofPoint y := by obtain (rfl | ⟨y, ⟨z, hz, rfl⟩, _, ⟨r, _⟩, hr0, rfl⟩) := mem_smulSet_iff_exists_ne_zero hx · exact .inl rfl · exact .inr ⟨z, hz, r, by rwa [← zero_lt_iff] at hr0, rfl⟩ lemma mem_homogenize_iff_ne_zero {s : Set A} {x : W} (hx : x ≠ 0) : - x ∈ homogenize R W s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize hom s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by simp [homogenize, mem_smulSet_of_ne_zero hx] lemma mem_homogenize_iff_nonempty {s : Set A} {x : W} (hs : s.Nonempty) : - x ∈ homogenize R W s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize hom s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by have : (hom.ofPoint '' s).Nonempty := Set.image_nonempty.mpr hs simp [homogenize, mem_smulSet_of_nonempty this] -@[simp] lemma homogenize_empty : homogenize R W (∅ : Set A) = ⊥ := by +@[simp] lemma homogenize_empty : homogenize hom (∅ : Set A) = ⊥ := by ext x; simp [homogenize] -lemma ofPoint_image_subset_homogenize : hom.ofPoint '' s ⊆ homogenize R W s := +lemma ofPoint_image_subset_homogenize : hom.ofPoint '' s ⊆ homogenize hom s := subset_smulSet -lemma ofPoint_mem_homogenize (hx : x ∈ s) : hom.ofPoint x ∈ homogenize R W s := - ofPoint_image_subset_homogenize ⟨x, hx, rfl⟩ +lemma ofPoint_mem_homogenize (hx : x ∈ s) : hom.ofPoint x ∈ homogenize hom s := + ofPoint_image_subset_homogenize _ ⟨x, hx, rfl⟩ lemma smul_ofPoint_mem_homogenize {r : R} (hr : 0 ≤ r) (h : x ∈ s) : - r • hom.ofPoint x ∈ homogenize R W s := - smul_mem _ ⟨r, hr⟩ (ofPoint_mem_homogenize h) + r • hom.ofPoint x ∈ homogenize hom s := + smul_mem _ ⟨r, hr⟩ (ofPoint_mem_homogenize _ h) -lemma homogenize_mono {s t : Set A} (h : s ⊆ t) : homogenize R W s ≤ homogenize R W t := +lemma homogenize_mono {s t : Set A} (h : s ⊆ t) : homogenize hom s ≤ homogenize hom t := smulSet_mono <| Set.image_mono h -lemma homogenize_monotone : Monotone (homogenize R W : Set A → SubMulAction₀ R≥0 W) := - fun _ _ => homogenize_mono +lemma homogenize_monotone : Monotone (homogenize hom : Set A → SubMulAction₀ R≥0 W) := + fun _ _ => homogenize_mono _ /-- Homogenization from sets to `SubMulAction₀` as an order homomorphism. -/ def homogenizeOrderHom : Set A →o SubMulAction₀ R≥0 W where - toFun := homogenize R W - monotone' := homogenize_monotone + toFun := homogenize hom + monotone' := homogenize_monotone _ lemma homogenize_union (s t : Set A) : - homogenize R W (s ∪ t) = homogenize R W s ⊔ homogenize R W t := by + homogenize hom (s ∪ t) = homogenize hom s ⊔ homogenize hom t := by simp only [homogenize, Set.image_union, smulSet_union] lemma homogenize_inter_le (s t : Set A) : - homogenize R W (s ∩ t) ≤ homogenize R W s ⊓ homogenize R W t := by + homogenize hom (s ∩ t) ≤ homogenize hom s ⊓ homogenize hom t := by unfold homogenize rw [Set.image_inter hom.ofPoint_injective] exact smulSet_inter_le _ _ lemma homogenize_sSup (S : Set (Set A)) : - homogenize R W (sSup S) = sSup (homogenize R W '' S) := by + homogenize hom (sSup S) = sSup (homogenize hom '' S) := by unfold homogenize rw [Set.image_sSup, smulSet_sSup, Set.image_image] def homogenizeSSupHom : sSupHom (Set A) (SubMulAction₀ R≥0 W) where - toFun := homogenize R W - map_sSup' := homogenize_sSup + toFun := homogenize hom + map_sSup' := homogenize_sSup _ lemma homogenize_sInf_le (S : Set (Set A)) : - homogenize R W (sInf S) ≤ sInf (homogenize R W '' S) := by + homogenize hom (sInf S) ≤ sInf (homogenize hom '' S) := by unfold homogenize apply le_trans <| smulSet_mono (Set.image_sInter_subset_sInf_image _ _) apply le_trans (smulSet_sInf_le _) @@ -122,42 +122,42 @@ section Nontrivial variable [Nontrivial R] @[simp] lemma ofPoint_mem_homogenize_iff {x : A} {s : Set A} : - hom.ofPoint x ∈ homogenize R W s ↔ x ∈ s where + hom.ofPoint x ∈ homogenize hom s ↔ x ∈ s where mp := by rintro (h | ⟨x, ⟨y, hy, rfl⟩, r, h⟩) - · exfalso; exact ofPoint_ne_zero _ h + · exfalso; exact ofPoint_ne_zero _ _ h · have := congrArg hom.weight h simp only [weight_one, ← Nonneg.coe_smul, map_smul, smul_eq_mul, mul_one, Eq.comm, Nonneg.coe_eq_one] at this rw [this, one_smul] at h rwa [hom.ofPoint_injective h] - mpr := ofPoint_mem_homogenize + mpr := ofPoint_mem_homogenize _ lemma ofPoint_mem_homogenize_singleton {x y : A} : - hom.ofPoint x ∈ homogenize R W {y} ↔ x = y := by simp + hom.ofPoint x ∈ homogenize hom {y} ↔ x = y := by simp lemma homogenize_injective : - Injective (homogenize R W : Set A → SubMulAction₀ R≥0 W) := by + Injective (homogenize hom : Set A → SubMulAction₀ R≥0 W) := by intro s t h; ext repeat rw [← ofPoint_mem_homogenize_iff (R := R) (W := W)] rw [h] -@[simp] lemma homogenize_inj {s t : Set A} : homogenize R W s = homogenize R W t ↔ s = t := - homogenize_injective.eq_iff +@[simp] lemma homogenize_inj {s t : Set A} : homogenize hom s = homogenize hom t ↔ s = t := + (homogenize_injective _).eq_iff -lemma homogenize_strictMono : StrictMono (homogenize R W : Set A → SubMulAction₀ R≥0 W) := - homogenize_monotone.strictMono_of_injective homogenize_injective +lemma homogenize_strictMono : StrictMono (homogenize hom : Set A → SubMulAction₀ R≥0 W) := + (homogenize_monotone _).strictMono_of_injective (homogenize_injective _) lemma homogenize_mono_iff {s t : Set A} : - homogenize R W s ≤ homogenize R W t ↔ s ⊆ t where + homogenize hom s ≤ homogenize hom t ↔ s ⊆ t where mp := by intro h x hx rw [← ofPoint_mem_homogenize_iff (R := R) (W := W)] at ⊢ hx exact h hx - mpr := homogenize_mono + mpr := homogenize_mono _ lemma homogenize_singleton_eq {x y : A} : - homogenize R W {x} = homogenize R W {y} ↔ x = y := by simp + homogenize hom {x} = homogenize hom {y} ↔ x = y := by simp end Nontrivial @@ -170,44 +170,43 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) variable {x : A} {s : Set A} -variable (A) in def _root_.SubMulAction₀.dehomogenize (S : SubMulAction₀ R≥0 W) : Set A := hom.ofPoint ⁻¹' S lemma dehomogenize_mono {S T : SubMulAction₀ R≥0 W} (h : S ≤ T) : - dehomogenize A S ≤ dehomogenize A T := + dehomogenize hom S ≤ dehomogenize hom T := Set.preimage_mono h -lemma dehomogenize_monotone : Monotone (dehomogenize A : SubMulAction₀ R≥0 W → Set A) := - fun _ _ => dehomogenize_mono +lemma dehomogenize_monotone : Monotone (dehomogenize hom : SubMulAction₀ R≥0 W → Set A) := + fun _ _ => dehomogenize_mono _ /-- Homogenization from sets to `SubMulAction₀` as an order homomorphism. -/ def dehomogenizeOrderHom : SubMulAction₀ R≥0 W →o Set A where - toFun := dehomogenize A - monotone' := dehomogenize_monotone + toFun := dehomogenize hom + monotone' := dehomogenize_monotone _ -lemma dehomogenize_top : dehomogenize A (⊤ : SubMulAction₀ R≥0 W) = Set.univ := by +lemma dehomogenize_top : dehomogenize hom (⊤ : SubMulAction₀ R≥0 W) = Set.univ := by ext x; simp [dehomogenize] lemma dehomogenize_inf (s t : SubMulAction₀ R≥0 W) : - dehomogenize A (s ⊓ t) = dehomogenize A s ∩ dehomogenize A t := by + dehomogenize hom (s ⊓ t) = dehomogenize hom s ∩ dehomogenize hom t := by ext x; simp [dehomogenize] lemma dehomogenize_sup (s t : SubMulAction₀ R≥0 W) : - dehomogenize A (s ⊔ t) = dehomogenize A s ∪ dehomogenize A t := by + dehomogenize hom (s ⊔ t) = dehomogenize hom s ∪ dehomogenize hom t := by ext x; simp [dehomogenize] def dehomogenizeLatticeHom : LatticeHom (SubMulAction₀ R≥0 W) (Set A) where - toFun := dehomogenize A - map_sup' := dehomogenize_sup - map_inf' := dehomogenize_inf + toFun := dehomogenize hom + map_sup' := dehomogenize_sup _ + map_inf' := dehomogenize_inf _ lemma dehomogenize_sInf (S : Set (SubMulAction₀ R≥0 W)) : - dehomogenize A (sInf S) = sInf (dehomogenize A '' S) := by + dehomogenize hom (sInf S) = sInf (dehomogenize hom '' S) := by ext x; simp [dehomogenize] section Nontrivial @@ -215,27 +214,27 @@ section Nontrivial variable [Nontrivial R] lemma dehomogenize_sSup (S : Set (SubMulAction₀ R≥0 W)) : - dehomogenize A (sSup S) = sSup (dehomogenize A '' S) := by - ext x; simpa [dehomogenize] using fun h => (ofPoint_ne_zero x h).elim + dehomogenize hom (sSup S) = sSup (dehomogenize hom '' S) := by + ext x; simpa [dehomogenize] using fun h => (ofPoint_ne_zero _ x h).elim def dehomogenizeCompleteLatticeHom : CompleteLatticeHom (SubMulAction₀ R≥0 W) (Set A) where - toFun := dehomogenize A - map_sInf' := dehomogenize_sInf - map_sSup' := dehomogenize_sSup + toFun := dehomogenize hom + map_sInf' := dehomogenize_sInf _ + map_sSup' := dehomogenize_sSup _ -@[simp] lemma dehomogenize_bot : (⊥ : SubMulAction₀ R≥0 W).dehomogenize A = ∅ := by - ext x; simp only [Set.mem_empty_iff_false, iff_false]; exact ofPoint_ne_zero _ +@[simp] lemma dehomogenize_bot : (⊥ : SubMulAction₀ R≥0 W).dehomogenize hom = ∅ := by + ext x; simp only [Set.mem_empty_iff_false, iff_false]; exact ofPoint_ne_zero _ _ variable [IsOrderedRing R] in /-- Dehomogenizing the homogenization of a set yields the same set again. -/ @[simp] theorem dehomogenize_homogenize (s : Set A) : - dehomogenize A (homogenize R W s) = s := by + dehomogenize hom (homogenize hom s) = s := by ext x; simp [dehomogenize] end Nontrivial variable [IsOrderedRing R] in -lemma homogenize_gc : GaloisConnection (homogenize R W) (dehomogenize A) := +lemma homogenize_gc : GaloisConnection (homogenize hom) (dehomogenize hom) := .compose Set.image_preimage smulSet_gc end Ring_no_OrderedRing @@ -247,10 +246,10 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) @[simp] lemma dehomogenize_weight_positive : - dehomogenize A (hom.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by + dehomogenize hom (hom.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by ext x; simp [dehomogenize, weight_one] lemma nonneg_smulSet_ofPoint_range_le_weight_positive : @@ -259,20 +258,20 @@ lemma nonneg_smulSet_ofPoint_range_le_weight_positive : exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : - homogenize R W (Set.univ : Set A) ≤ hom.weight.positive := by - simpa [homogenize] using nonneg_smulSet_ofPoint_range_le_weight_positive + homogenize hom (Set.univ : Set A) ≤ hom.weight.positive := by + simpa [homogenize] using nonneg_smulSet_ofPoint_range_le_weight_positive _ lemma homogenize_le_weight_positive (s : Set A) : - homogenize R W s ≤ hom.weight.positive := - le_trans (homogenize_mono (Set.subset_univ _)) homogenize_univ_le_weight_positive + homogenize hom s ≤ hom.weight.positive := + le_trans (homogenize_mono _ (Set.subset_univ _)) (homogenize_univ_le_weight_positive _) @[simp] theorem homogenize_dehomogenize_le_weight_positive {S : SubMulAction₀ R≥0 W} : - homogenize R W (S.dehomogenize A) ≤ S ⊓ hom.weight.positive := by + homogenize hom (S.dehomogenize hom) ≤ S ⊓ hom.weight.positive := by have aux : Set.range hom.ofPoint = hom.ofPoint.range := rfl rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, aux] refine le_trans (smulSet_inter_le _ _) ?_ simp only [smulSet_eq, le_inf_iff, inf_le_left, true_and] - exact le_trans inf_le_right nonneg_smulSet_ofPoint_range_le_weight_positive + exact le_trans inf_le_right (nonneg_smulSet_ofPoint_range_le_weight_positive _) end IsStrictOrderedRing @@ -283,49 +282,49 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] [Module.IsTorsionFree R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) /-- For the weaker version with `r = 1` see `ofPoint_mem_homogenize_iff`. -/ @[simp] lemma smul_ofPoint_mem_homogenize_iff {r : R} (hr : 0 < r) {x : A} (s : Set A) : - r • hom.ofPoint x ∈ homogenize R W s ↔ x ∈ s where + r • hom.ofPoint x ∈ homogenize hom s ↔ x ∈ s where mp := by rintro (h | ⟨x, ⟨y, hy, rfl⟩, ⟨r', hr'⟩, h⟩) · exfalso - exact smul_ne_zero hr.ne.symm (ofPoint_ne_zero x) h + exact smul_ne_zero hr.ne.symm (ofPoint_ne_zero _ x) h · have := congrArg hom.weight h simp only [map_smul, weight_one, smul_eq_mul, mul_one, Nonneg.mk_smul] at this rw [this] at hr h - rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, ofPoint_injective.eq_iff] at h + rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, hom.ofPoint_injective.eq_iff] at h rwa [h] - mpr := smul_ofPoint_mem_homogenize hr.le + mpr := smul_ofPoint_mem_homogenize _ hr.le lemma homogenize_inter (s t : Set A) : - homogenize R W (s ∩ t) = homogenize R W s ⊓ homogenize R W t := by + homogenize hom (s ∩ t) = homogenize hom s ⊓ homogenize hom t := by apply le_antisymm - · exact homogenize_inter_le s t + · exact homogenize_inter_le _ s t · rintro x hx obtain (rfl | ⟨y, hys, r, hr, rfl⟩) := mem_homogenize_iff_exist_lt_zero hx.1 · exact SubMulAction₀.zero_mem - refine smul_ofPoint_mem_homogenize hr.le ⟨hys, ?_⟩ - exact (smul_ofPoint_mem_homogenize_iff hr t).mp hx.2 + refine smul_ofPoint_mem_homogenize _ hr.le ⟨hys, ?_⟩ + exact (smul_ofPoint_mem_homogenize_iff _ hr t).mp hx.2 /-- Homogenization from sets to `SubMulAction₀` as a lattice homomorphism. -/ def homogenizeLatticeHom : LatticeHom (Set A) (SubMulAction₀ R≥0 W) where - toFun := homogenize R W - map_sup' := homogenize_union - map_inf' := homogenize_inter + toFun := homogenize hom + map_sup' := homogenize_union _ + map_inf' := homogenize_inter _ lemma homogenize_sInf {S : Set (Set A)} (hS : S.Nonempty) : - homogenize R W (sInf S) = sInf (homogenize R W '' S) := by + homogenize hom (sInf S) = sInf (homogenize hom '' S) := by apply le_antisymm - · exact homogenize_sInf_le S + · exact homogenize_sInf_le _ S intro x hx simp only [SetLike.mem_sInf, Set.mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at hx obtain (rfl | ⟨y, hys, r, hr, rfl⟩) := mem_homogenize_iff_exist_lt_zero (hx _ hS.choose_spec) · exact SubMulAction₀.zero_mem - exact smul_ofPoint_mem_homogenize hr.le fun t ht => - (smul_ofPoint_mem_homogenize_iff hr t).mp (hx _ ht) + exact smul_ofPoint_mem_homogenize _ hr.le fun t ht => + (smul_ofPoint_mem_homogenize_iff _ hr t).mp (hx _ ht) end IsCancelMulZero_IsTorsionFree @@ -336,15 +335,15 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : R≥0 ∙ (Set.range hom.ofPoint) = hom.weight.positive := by rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_eq_positive _ -@[simp] lemma homogenize_univ : homogenize R W (Set.univ : Set A) = hom.weight.positive := by - simpa [homogenize] using nonneg_smulSet_ofPoint_range +@[simp] lemma homogenize_univ : homogenize hom (Set.univ : Set A) = hom.weight.positive := by + simpa [homogenize] using nonneg_smulSet_ofPoint_range _ end DivisionRing @@ -355,23 +354,24 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (hom : IsHomogenization R A W) @[simp] theorem homogenize_dehomogenize {S : SubMulAction₀ R≥0 W} : - homogenize R W (S.dehomogenize A) = S ⊓ hom.weight.positive := by + homogenize hom (S.dehomogenize hom) = S ⊓ hom.weight.positive := by rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, smulSet_inter_left, nonneg_smulSet_ofPoint_range] +variable {hom} in @[simp] theorem homogenize_dehomogenize_of_le_weight_positive {S : SubMulAction₀ R≥0 W} - (hS : S ≤ hom.weight.positive) : homogenize R W (S.dehomogenize A) = S := by + (hS : S ≤ hom.weight.positive) : homogenize hom (S.dehomogenize hom) = S := by simp [homogenize_dehomogenize, hS] def homogenizeOrderIso : Set A ≃o Set.Iic (hom.weight.positive : SubMulAction₀ R≥0 W) where - toFun s := ⟨_, homogenize_le_weight_positive s⟩ - invFun S := S.1.dehomogenize A - left_inv := dehomogenize_homogenize + toFun s := ⟨_, homogenize_le_weight_positive _ s⟩ + invFun S := S.1.dehomogenize hom + left_inv := dehomogenize_homogenize _ right_inv S := by simp only [homogenize_dehomogenize_of_le_weight_positive S.2] - map_rel_iff' := homogenize_mono_iff + map_rel_iff' := homogenize_mono_iff _ end LinearOrderDivisionRing From 895aa0fcb9f584d6b28c44fcec6313d76e60990f Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 9 Sep 2026 18:20:03 +0200 Subject: [PATCH 03/39] making a fancy H --- .../Convex/ConvexSpace/Homogenization.lean | 38 ++--- .../ConvexSpace/Polytope/Homogenization.lean | 28 ++-- .../ConvexSpace/Set/Face/Homogenization.lean | 40 ++--- .../ConvexSpace/Set/Homogenization.lean | 118 +++++++-------- .../AffineSpace/Homogenization/Basic.lean | 110 +++++++------- .../AffineSpace/Homogenization/Set.lean | 142 +++++++++--------- 6 files changed, 238 insertions(+), 238 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean index 1c67ff1c..5d604df0 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean @@ -24,7 +24,7 @@ variable {R : Type*} [Ring R] [PartialOrder R] [IsStrictOrderedRing R] variable {V : Type*} [AddCommGroup V] [Module R V] variable {A : Type*} [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable {W : Type*} [AddCommGroup W] [Module R W] [ConvexSpace R W] -variable {hom : Affine.IsHomogenization R A W} +variable {ℋ : Affine.IsHomogenization R A W} section Module @@ -33,55 +33,55 @@ variable [IsModuleConvexSpace R W] /-- If the homogenization of a point lies in the conic hull of a subset `s` of the homogenization plane, the point can be written as a convex combination of points in the preimage of `s` under the homogenization embedding. -/ -theorem exists_sConvexComb_preimage_of_mem_hull {x} {s : Set W} (hs : s ⊆ Set.range hom.ofPoint) - (hx : hom.ofPoint x ∈ hull R s) : ∃ c' : StdSimplex R A, - sConvexComb c' = x ∧ (c'.weights.support : Set A) ⊆ (hom.ofPoint ⁻¹' s) := by +theorem exists_sConvexComb_preimage_of_mem_hull {x} {s : Set W} (hs : s ⊆ Set.range ℋ.ofPoint) + (hx : ℋ.ofPoint x ∈ hull R s) : ∃ c' : StdSimplex R A, + sConvexComb c' = x ∧ (c'.weights.support : Set A) ⊆ (ℋ.ofPoint ⁻¹' s) := by obtain ⟨c, ha, hb, hc⟩ := mem_hull_set.mp hx -- use the same weights, just un-embed the domain - use StdSimplex.mk (c.comapDomain hom.ofPoint hom.ofPoint_injective.injOn) ?_ ?_ + use StdSimplex.mk (c.comapDomain ℋ.ofPoint ℋ.ofPoint_injective.injOn) ?_ ?_ constructor · -- the convex combo yields x - apply hom.ofPoint_injective - rw [hom.ofPoint.isAffineMap.map_sConvexComb, sConvexComb_eq_sum, - StdSimplex.weights_map, ← hc, Finsupp.mapDomain_comapDomain _ hom.ofPoint_injective] + apply ℋ.ofPoint_injective + rw [ℋ.ofPoint.isAffineMap.map_sConvexComb, sConvexComb_eq_sum, + StdSimplex.weights_map, ← hc, Finsupp.mapDomain_comapDomain _ ℋ.ofPoint_injective] exact ha.trans hs · -- the weights are a subset of the preimage of s simpa using (Set.preimage_mono ha) · -- they're always nonneg intro y - simpa using hb (hom.ofPoint y) + simpa using hb (ℋ.ofPoint y) · -- its actually a convex combo, i.e. weights sum to 1 - have hsum : c.sum (fun a b => b * hom.weight a) = c.sum (fun a b => b) := by + have hsum : c.sum (fun a b => b * ℋ.weight a) = c.sum (fun a b => b) := by refine Finsupp.sum_congr (fun a h => ?_) obtain ⟨_, _, rfl⟩ := (ha.trans hs) h - simp [hom.weight_one] + simp [ℋ.weight_one] -- apply weights map to both sides - have := congrArg hom.weight hc - simp only [map_finsuppSum, map_smul, smul_eq_mul, hsum, hom.weight_one] at this + have := congrArg ℋ.weight hc + simp only [map_finsuppSum, map_smul, smul_eq_mul, hsum, ℋ.weight_one] at this rw [← this] simp only [Finsupp.sum, Finsupp.comapDomain_support, Finsupp.comapDomain_apply] - rw [Finset.sum_preimage hom.ofPoint _ (hom.ofPoint_injective.injOn)] + rw [Finset.sum_preimage ℋ.ofPoint _ (ℋ.ofPoint_injective.injOn)] exact fun _ hx hnx ↦ Finsupp.notMem_support_iff.mp fun _ ↦ hnx (hs (ha hx)) /-- The preimage of the conic hull of a set in the homogenization plane is the convex hull of the preimage of the set. -/ -theorem preimage_hull_eq_convexHull_preimage {s : Set W} (hs : s ⊆ Set.range hom.ofPoint) : - hom.ofPoint ⁻¹' hull R s = Convexity.convexHull R (hom.ofPoint ⁻¹' s) := by +theorem preimage_hull_eq_convexHull_preimage {s : Set W} (hs : s ⊆ Set.range ℋ.ofPoint) : + ℋ.ofPoint ⁻¹' hull R s = Convexity.convexHull R (ℋ.ofPoint ⁻¹' s) := by refine subset_antisymm ?_ ?_ · intro x hx obtain ⟨c', rfl, hs⟩ := exists_sConvexComb_preimage_of_mem_hull hs hx exact IsConvexSet.convexHull.sConvexComb_mem (le_trans hs subset_convexHull_self) · apply Set.image_subset_iff.mp - rw [hom.ofPoint.isAffineMap.image_convexHull, Set.image_preimage_eq_iff.mpr hs] + rw [ℋ.ofPoint.isAffineMap.image_convexHull, Set.image_preimage_eq_iff.mpr hs] exact (hull R s).isConvexSet.convexHull_subset_iff.mpr subset_hull variable (hom) in /-- The homogenization embedding of the convex hull of a set is contained in the hull of the embedding of the set. -/ theorem image_hull_eq_convexHull_image {s : Set A} : - hom.ofPoint '' Convexity.convexHull R s ⊆ hull R (hom.ofPoint '' s) := by + ℋ.ofPoint '' Convexity.convexHull R s ⊆ hull R (ℋ.ofPoint '' s) := by apply Set.image_subset_iff.mp - rw [hom.ofPoint.isAffineMap.image_convexHull] + rw [ℋ.ofPoint.isAffineMap.image_convexHull] simpa using (hull R _).isConvexSet.convexHull_subset_iff.mpr subset_hull end Module diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean index dc8afffa..af88ac64 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean @@ -28,46 +28,46 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) open PointedCone /-- The homogenization of a polytope is a finitely generated cone. -/ theorem IsPolytope.homogenize_fg {C : ConvexSet R A} (hCfg : IsPolytope R (C : Set A)) : - (homogenize hom C).FG := by + (homogenize ℋ C).FG := by obtain ⟨t, ht⟩ := hCfg have : C = ⟨convexHull R t, IsConvexSet.convexHull⟩ := SetLike.ext' ht - have := congrArg (ConvexSet.homogenize hom) this + have := congrArg (ConvexSet.homogenize ℋ) this rw [this] - use t.map ⟨_, hom.ofPoint_injective⟩ + use t.map ⟨_, ℋ.ofPoint_injective⟩ simp only [Finset.coe_map, Function.Embedding.coeFn_mk, homogenize, PointedCone.hull, ConvexSet.mk_eq] - rw [hom.ofPoint.isAffineMap.image_convexHull t] - exact (PointedCone.hull_convexHull (hom.ofPoint '' t)).symm + rw [ℋ.ofPoint.isAffineMap.image_convexHull t] + exact (PointedCone.hull_convexHull (ℋ.ofPoint '' t)).symm /-- A convex set is a polytope iff its homogenization is a finitely generated cone. -/ theorem IsPolytope.iff_homogenize_fg {C : ConvexSet R A} : - IsPolytope R (C : Set A) ↔ (homogenize hom C).FG := by classical + IsPolytope R (C : Set A) ↔ (homogenize ℋ C).FG := by classical refine ⟨homogenize_fg _, fun hfg ↦ ?_⟩ -- get cone generators that lie in the embedding of A obtain ⟨g, hg, hs⟩ := homogenize_fg_ofPoint_range hfg -- un-embed them - use g.preimage hom.ofPoint hom.ofPoint_injective.injOn + use g.preimage ℋ.ofPoint ℋ.ofPoint_injective.injOn -- show they generate C simp only [Finset.coe_preimage] apply le_antisymm · intro x hx rw [← preimage_hull_eq_convexHull_preimage hs] simp only [hg, homogenize] - exact Submodule.mem_span_of_mem <| Set.mem_image_of_mem hom.ofPoint hx + exact Submodule.mem_span_of_mem <| Set.mem_image_of_mem ℋ.ofPoint hx · apply C.isConvexSet.convexHull_subset_iff.mpr intro x hx simp only [Set.mem_preimage, SetLike.mem_coe] at hx have := Set.mem_preimage.mpr <| Submodule.mem_span_of_mem (R := {c : R // 0 ≤ c}) hx simp_rw [hg, homogenize] at this - rw [preimage_hull_eq_convexHull_preimage (Set.image_subset_range hom.ofPoint C)] at this + rw [preimage_hull_eq_convexHull_preimage (Set.image_subset_range ℋ.ofPoint C)] at this rw [← C.isConvexSet.convexHull_eq_self] - simpa [← C.isConvexSet.convexHull_eq_self, Set.preimage_image_eq _ hom.ofPoint_injective] + simpa [← C.isConvexSet.convexHull_eq_self, Set.preimage_image_eq _ ℋ.ofPoint_injective] end Ring @@ -80,13 +80,13 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable {hom : IsHomogenization R A W} +variable {ℋ : IsHomogenization R A W} open Pointwise Submodule in /-- Dehomogenizing a finitely generated positive cone yields a polytope. -/ theorem FG.dehomogenize_isPolytope {C : PointedCone R W} (h : C.FG) - (hc : C ≤ hom.weight.positive) : IsPolytope R (dehomogenize hom C : Set A) := by - rw [IsPolytope.iff_homogenize_fg hom] + (hc : C ≤ ℋ.weight.positive) : IsPolytope R (dehomogenize ℋ C : Set A) := by + rw [IsPolytope.iff_homogenize_fg ℋ] simpa [homogenize_dehomogenize_of_le_positive hc] end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean index 1febd22a..eeaadbea 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean @@ -28,34 +28,34 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable (hom : Affine.IsHomogenization R A W) +variable (ℋ : Affine.IsHomogenization R A W) -variable {hom} in +variable {ℋ} in /-- If the homogenization of a point `q` is a positive combination of the homogenization of two other points, then `q` lies in the open segment between them. -/ theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} (h₁ : 0 < r₁) (h₂ : 0 < r₂) (hₜ : 0 < t) - (h : r₁ • hom.ofPoint p₁ + r₂ • hom.ofPoint p₂ = t • hom.ofPoint q) : + (h : r₁ • ℋ.ofPoint p₁ + r₂ • ℋ.ofPoint p₂ = t • ℋ.ofPoint q) : q ∈ Convexity.openSegment R p₁ p₂ := by - have : r₁ + r₂ = t := by simpa [hom.weight_one, map_add, map_smul] using congr_arg hom.weight h + have : r₁ + r₂ = t := by simpa [ℋ.weight_one, map_add, map_smul] using congr_arg ℋ.weight h have : t⁻¹ • r₁ + t⁻¹ • r₂ = 1 := by simp_rw [← smul_add, smul_eq_mul, this, mul_comm, Field.mul_inv_cancel _ hₜ.ne.symm] use (t⁻¹ • r₁), (t⁻¹ • r₂), (smul_pos (by positivity) h₁), (smul_pos (by positivity) h₂), this - apply hom.ofPoint_injective - have : t⁻¹ • (r₁ • hom.ofPoint p₁ + r₂ • hom.ofPoint p₂) = hom.ofPoint q := by + apply ℋ.ofPoint_injective + have : t⁻¹ • (r₁ • ℋ.ofPoint p₁ + r₂ • ℋ.ofPoint p₂) = ℋ.ofPoint q := by rw [h, smul_smul, inv_mul_cancel₀ (ne_of_gt hₜ), one_smul] - simp [hom.ofPoint.isAffineMap.map_convexCombPair, convexCombPair_eq_sum, ← this, smul_smul] + simp [ℋ.ofPoint.isAffineMap.map_convexCombPair, convexCombPair_eq_sum, ← this, smul_smul] /-- If `F` is a face of `P`, then the homogenization of `F` is a face of the homogenization of `P`. -/ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : - (F.homogenize hom).IsFaceOf (P.homogenize hom) where - le := (homogenizeOrderHom hom).monotone' he.le + (F.homogenize ℋ).IsFaceOf (P.homogenize ℋ) where + le := (homogenizeOrderHom ℋ).monotone' he.le mem_of_smul_add_mem := by intro v w a hv hw ha hvw - have hhom := homogenize_salient hom P + have hhom := homogenize_salient ℋ P by_cases hnf : (F : Set A).Nonempty - · have cF := F.isConvexSet.image hom.ofPoint.isAffineMap + · have cF := F.isConvexSet.image ℋ.ofPoint.isAffineMap apply (Set.ext_iff.mp (PointedCone.hull_eq_smul (hnf.image _) cF) _).mpr by_cases hv0 : v = 0 · exact ⟨0, le_rfl, mem_smul_set.mpr (by simpa [hv0] using nonempty_def.mp hnf)⟩ @@ -71,13 +71,13 @@ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : rw [smul_assoc, hra, ← smul_assoc, smul_eq_mul, inv_mul_cancel₀ ha.ne.symm, one_smul] · obtain ⟨rw, rw0, q, ⟨q', qq, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hw hw0 obtain ⟨rv, rv0, _, ⟨p', pp, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hv hv0 - have : a • (rv • hom.ofPoint p') + (rw • hom.ofPoint q') ≠ 0 := by + have : a • (rv • ℋ.ofPoint p') + (rw • ℋ.ofPoint q') ≠ 0 := by intro hc - exact (smul_ne_zero rw0.ne.symm (hom.ofPoint_ne_zero q')) <| + exact (smul_ne_zero rw0.ne.symm (ℋ.ofPoint_ne_zero q')) <| hhom _ hw _ (PointedCone.smul_mem _ ha.le hv) (by simpa [add_comm] using hc) obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := smul_pos_of_mem_homogenize hvw this have := he.left_mem_of_mem_openSegment pp qq qqp ?_ - · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem hom.ofPoint this⟩ + · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem ℋ.ofPoint this⟩ rw [← smul_assoc _ rv] at pdp exact pos_combo_openSegment (smul_pos ha rv0) rw0 rvw0 pdp.symm · have := not_nonempty_iff_eq_empty.mp hnf @@ -93,13 +93,13 @@ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : /-- If `F` is a face of `C`, then the dehomogenization of `F` is a face of the dehomogenization of `C`. -/ theorem dehomogenize_isFaceOf {F C : PointedCone R W} (hf : F.IsFaceOf C) : - (ConvexSet.dehomogenize hom F).IsFaceOf (ConvexSet.dehomogenize hom C) where + (ConvexSet.dehomogenize ℋ F).IsFaceOf (ConvexSet.dehomogenize ℋ C) where le := preimage_mono (fun _ x ↦ hf.le x) left_mem_of_mem_openSegment := by rintro x hx y hy z hz ⟨a, b, ha, hb, hab, hzo⟩ refine hf.mem_of_smul_add_mem hx (C.smul_mem hb.le hy) ha ?_ rwa [← convexCombPair_eq_sum _ _ ha.le hb.le hab, - ← hom.ofPoint.isAffineMap.map_convexCombPair, hzo] + ← ℋ.ofPoint.isAffineMap.map_convexCombPair, hzo] /-- The isomorphism between the face lattice of a convex set `P` and the face lattice of its homogenization cone. @@ -108,10 +108,10 @@ This isomorphism is used to translate results between face lattices of cones and of convex sets. -/ def Face.homogenizeIso (P : ConvexSet R A) : - Face P ≃o PointedCone.Face (P.homogenize hom) where - toFun F := ⟨_, hom.homogenize_isFaceOf F.isFaceOf⟩ - invFun F := ⟨dehomogenize hom F.toSubmodule, - by simpa [dehomogenize_homogenize hom] using dehomogenize_isFaceOf hom F.isFaceOf⟩ + Face P ≃o PointedCone.Face (P.homogenize ℋ) where + toFun F := ⟨_, ℋ.homogenize_isFaceOf F.isFaceOf⟩ + invFun F := ⟨dehomogenize ℋ F.toSubmodule, + by simpa [dehomogenize_homogenize ℋ] using dehomogenize_isFaceOf ℋ F.isFaceOf⟩ map_rel_iff' := by intro a b refine ⟨fun h x xm ↦ ?_, fun h _ xm ↦ span_mono (image_mono h) xm⟩ diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index fe6adb67..3b091332 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -31,62 +31,62 @@ variable [AddCommGroup V] [Module R V] variable [AddCommGroup W] [Module R W] variable [AddTorsor V A] [ConvexSpace R A] -variable (hom : Affine.IsHomogenization R A W) +variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization cone of a convex set in an affine space. -/ -def homogenize (P : ConvexSet R A) : PointedCone R W := hull R (hom.ofPoint '' P) +def homogenize (P : ConvexSet R A) : PointedCone R W := hull R (ℋ.ofPoint '' P) lemma homogenize_mono {K₁ K₂ : ConvexSet R A} (h : K₁ ≤ K₂) : - K₁.homogenize hom ≤ K₂.homogenize hom := Submodule.span_mono <| Set.image_mono h + K₁.homogenize ℋ ≤ K₂.homogenize ℋ := Submodule.span_mono <| Set.image_mono h -lemma homogenize_monotone : Monotone (homogenize hom : ConvexSet R A → PointedCone R W) := +lemma homogenize_monotone : Monotone (homogenize ℋ : ConvexSet R A → PointedCone R W) := fun _ _ => homogenize_mono _ /-- Homogenization from convex set to convex cones as an order homomorphism. -/ def homogenizeOrderHom : ConvexSet R A →o PointedCone R W where - toFun := homogenize hom + toFun := homogenize ℋ monotone' := homogenize_monotone _ @[simp] -lemma homogenize_bot : homogenize hom (⊥ : ConvexSet R A) = ⊥ := by +lemma homogenize_bot : homogenize ℋ (⊥ : ConvexSet R A) = ⊥ := by simp [homogenize, Bot.bot] @[simp] -lemma homogenize_eq_bot_iff (P : ConvexSet R A) : homogenize hom P = ⊥ ↔ P = ⊥ := by +lemma homogenize_eq_bot_iff (P : ConvexSet R A) : homogenize ℋ P = ⊥ ↔ P = ⊥ := by refine ⟨fun h ↦ ?_, by simp +contextual [-SetLike.bot_eq_empty]⟩ ext x simp only [homogenize, span_eq_bot, mem_image, SetLike.mem_coe, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at h - simpa using fun hx ↦ hom.ofPoint_ne_zero _ (h x hx) + simpa using fun hx ↦ ℋ.ofPoint_ne_zero _ (h x hx) -/- NOTE: `homogenize_top`, stating `homogenize hom (⊤ : ConvexSet R A) = hom.weight.positive`, +/- NOTE: `homogenize_top`, stating `homogenize ℋ (⊤ : ConvexSet R A) = ℋ.weight.positive`, only holds over linearly ordered fields and is proven in the `Field` section below. Over a general ordered ring it fails: for `R = ℤ[ε]` with `ε` a positive infinitesimal, the point `(1, ε)` lies in `weight.positive` but not in the cone hull of the weight-one hyperplane, since all nonnegative coefficients bounded by `ε` lie in the ideal `(ε)`. -/ lemma homogenize_le_weight_positive (K : ConvexSet R A) : - homogenize hom K ≤ hom.weight.positive := by + homogenize ℋ K ≤ ℋ.weight.positive := by exact LinearMap.hull_le_positive_of_subset_preimage_singleton one_pos fun _ ↦ by rintro ⟨x, -, rfl⟩ - simp [hom.weight_one] + simp [ℋ.weight_one] variable {hom} in -lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize hom P) (hx : x ≠ 0) : - 0 < hom.weight x := homogenize_le_weight_positive _ P h hx +lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize ℋ P) (hx : x ≠ 0) : + 0 < ℋ.weight x := homogenize_le_weight_positive _ P h hx variable {hom} in -lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ homogenize hom P) : - 0 ≤ hom.weight x := +lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ homogenize ℋ P) : + 0 ≤ ℋ.weight x := (LinearMap.mem_positive'.mp (homogenize_le_weight_positive _ P h)).1 -lemma homogenize_salient (K : ConvexSet R A) : PointedCone.Salient (homogenize hom K) := - Salient.of_le_salient hom.weight.positive_salient (homogenize_le_weight_positive _ K) +lemma homogenize_salient (K : ConvexSet R A) : PointedCone.Salient (homogenize ℋ K) := + Salient.of_le_salient ℋ.weight.positive_salient (homogenize_le_weight_positive _ K) variable {hom} in -theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize hom C).FG) : - ∃ g : Finset W, PointedCone.hull R g = homogenize hom C ∧ - (g : Set W) ⊆ Set.range hom.ofPoint := by +theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize ℋ C).FG) : + ∃ g : Finset W, PointedCone.hull R g = homogenize ℋ C ∧ + (g : Set W) ⊆ Set.range ℋ.ofPoint := by obtain ⟨g, hg⟩ := h -- express each generator as a positive combo of stuff in the embedding of C have gsum {x} (hx : x ∈ g) := mem_hull_set.mp (hg ▸ (Submodule.mem_span_of_mem hx)) @@ -94,7 +94,7 @@ theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize hom C). -- collect all said stuff and use as the new generators let g' := g.attach.biUnion (fun x => (Classical.choose (gsum x.2)).support) use g' - have g'sub : (g' : Set W) ⊆ hom.ofPoint '' C := by + have g'sub : (g' : Set W) ⊆ ℋ.ofPoint '' C := by simpa [g'] using fun _ b ↦ (Classical.choose_spec (gsum b)).1 have gsubhull : (g : Set W) ⊆ hull R (g' : Set W) := by intro x hx @@ -110,34 +110,34 @@ section Module variable [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] def dehomogenize (C : PointedCone R W) : ConvexSet R A := - ⟨_, C.isConvexSet.preimage hom.ofPoint.isAffineMap⟩ + ⟨_, C.isConvexSet.preimage ℋ.ofPoint.isAffineMap⟩ alias _root_.PointedCone.dehomogenize := dehomogenize @[simp] -lemma dehomogenize_bot : dehomogenize hom (⊥ : PointedCone R W) = ⊥ := by +lemma dehomogenize_bot : dehomogenize ℋ (⊥ : PointedCone R W) = ⊥ := by ext simp [dehomogenize, Affine.IsHomogenization.ofPoint_ne_zero] @[simp] -lemma dehomogenize_top : dehomogenize hom (⊤ : PointedCone R W) = ⊤ := by +lemma dehomogenize_top : dehomogenize ℋ (⊤ : PointedCone R W) = ⊤ := by ext simp [dehomogenize, SetLike.mem_coe.mp] @[simp] -lemma dehomogenize_weight_positive : dehomogenize hom hom.weight.positive = ⊤ := - SetLike.eq_top_of_forall fun _ ↦ LinearMap.mem_positive'.mpr (by simp [hom.weight_one]) +lemma dehomogenize_weight_positive : dehomogenize ℋ ℋ.weight.positive = ⊤ := + SetLike.eq_top_of_forall fun _ ↦ LinearMap.mem_positive'.mpr (by simp [ℋ.weight_one]) lemma dehomogenize_mono {C₁ C₂ : PointedCone R W} (h : C₁ ≤ C₂) : - dehomogenize hom C₁ ≤ dehomogenize hom C₂ := Set.preimage_mono <| Set.preimage_mono h + dehomogenize ℋ C₁ ≤ dehomogenize ℋ C₂ := Set.preimage_mono <| Set.preimage_mono h -- Q: why Set.preimage_mono twice? -lemma dehomogenize_monotone : Monotone (dehomogenize hom : PointedCone R W → ConvexSet R A) := +lemma dehomogenize_monotone : Monotone (dehomogenize ℋ : PointedCone R W → ConvexSet R A) := fun _ _ => dehomogenize_mono _ -- This lemma is just `Set.image_preimage_eq_inter_range` in disguise. It is likely not needed. lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : - hom.ofPoint '' dehomogenize hom C = (C : Set W) ∩ hom.ofPoint.range := by + ℋ.ofPoint '' dehomogenize ℋ C = (C : Set W) ∩ ℋ.ofPoint.range := by ext x simp only [Set.mem_image, SetLike.mem_coe, Set.mem_inter_iff, AffineMap.mem_range] constructor @@ -150,8 +150,8 @@ lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : /-- The preimage of the conic hull of a set in the homogenization plane is the convex hull of the preimage of the set. -/ theorem hull_image_ofPoint_eq_homogenize_convexHull {s : Set A} : - hull R (hom.ofPoint '' s) = homogenize hom (ConvexSet.convexHull R s) := by - simp [homogenize, ConvexSet.convexHull, hom.ofPoint.isAffineMap.image_convexHull] + hull R (ℋ.ofPoint '' s) = homogenize ℋ (ConvexSet.convexHull R s) := by + simp [homogenize, ConvexSet.convexHull, ℋ.ofPoint.isAffineMap.image_convexHull] end Module @@ -164,80 +164,80 @@ variable [AddCommGroup V] [Module R V] variable [AddCommGroup W] [Module R W] variable [AddTorsor V A] [ConvexSpace R A] -variable (hom : Affine.IsHomogenization R A W) +variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ -lemma homogenize_top : homogenize hom (⊤ : ConvexSet R A) = hom.weight.positive := by - rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton hom.weight one_pos, - ← hom.ofPoint_range_eq_preimage_weight_one] +lemma homogenize_top : homogenize ℋ (⊤ : ConvexSet R A) = ℋ.weight.positive := by + rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton ℋ.weight one_pos, + ← ℋ.ofPoint_range_eq_preimage_weight_one] congr! with x simp variable [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] -variable {hom} in -lemma smul_pos_of_mem_homogenize {P : ConvexSet R A} {x} (h : x ∈ homogenize hom P) (hx : x ≠ 0) : - x ∈ Set.Ioi (0 : R) • hom.ofPoint '' (P : Set A) := +variable {ℋ} in +lemma smul_pos_of_mem_homogenize {P : ConvexSet R A} {x} (h : x ∈ homogenize ℋ P) (hx : x ≠ 0) : + x ∈ Set.Ioi (0 : R) • ℋ.ofPoint '' (P : Set A) := (mem_hull_iff_mem_pos_smul_of_convex_nonzero - (P.isConvexSet.image hom.ofPoint.isAffineMap) hx).mp h + (P.isConvexSet.image ℋ.ofPoint.isAffineMap) hx).mp h -- TODO: This lemma should be proven for general sets (homogenizing to SubMulAction) and then -- applied here as a special case. lemma ofPoint_mem_homogenize_iff_mem (x : A) (P : ConvexSet R A) : - hom.ofPoint x ∈ homogenize hom P ↔ x ∈ P := by - refine ⟨fun h ↦ ?_, fun h ↦ mem_span_of_mem (Set.mem_image_of_mem hom.ofPoint h)⟩ - obtain ⟨_, _, h'⟩ := smul_pos_of_mem_homogenize (Set.mem_preimage.mpr h) (hom.ofPoint_ne_zero x) + ℋ.ofPoint x ∈ homogenize ℋ P ↔ x ∈ P := by + refine ⟨fun h ↦ ?_, fun h ↦ mem_span_of_mem (Set.mem_image_of_mem ℋ.ofPoint h)⟩ + obtain ⟨_, _, h'⟩ := smul_pos_of_mem_homogenize (Set.mem_preimage.mpr h) (ℋ.ofPoint_ne_zero x) obtain ⟨_, ⟨_, _, hyy'⟩, hy'⟩ := Set.mem_smul_set.mp h' - have := congrArg hom.weight hy' - simp [← hyy', hom.weight_one] at this + have := congrArg ℋ.weight hy' + simp [← hyy', ℋ.weight_one] at this simp only [this, Set.mem_image, one_smul, exists_eq_right] at h' obtain ⟨_, _, hxx'⟩ := h' - simpa [← hom.ofPoint_injective hxx'] + simpa [← ℋ.ofPoint_injective hxx'] /-- Dehomogenizing the homogenization of a convex set yields the same set again. -/ @[simp] theorem dehomogenize_homogenize (P : ConvexSet R A) : - dehomogenize hom (homogenize hom P) = P := by + dehomogenize ℋ (homogenize ℋ P) = P := by ext x; exact ofPoint_mem_homogenize_iff_mem _ _ _ -lemma homogenize_injective : Function.Injective (homogenize hom) := by +lemma homogenize_injective : Function.Injective (homogenize ℋ) := by intro P Q h - have hh := congr_arg (ConvexSet.dehomogenize hom) h + have hh := congr_arg (ConvexSet.dehomogenize ℋ) h simp [dehomogenize_homogenize] at hh assumption -variable {hom} in +variable {ℋ} in /-- If the entire cone save the origin are at positive weight, homogenizing the dehomogenization of the homogenize yields the cone again. -/ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} - (hC : C ≤ hom.weight.positive) : homogenize hom (dehomogenize hom C) = C := by + (hC : C ≤ ℋ.weight.positive) : homogenize ℋ (dehomogenize ℋ C) = C := by by_cases hbot : C = ⊥ · simp [hbot, homogenize, dehomogenize] · apply SetLike.ext' unfold homogenize rw [eq_Ici_zero_smul_inter_preimage_of_pos_of_ne_bot hC zero_lt_one hbot, - ofPoint_dehomogenize_eq_inter_ofPoint, ← hom.ofPoint_range_eq_preimage_weight_one] + ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_one] apply hull_eq_smul · obtain ⟨y, hyC, hy0⟩ := exists_mem_ne_zero_of_ne_bot hbot - let y' := (hom.weight y)⁻¹ • y + let y' := (ℋ.weight y)⁻¹ • y have hy'C : y' ∈ C := C.smul_mem (inv_nonneg.mpr (@hC y hyC hy0).le) hyC - have hy' : y' ∈ Set.range hom.ofPoint := by - simpa [y', hom.ofPoint_range_eq_preimage_weight_one] + have hy' : y' ∈ Set.range ℋ.ofPoint := by + simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ - · exact C.isConvexSet.inter hom.ofPoint.range_isConvexSet + · exact C.isConvexSet.inter ℋ.ofPoint.range_isConvexSet lemma homogenize_mono_iff {K₁ K₂ : ConvexSet R A} : - K₁.homogenize hom ≤ K₂.homogenize hom ↔ K₁ ≤ K₂ where - mp h := by simpa using dehomogenize_mono hom h + K₁.homogenize ℋ ≤ K₂.homogenize ℋ ↔ K₁ ≤ K₂ where + mp h := by simpa using dehomogenize_mono ℋ h mpr := homogenize_mono _ -- Issue #66 /-- The lattice of convex sets is isomorphic to the lattice of convex sub-cones of the positive cone. -/ -def homogenizeOrderEquiv : ConvexSet R A ≃o Set.Iic hom.weight.positive where +def homogenizeOrderEquiv : ConvexSet R A ≃o Set.Iic ℋ.weight.positive where toFun K := ⟨_, K.homogenize_le_weight_positive _⟩ - invFun C := dehomogenize hom C.1 + invFun C := dehomogenize ℋ C.1 left_inv K := dehomogenize_homogenize _ K right_inv C := by dsimp; congr; exact homogenize_dehomogenize_of_le_positive C.2 map_rel_iff' := homogenize_mono_iff _ diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index 5f2a6fd0..5cc5bef7 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -66,116 +66,116 @@ noncomputable def IsHomogenization.canonical : namespace IsHomogenization -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) -abbrev ofVector := hom.ofPoint.linear +abbrev ofVector := ℋ.ofPoint.linear -theorem ofVector_injective : Injective hom.ofVector := by - simp [hom.ofPoint_injective] +theorem ofVector_injective : Injective ℋ.ofVector := by + simp [ℋ.ofPoint_injective] /-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ -theorem ofVector_range_eq_weight_ker : hom.ofVector.range = hom.weight.ker := by +theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by ext x let a₀ := Classical.arbitrary A simp only [LinearMap.mem_range, LinearMap.mem_ker] - have : (∃ y, hom.ofVector y = x) ↔ ∃ a b : A, hom.ofVector (a -ᵥ b) = x := + have : (∃ y, ℋ.ofVector y = x) ↔ ∃ a b : A, ℋ.ofVector (a -ᵥ b) = x := ⟨fun ⟨y, hy⟩ => ⟨y +ᵥ a₀, a₀, by simp [vadd_vsub, hy]⟩, fun ⟨a, b, hab⟩ => ⟨a -ᵥ b, hab⟩⟩ rw [this] - have hh := Set.ext_iff.mp hom.ofPoint_range_eq_preimage_weight_one + have hh := Set.ext_iff.mp ℋ.ofPoint_range_eq_preimage_weight_one constructor · rintro ⟨a, b, hab⟩ simp only [Set.mem_preimage, Set.mem_singleton_iff] at hh - simp [← hab, map_sub, (hh (hom.ofPoint b)).mp ⟨b, rfl⟩, (hh (hom.ofPoint a)).mp ⟨a, rfl⟩] + simp [← hab, map_sub, (hh (ℋ.ofPoint b)).mp ⟨b, rfl⟩, (hh (ℋ.ofPoint a)).mp ⟨a, rfl⟩] · intro h - have ha := Set.mem_preimage.mp <| (hh (hom.ofPoint a₀)).mp (by simp) - obtain ⟨b, hb⟩ : x + hom.ofPoint a₀ ∈ (Set.range hom.ofPoint) := by - simpa [hom.ofPoint_range_eq_preimage_weight_one, Set.mem_preimage, map_add, h] + have ha := Set.mem_preimage.mp <| (hh (ℋ.ofPoint a₀)).mp (by simp) + obtain ⟨b, hb⟩ : x + ℋ.ofPoint a₀ ∈ (Set.range ℋ.ofPoint) := by + simpa [ℋ.ofPoint_range_eq_preimage_weight_one, Set.mem_preimage, map_add, h] exact ⟨b, a₀, by simp [AffineMap.linearMap_vsub, hb]⟩ /-- The homogenization of a point in `A` has weight 1. -/ -lemma weight_one (a₀ : A) : hom.weight (hom.ofPoint a₀) = 1 := by - convert Set.ext_iff.mp hom.ofPoint_range_eq_preimage_weight_one (hom.ofPoint a₀) +lemma weight_one (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by + convert Set.ext_iff.mp ℋ.ofPoint_range_eq_preimage_weight_one (ℋ.ofPoint a₀) simp [exists_apply_eq_apply, Set.mem_preimage, Set.mem_singleton_iff, true_iff] variable [Nontrivial R] in -theorem ofPoint_ne_zero (x : A) : hom.ofPoint x ≠ (0 : W) := by +theorem ofPoint_ne_zero (x : A) : ℋ.ofPoint x ≠ (0 : W) := by intro hn - have := congrArg hom.weight hn - simp [hom.weight_one x] at this + have := congrArg ℋ.weight hn + simp [ℋ.weight_one x] at this /-- The homogenization of a point in `V` has weight 0. -/ -lemma weight_zero (v : V) : hom.weight (hom.ofVector v) = 0 := by +lemma weight_zero (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [LinearMap.mem_ker.mp, ← ofVector_range_eq_weight_ker] -theorem span_range_ofPoint : span R (Set.range hom.ofPoint) = ⊤ := by +theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by refine eq_top_iff'.mpr (fun x ↦ ?_) let a₀ := Classical.arbitrary A -- projecting x to weight 0 along a₀ gives sth in the span of image of ofPoint - have hlin : x - hom.weight x • hom.ofPoint a₀ ∈ Submodule.span R hom.ofPoint.range := by - obtain ⟨v, hv⟩ : x - hom.weight x • hom.ofPoint a₀ ∈ hom.ofVector.range := by - simp [ofVector_range_eq_weight_ker, hom.weight_one a₀] - have : hom.ofVector v = hom.ofPoint (v +ᵥ a₀) - hom.ofPoint a₀ := by simp + have hlin : x - ℋ.weight x • ℋ.ofPoint a₀ ∈ Submodule.span R ℋ.ofPoint.range := by + obtain ⟨v, hv⟩ : x - ℋ.weight x • ℋ.ofPoint a₀ ∈ ℋ.ofVector.range := by + simp [ofVector_range_eq_weight_ker, ℋ.weight_one a₀] + have : ℋ.ofVector v = ℋ.ofPoint (v +ᵥ a₀) - ℋ.ofPoint a₀ := by simp rw [← hv, this] apply Submodule.sub_mem <;> apply Submodule.subset_span · exact ⟨v +ᵥ a₀, rfl⟩ · exact ⟨a₀, rfl⟩ simpa using - Submodule.add_mem _ hlin <| smul_mem _ (hom.weight x) (subset_span ⟨a₀, rfl⟩) + Submodule.add_mem _ hlin <| smul_mem _ (ℋ.weight x) (subset_span ⟨a₀, rfl⟩) /-- The canonical linear map from `Homogenization R A` to any homogenization `W` of `A`. -/ -noncomputable def ofCanonical : Homogenization R A →ₗ[R] W := Homogenization.lift hom.ofPoint +noncomputable def ofCanonical : Homogenization R A →ₗ[R] W := Homogenization.lift ℋ.ofPoint @[simp] lemma ofCanonical_ofPoint (a : A) : - hom.ofCanonical (Homogenization.ofPoint a) = hom.ofPoint a := by + ℋ.ofCanonical (Homogenization.ofPoint a) = ℋ.ofPoint a := by simp [ofCanonical] @[simp] lemma ofCanonical_ofVector (v : V) : - hom.ofCanonical (Homogenization.ofVector v) = hom.ofVector v := by + ℋ.ofCanonical (Homogenization.ofVector v) = ℋ.ofVector v := by simp [ofCanonical] lemma weight_comp_ofCanonical : - hom.weight ∘ₗ hom.ofCanonical = (Homogenization.weight : Homogenization R A →ₗ[R] R) := + ℋ.weight ∘ₗ ℋ.ofCanonical = (Homogenization.weight : Homogenization R A →ₗ[R] R) := Homogenization.hom_ext fun a ↦ by simp [weight_one] @[simp] lemma weight_ofCanonical (x : Homogenization R A) : - hom.weight (hom.ofCanonical x) = Homogenization.weight x := - congr($(weight_comp_ofCanonical (hom := hom)) x) + ℋ.weight (ℋ.ofCanonical x) = Homogenization.weight x := + congr($(weight_comp_ofCanonical _) x) -theorem ofCanonical_bijective : Bijective hom.ofCanonical := by +theorem ofCanonical_bijective : Bijective ℋ.ofCanonical := by constructor · rw [injective_iff_map_eq_zero] intro x hx have hw : Homogenization.weight x = 0 := by - rw [← hom.weight_ofCanonical x, hx, map_zero] + rw [← ℋ.weight_ofCanonical x, hx, map_zero] obtain ⟨v, rfl⟩ := Homogenization.weight_eq_zero_iff.mp hw - rw [ofCanonical_ofVector, map_eq_zero_iff _ hom.ofVector_injective] at hx + rw [ofCanonical_ofVector, map_eq_zero_iff _ ℋ.ofVector_injective] at hx simp [hx] - · rw [← LinearMap.range_eq_top, ← top_le_iff, ← hom.span_range_ofPoint, Submodule.span_le, + · rw [← LinearMap.range_eq_top, ← top_le_iff, ← ℋ.span_range_ofPoint, Submodule.span_le, Set.range_subset_iff] exact fun a ↦ ⟨Homogenization.ofPoint a, by simp⟩ /-- Every homogenization is linearly equivalent to the canonical homogenization. -/ noncomputable def canonEquiv : W ≃ₗ[R] Homogenization R A := - (LinearEquiv.ofBijective _ hom.ofCanonical_bijective).symm + (LinearEquiv.ofBijective _ ℋ.ofCanonical_bijective).symm @[simp] lemma canonEquiv_symm_apply (x : Homogenization R A) : - hom.canonEquiv.symm x = hom.ofCanonical x := + ℋ.canonEquiv.symm x = ℋ.ofCanonical x := rfl -@[simp] lemma ofCanonical_canonEquiv (x : W) : hom.ofCanonical (hom.canonEquiv x) = x := - hom.canonEquiv.symm_apply_apply x +@[simp] lemma ofCanonical_canonEquiv (x : W) : ℋ.ofCanonical (ℋ.canonEquiv x) = x := + ℋ.canonEquiv.symm_apply_apply x @[simp] lemma canonEquiv_ofPoint (a : A) : - hom.canonEquiv (hom.ofPoint a) = Homogenization.ofPoint a := - hom.canonEquiv.symm.injective <| by simp + ℋ.canonEquiv (ℋ.ofPoint a) = Homogenization.ofPoint a := + ℋ.canonEquiv.symm.injective <| by simp theorem canonEquiv_canonical_ofPoint : - hom.canonEquiv ∘ hom.ofPoint = Homogenization.ofPoint := by + ℋ.canonEquiv ∘ ℋ.ofPoint = Homogenization.ofPoint := by ext a; simp -theorem weight_canonEquiv : Homogenization.weight ∘ hom.canonEquiv = hom.weight := by +theorem weight_canonEquiv : Homogenization.weight ∘ ℋ.canonEquiv = ℋ.weight := by ext x - rw [Function.comp_apply, ← hom.weight_ofCanonical (hom.canonEquiv x), + rw [Function.comp_apply, ← ℋ.weight_ofCanonical (ℋ.canonEquiv x), ofCanonical_canonEquiv] -- proving the universal property using the equiv @@ -183,36 +183,36 @@ theorem weight_canonEquiv : Homogenization.weight ∘ hom.canonEquiv = hom.weigh into any vector space extends uniquely to a linear map from `W` to the vector space. -/ theorem extend (U : Type*) [AddCommGroup U] [Module R U] (f : A →ᵃ[R] U) : - ∃! (F : W →ₗ[R] U), F ∘ hom.ofPoint = f := by - refine ⟨Homogenization.lift f ∘ₗ hom.canonEquiv.toLinearMap, funext fun a ↦ by simp, ?_⟩ + ∃! (F : W →ₗ[R] U), F ∘ ℋ.ofPoint = f := by + refine ⟨Homogenization.lift f ∘ₗ ℋ.canonEquiv.toLinearMap, funext fun a ↦ by simp, ?_⟩ intro g hg - have : g ∘ₗ hom.canonEquiv.symm.toLinearMap = Homogenization.lift f := + have : g ∘ₗ ℋ.canonEquiv.symm.toLinearMap = Homogenization.lift f := Homogenization.hom_ext fun a ↦ by simpa using congrFun hg a rw [← this, LinearMap.comp_assoc] simp open AffineMap LinearEquiv in /-- The linear equivalence between the underlying vector space and its embedding. -/ -noncomputable def ofVectorRangeEquiv : V ≃ₗ[R] hom.ofVector.range := { - toFun v := ⟨hom.ofVector v, hom.ofVector.mem_range_self v⟩ +noncomputable def ofVectorRangeEquiv : V ≃ₗ[R] ℋ.ofVector.range := { + toFun v := ⟨ℋ.ofVector v, ℋ.ofVector.mem_range_self v⟩ map_add' v w := by simp map_smul' r v := by simp invFun := - (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr hom.ofPoint_injective)).invFun + (ofInjective ℋ.ofVector (linear_injective_iff _ |>.mpr ℋ.ofPoint_injective)).invFun left_inv := - (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr hom.ofPoint_injective)).left_inv + (ofInjective ℋ.ofVector (linear_injective_iff _ |>.mpr ℋ.ofPoint_injective)).left_inv right_inv v' := by simp } /-- The affine equivalence between the affine space space and its embedding. -/ -public noncomputable def ofPointRangeEquiv : A ≃ᵃ[R] hom.ofPoint.range := +public noncomputable def ofPointRangeEquiv : A ≃ᵃ[R] ℋ.ofPoint.range := .ofBijective - ⟨hom.ofPoint.rangeRestrict_injective_iff.mpr hom.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ + ⟨ℋ.ofPoint.rangeRestrict_injective_iff.mpr ℋ.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ -lemma apply_ofPointRangeEquiv_symm (x : hom.ofPoint.range) : - hom.ofPoint (hom.ofPointRangeEquiv.symm x) = x := by - rw [← hom.ofPointRangeEquiv.right_inv x] - congr; exact hom.ofPointRangeEquiv.symm_apply_apply _ +lemma apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : + ℋ.ofPoint (ℋ.ofPointRangeEquiv.symm x) = x := by + rw [← ℋ.ofPointRangeEquiv.right_inv x] + congr; exact ℋ.ofPointRangeEquiv.symm_apply_apply _ end IsHomogenization diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index 5a437b75..dbed16a0 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -34,84 +34,84 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) variable {x : A} {s : Set A} -def homogenize (s : Set A) : SubMulAction₀ R≥0 W := R≥0 ∙ (hom.ofPoint '' s) +def homogenize (s : Set A) : SubMulAction₀ R≥0 W := R≥0 ∙ (ℋ.ofPoint '' s) -- potential notations for homogenization: `R≥0 ∙[W] s` or `R ∙₊[W] s` -- -- /- Note that the character `∙` U+2219 used below is different from the scalar multiplication -- character `•` U+2022. -/ --- /-- Notation for the homogenizationof a set `s`, short for `homogenize hom s`. -/ --- scoped notation:70 R:70 " ∙[" W "] " s:70 => homogenize hom s +-- /-- Notation for the homogenizationof a set `s`, short for `homogenize ℋ s`. -/ +-- scoped notation:70 R:70 " ∙[" W "] " s:70 => homogenize ℋ s lemma mem_homogenize {s : Set A} {x : W} : - x ∈ homogenize hom s ↔ x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize ℋ s ↔ x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • ℋ.ofPoint y := by simp [homogenize, mem_smulSet] -variable {hom} in -lemma mem_homogenize_iff_exist_lt_zero {s : Set A} {x : W} (hx : x ∈ homogenize hom s) : - x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 < r ∧ x = r • hom.ofPoint y := by +variable {ℋ} in +lemma mem_homogenize_iff_exist_lt_zero {s : Set A} {x : W} (hx : x ∈ homogenize ℋ s) : + x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 < r ∧ x = r • ℋ.ofPoint y := by obtain (rfl | ⟨y, ⟨z, hz, rfl⟩, _, ⟨r, _⟩, hr0, rfl⟩) := mem_smulSet_iff_exists_ne_zero hx · exact .inl rfl · exact .inr ⟨z, hz, r, by rwa [← zero_lt_iff] at hr0, rfl⟩ lemma mem_homogenize_iff_ne_zero {s : Set A} {x : W} (hx : x ≠ 0) : - x ∈ homogenize hom s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize ℋ s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • ℋ.ofPoint y := by simp [homogenize, mem_smulSet_of_ne_zero hx] lemma mem_homogenize_iff_nonempty {s : Set A} {x : W} (hs : s.Nonempty) : - x ∈ homogenize hom s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by - have : (hom.ofPoint '' s).Nonempty := Set.image_nonempty.mpr hs + x ∈ homogenize ℋ s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • ℋ.ofPoint y := by + have : (ℋ.ofPoint '' s).Nonempty := Set.image_nonempty.mpr hs simp [homogenize, mem_smulSet_of_nonempty this] -@[simp] lemma homogenize_empty : homogenize hom (∅ : Set A) = ⊥ := by +@[simp] lemma homogenize_empty : homogenize ℋ (∅ : Set A) = ⊥ := by ext x; simp [homogenize] -lemma ofPoint_image_subset_homogenize : hom.ofPoint '' s ⊆ homogenize hom s := +lemma ofPoint_image_subset_homogenize : ℋ.ofPoint '' s ⊆ homogenize ℋ s := subset_smulSet -lemma ofPoint_mem_homogenize (hx : x ∈ s) : hom.ofPoint x ∈ homogenize hom s := +lemma ofPoint_mem_homogenize (hx : x ∈ s) : ℋ.ofPoint x ∈ homogenize ℋ s := ofPoint_image_subset_homogenize _ ⟨x, hx, rfl⟩ lemma smul_ofPoint_mem_homogenize {r : R} (hr : 0 ≤ r) (h : x ∈ s) : - r • hom.ofPoint x ∈ homogenize hom s := + r • ℋ.ofPoint x ∈ homogenize ℋ s := smul_mem _ ⟨r, hr⟩ (ofPoint_mem_homogenize _ h) -lemma homogenize_mono {s t : Set A} (h : s ⊆ t) : homogenize hom s ≤ homogenize hom t := +lemma homogenize_mono {s t : Set A} (h : s ⊆ t) : homogenize ℋ s ≤ homogenize ℋ t := smulSet_mono <| Set.image_mono h -lemma homogenize_monotone : Monotone (homogenize hom : Set A → SubMulAction₀ R≥0 W) := +lemma homogenize_monotone : Monotone (homogenize ℋ : Set A → SubMulAction₀ R≥0 W) := fun _ _ => homogenize_mono _ /-- Homogenization from sets to `SubMulAction₀` as an order homomorphism. -/ def homogenizeOrderHom : Set A →o SubMulAction₀ R≥0 W where - toFun := homogenize hom + toFun := homogenize ℋ monotone' := homogenize_monotone _ lemma homogenize_union (s t : Set A) : - homogenize hom (s ∪ t) = homogenize hom s ⊔ homogenize hom t := by + homogenize ℋ (s ∪ t) = homogenize ℋ s ⊔ homogenize ℋ t := by simp only [homogenize, Set.image_union, smulSet_union] lemma homogenize_inter_le (s t : Set A) : - homogenize hom (s ∩ t) ≤ homogenize hom s ⊓ homogenize hom t := by + homogenize ℋ (s ∩ t) ≤ homogenize ℋ s ⊓ homogenize ℋ t := by unfold homogenize - rw [Set.image_inter hom.ofPoint_injective] + rw [Set.image_inter ℋ.ofPoint_injective] exact smulSet_inter_le _ _ lemma homogenize_sSup (S : Set (Set A)) : - homogenize hom (sSup S) = sSup (homogenize hom '' S) := by + homogenize ℋ (sSup S) = sSup (homogenize ℋ '' S) := by unfold homogenize rw [Set.image_sSup, smulSet_sSup, Set.image_image] def homogenizeSSupHom : sSupHom (Set A) (SubMulAction₀ R≥0 W) where - toFun := homogenize hom + toFun := homogenize ℋ map_sSup' := homogenize_sSup _ lemma homogenize_sInf_le (S : Set (Set A)) : - homogenize hom (sInf S) ≤ sInf (homogenize hom '' S) := by + homogenize ℋ (sInf S) ≤ sInf (homogenize ℋ '' S) := by unfold homogenize apply le_trans <| smulSet_mono (Set.image_sInter_subset_sInf_image _ _) apply le_trans (smulSet_sInf_le _) @@ -122,34 +122,34 @@ section Nontrivial variable [Nontrivial R] @[simp] lemma ofPoint_mem_homogenize_iff {x : A} {s : Set A} : - hom.ofPoint x ∈ homogenize hom s ↔ x ∈ s where + ℋ.ofPoint x ∈ homogenize ℋ s ↔ x ∈ s where mp := by rintro (h | ⟨x, ⟨y, hy, rfl⟩, r, h⟩) · exfalso; exact ofPoint_ne_zero _ _ h - · have := congrArg hom.weight h + · have := congrArg ℋ.weight h simp only [weight_one, ← Nonneg.coe_smul, map_smul, smul_eq_mul, mul_one, Eq.comm, Nonneg.coe_eq_one] at this rw [this, one_smul] at h - rwa [hom.ofPoint_injective h] + rwa [ℋ.ofPoint_injective h] mpr := ofPoint_mem_homogenize _ lemma ofPoint_mem_homogenize_singleton {x y : A} : - hom.ofPoint x ∈ homogenize hom {y} ↔ x = y := by simp + ℋ.ofPoint x ∈ homogenize ℋ {y} ↔ x = y := by simp lemma homogenize_injective : - Injective (homogenize hom : Set A → SubMulAction₀ R≥0 W) := by + Injective (homogenize ℋ : Set A → SubMulAction₀ R≥0 W) := by intro s t h; ext repeat rw [← ofPoint_mem_homogenize_iff (R := R) (W := W)] rw [h] -@[simp] lemma homogenize_inj {s t : Set A} : homogenize hom s = homogenize hom t ↔ s = t := +@[simp] lemma homogenize_inj {s t : Set A} : homogenize ℋ s = homogenize ℋ t ↔ s = t := (homogenize_injective _).eq_iff -lemma homogenize_strictMono : StrictMono (homogenize hom : Set A → SubMulAction₀ R≥0 W) := +lemma homogenize_strictMono : StrictMono (homogenize ℋ : Set A → SubMulAction₀ R≥0 W) := (homogenize_monotone _).strictMono_of_injective (homogenize_injective _) lemma homogenize_mono_iff {s t : Set A} : - homogenize hom s ≤ homogenize hom t ↔ s ⊆ t where + homogenize ℋ s ≤ homogenize ℋ t ↔ s ⊆ t where mp := by intro h x hx rw [← ofPoint_mem_homogenize_iff (R := R) (W := W)] at ⊢ hx @@ -157,7 +157,7 @@ lemma homogenize_mono_iff {s t : Set A} : mpr := homogenize_mono _ lemma homogenize_singleton_eq {x y : A} : - homogenize hom {x} = homogenize hom {y} ↔ x = y := by simp + homogenize ℋ {x} = homogenize ℋ {y} ↔ x = y := by simp end Nontrivial @@ -170,43 +170,43 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) variable {x : A} {s : Set A} def _root_.SubMulAction₀.dehomogenize (S : SubMulAction₀ R≥0 W) : Set A := - hom.ofPoint ⁻¹' S + ℋ.ofPoint ⁻¹' S lemma dehomogenize_mono {S T : SubMulAction₀ R≥0 W} (h : S ≤ T) : - dehomogenize hom S ≤ dehomogenize hom T := + dehomogenize ℋ S ≤ dehomogenize ℋ T := Set.preimage_mono h -lemma dehomogenize_monotone : Monotone (dehomogenize hom : SubMulAction₀ R≥0 W → Set A) := +lemma dehomogenize_monotone : Monotone (dehomogenize ℋ : SubMulAction₀ R≥0 W → Set A) := fun _ _ => dehomogenize_mono _ /-- Homogenization from sets to `SubMulAction₀` as an order homomorphism. -/ def dehomogenizeOrderHom : SubMulAction₀ R≥0 W →o Set A where - toFun := dehomogenize hom + toFun := dehomogenize ℋ monotone' := dehomogenize_monotone _ -lemma dehomogenize_top : dehomogenize hom (⊤ : SubMulAction₀ R≥0 W) = Set.univ := by +lemma dehomogenize_top : dehomogenize ℋ (⊤ : SubMulAction₀ R≥0 W) = Set.univ := by ext x; simp [dehomogenize] lemma dehomogenize_inf (s t : SubMulAction₀ R≥0 W) : - dehomogenize hom (s ⊓ t) = dehomogenize hom s ∩ dehomogenize hom t := by + dehomogenize ℋ (s ⊓ t) = dehomogenize ℋ s ∩ dehomogenize ℋ t := by ext x; simp [dehomogenize] lemma dehomogenize_sup (s t : SubMulAction₀ R≥0 W) : - dehomogenize hom (s ⊔ t) = dehomogenize hom s ∪ dehomogenize hom t := by + dehomogenize ℋ (s ⊔ t) = dehomogenize ℋ s ∪ dehomogenize ℋ t := by ext x; simp [dehomogenize] def dehomogenizeLatticeHom : LatticeHom (SubMulAction₀ R≥0 W) (Set A) where - toFun := dehomogenize hom + toFun := dehomogenize ℋ map_sup' := dehomogenize_sup _ map_inf' := dehomogenize_inf _ lemma dehomogenize_sInf (S : Set (SubMulAction₀ R≥0 W)) : - dehomogenize hom (sInf S) = sInf (dehomogenize hom '' S) := by + dehomogenize ℋ (sInf S) = sInf (dehomogenize ℋ '' S) := by ext x; simp [dehomogenize] section Nontrivial @@ -214,27 +214,27 @@ section Nontrivial variable [Nontrivial R] lemma dehomogenize_sSup (S : Set (SubMulAction₀ R≥0 W)) : - dehomogenize hom (sSup S) = sSup (dehomogenize hom '' S) := by + dehomogenize ℋ (sSup S) = sSup (dehomogenize ℋ '' S) := by ext x; simpa [dehomogenize] using fun h => (ofPoint_ne_zero _ x h).elim def dehomogenizeCompleteLatticeHom : CompleteLatticeHom (SubMulAction₀ R≥0 W) (Set A) where - toFun := dehomogenize hom + toFun := dehomogenize ℋ map_sInf' := dehomogenize_sInf _ map_sSup' := dehomogenize_sSup _ -@[simp] lemma dehomogenize_bot : (⊥ : SubMulAction₀ R≥0 W).dehomogenize hom = ∅ := by +@[simp] lemma dehomogenize_bot : (⊥ : SubMulAction₀ R≥0 W).dehomogenize ℋ = ∅ := by ext x; simp only [Set.mem_empty_iff_false, iff_false]; exact ofPoint_ne_zero _ _ variable [IsOrderedRing R] in /-- Dehomogenizing the homogenization of a set yields the same set again. -/ @[simp] theorem dehomogenize_homogenize (s : Set A) : - dehomogenize hom (homogenize hom s) = s := by + dehomogenize ℋ (homogenize ℋ s) = s := by ext x; simp [dehomogenize] end Nontrivial variable [IsOrderedRing R] in -lemma homogenize_gc : GaloisConnection (homogenize hom) (dehomogenize hom) := +lemma homogenize_gc : GaloisConnection (homogenize ℋ) (dehomogenize ℋ) := .compose Set.image_preimage smulSet_gc end Ring_no_OrderedRing @@ -246,28 +246,28 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) @[simp] lemma dehomogenize_weight_positive : - dehomogenize hom (hom.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by + dehomogenize ℋ (ℋ.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by ext x; simp [dehomogenize, weight_one] lemma nonneg_smulSet_ofPoint_range_le_weight_positive : - R≥0 ∙ (Set.range hom.ofPoint) ≤ hom.weight.positive := by + R≥0 ∙ (Set.range ℋ.ofPoint) ≤ ℋ.weight.positive := by rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : - homogenize hom (Set.univ : Set A) ≤ hom.weight.positive := by + homogenize ℋ (Set.univ : Set A) ≤ ℋ.weight.positive := by simpa [homogenize] using nonneg_smulSet_ofPoint_range_le_weight_positive _ lemma homogenize_le_weight_positive (s : Set A) : - homogenize hom s ≤ hom.weight.positive := + homogenize ℋ s ≤ ℋ.weight.positive := le_trans (homogenize_mono _ (Set.subset_univ _)) (homogenize_univ_le_weight_positive _) @[simp] theorem homogenize_dehomogenize_le_weight_positive {S : SubMulAction₀ R≥0 W} : - homogenize hom (S.dehomogenize hom) ≤ S ⊓ hom.weight.positive := by - have aux : Set.range hom.ofPoint = hom.ofPoint.range := rfl + homogenize ℋ (S.dehomogenize ℋ) ≤ S ⊓ ℋ.weight.positive := by + have aux : Set.range ℋ.ofPoint = ℋ.ofPoint.range := rfl rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, aux] refine le_trans (smulSet_inter_le _ _) ?_ simp only [smulSet_eq, le_inf_iff, inf_le_left, true_and] @@ -282,24 +282,24 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] [Module.IsTorsionFree R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) /-- For the weaker version with `r = 1` see `ofPoint_mem_homogenize_iff`. -/ @[simp] lemma smul_ofPoint_mem_homogenize_iff {r : R} (hr : 0 < r) {x : A} (s : Set A) : - r • hom.ofPoint x ∈ homogenize hom s ↔ x ∈ s where + r • ℋ.ofPoint x ∈ homogenize ℋ s ↔ x ∈ s where mp := by rintro (h | ⟨x, ⟨y, hy, rfl⟩, ⟨r', hr'⟩, h⟩) · exfalso exact smul_ne_zero hr.ne.symm (ofPoint_ne_zero _ x) h - · have := congrArg hom.weight h + · have := congrArg ℋ.weight h simp only [map_smul, weight_one, smul_eq_mul, mul_one, Nonneg.mk_smul] at this rw [this] at hr h - rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, hom.ofPoint_injective.eq_iff] at h + rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, ℋ.ofPoint_injective.eq_iff] at h rwa [h] mpr := smul_ofPoint_mem_homogenize _ hr.le lemma homogenize_inter (s t : Set A) : - homogenize hom (s ∩ t) = homogenize hom s ⊓ homogenize hom t := by + homogenize ℋ (s ∩ t) = homogenize ℋ s ⊓ homogenize ℋ t := by apply le_antisymm · exact homogenize_inter_le _ s t · rintro x hx @@ -310,12 +310,12 @@ lemma homogenize_inter (s t : Set A) : /-- Homogenization from sets to `SubMulAction₀` as a lattice homomorphism. -/ def homogenizeLatticeHom : LatticeHom (Set A) (SubMulAction₀ R≥0 W) where - toFun := homogenize hom + toFun := homogenize ℋ map_sup' := homogenize_union _ map_inf' := homogenize_inter _ lemma homogenize_sInf {S : Set (Set A)} (hS : S.Nonempty) : - homogenize hom (sInf S) = sInf (homogenize hom '' S) := by + homogenize ℋ (sInf S) = sInf (homogenize ℋ '' S) := by apply le_antisymm · exact homogenize_sInf_le _ S intro x hx @@ -335,14 +335,14 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : - R≥0 ∙ (Set.range hom.ofPoint) = hom.weight.positive := by + R≥0 ∙ (Set.range ℋ.ofPoint) = ℋ.weight.positive := by rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_eq_positive _ -@[simp] lemma homogenize_univ : homogenize hom (Set.univ : Set A) = hom.weight.positive := by +@[simp] lemma homogenize_univ : homogenize ℋ (Set.univ : Set A) = ℋ.weight.positive := by simpa [homogenize] using nonneg_smulSet_ofPoint_range _ end DivisionRing @@ -354,21 +354,21 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable (hom : IsHomogenization R A W) +variable (ℋ : IsHomogenization R A W) @[simp] theorem homogenize_dehomogenize {S : SubMulAction₀ R≥0 W} : - homogenize hom (S.dehomogenize hom) = S ⊓ hom.weight.positive := by + homogenize ℋ (S.dehomogenize ℋ) = S ⊓ ℋ.weight.positive := by rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, smulSet_inter_left, nonneg_smulSet_ofPoint_range] -variable {hom} in +variable {ℋ} in @[simp] theorem homogenize_dehomogenize_of_le_weight_positive {S : SubMulAction₀ R≥0 W} - (hS : S ≤ hom.weight.positive) : homogenize hom (S.dehomogenize hom) = S := by + (hS : S ≤ ℋ.weight.positive) : homogenize ℋ (S.dehomogenize ℋ) = S := by simp [homogenize_dehomogenize, hS] -def homogenizeOrderIso : Set A ≃o Set.Iic (hom.weight.positive : SubMulAction₀ R≥0 W) where +def homogenizeOrderIso : Set A ≃o Set.Iic (ℋ.weight.positive : SubMulAction₀ R≥0 W) where toFun s := ⟨_, homogenize_le_weight_positive _ s⟩ - invFun S := S.1.dehomogenize hom + invFun S := S.1.dehomogenize ℋ left_inv := dehomogenize_homogenize _ right_inv S := by simp only [homogenize_dehomogenize_of_le_weight_positive S.2] map_rel_iff' := homogenize_mono_iff _ From 3b4ddd2c99f7ffc52ed1e5c1f22b25abf0bd5fc1 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 15 Sep 2026 17:04:40 +0200 Subject: [PATCH 04/39] forgot one --- .../Geometry/Convex/ConvexSpace/Set/Homogenization.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 3b091332..2a080fda 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -71,11 +71,11 @@ lemma homogenize_le_weight_positive (K : ConvexSet R A) : rintro ⟨x, -, rfl⟩ simp [ℋ.weight_one] -variable {hom} in +variable {ℋ} in lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize ℋ P) (hx : x ≠ 0) : 0 < ℋ.weight x := homogenize_le_weight_positive _ P h hx -variable {hom} in +variable {ℋ} in lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ homogenize ℋ P) : 0 ≤ ℋ.weight x := (LinearMap.mem_positive'.mp (homogenize_le_weight_positive _ P h)).1 @@ -83,7 +83,7 @@ lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ hom lemma homogenize_salient (K : ConvexSet R A) : PointedCone.Salient (homogenize ℋ K) := Salient.of_le_salient ℋ.weight.positive_salient (homogenize_le_weight_positive _ K) -variable {hom} in +variable {ℋ} in theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize ℋ C).FG) : ∃ g : Finset W, PointedCone.hull R g = homogenize ℋ C ∧ (g : Set W) ⊆ Set.range ℋ.ofPoint := by From c19e5ef6f5f14dfe6b836bea422d6f683784767b Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 17 Sep 2026 14:37:11 +0200 Subject: [PATCH 05/39] trying out new definition of homogenization --- .../Convex/ConvexSpace/Homogenization.lean | 4 +- .../ConvexSpace/Set/Face/Homogenization.lean | 2 +- .../ConvexSpace/Set/Homogenization.lean | 12 +- .../AffineSpace/Homogenization/Basic.lean | 268 ++++++++---------- .../AffineSpace/Homogenization/Canonical.lean | 62 ++++ .../AffineSpace/Homogenization/Set.lean | 10 +- 6 files changed, 200 insertions(+), 158 deletions(-) create mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean index 5d604df0..23e0442a 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean @@ -54,10 +54,10 @@ theorem exists_sConvexComb_preimage_of_mem_hull {x} {s : Set W} (hs : s ⊆ Set. have hsum : c.sum (fun a b => b * ℋ.weight a) = c.sum (fun a b => b) := by refine Finsupp.sum_congr (fun a h => ?_) obtain ⟨_, _, rfl⟩ := (ha.trans hs) h - simp [ℋ.weight_one] + simp [ℋ.weight_ofPoint] -- apply weights map to both sides have := congrArg ℋ.weight hc - simp only [map_finsuppSum, map_smul, smul_eq_mul, hsum, ℋ.weight_one] at this + simp only [map_finsuppSum, map_smul, smul_eq_mul, hsum, ℋ.weight_ofPoint] at this rw [← this] simp only [Finsupp.sum, Finsupp.comapDomain_support, Finsupp.comapDomain_apply] rw [Finset.sum_preimage ℋ.ofPoint _ (ℋ.ofPoint_injective.injOn)] diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean index eeaadbea..25ceb7a9 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean @@ -37,7 +37,7 @@ theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} (h₁ : 0 < r₁) (h₂ : 0 < r₂) (hₜ : 0 < t) (h : r₁ • ℋ.ofPoint p₁ + r₂ • ℋ.ofPoint p₂ = t • ℋ.ofPoint q) : q ∈ Convexity.openSegment R p₁ p₂ := by - have : r₁ + r₂ = t := by simpa [ℋ.weight_one, map_add, map_smul] using congr_arg ℋ.weight h + have : r₁ + r₂ = t := by simpa [ℋ.weight_ofPoint, map_add, map_smul] using congr_arg ℋ.weight h have : t⁻¹ • r₁ + t⁻¹ • r₂ = 1 := by simp_rw [← smul_add, smul_eq_mul, this, mul_comm, Field.mul_inv_cancel _ hₜ.ne.symm] use (t⁻¹ • r₁), (t⁻¹ • r₂), (smul_pos (by positivity) h₁), (smul_pos (by positivity) h₂), this diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 2a080fda..70a3d0b6 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -69,7 +69,7 @@ lemma homogenize_le_weight_positive (K : ConvexSet R A) : homogenize ℋ K ≤ ℋ.weight.positive := by exact LinearMap.hull_le_positive_of_subset_preimage_singleton one_pos fun _ ↦ by rintro ⟨x, -, rfl⟩ - simp [ℋ.weight_one] + simp [ℋ.weight_ofPoint] variable {ℋ} in lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize ℋ P) (hx : x ≠ 0) : @@ -126,7 +126,7 @@ lemma dehomogenize_top : dehomogenize ℋ (⊤ : PointedCone R W) = ⊤ := by @[simp] lemma dehomogenize_weight_positive : dehomogenize ℋ ℋ.weight.positive = ⊤ := - SetLike.eq_top_of_forall fun _ ↦ LinearMap.mem_positive'.mpr (by simp [ℋ.weight_one]) + SetLike.eq_top_of_forall fun _ ↦ LinearMap.mem_positive'.mpr (by simp [ℋ.weight_ofPoint]) lemma dehomogenize_mono {C₁ C₂ : PointedCone R W} (h : C₁ ≤ C₂) : dehomogenize ℋ C₁ ≤ dehomogenize ℋ C₂ := Set.preimage_mono <| Set.preimage_mono h @@ -169,7 +169,7 @@ variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ lemma homogenize_top : homogenize ℋ (⊤ : ConvexSet R A) = ℋ.weight.positive := by rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton ℋ.weight one_pos, - ← ℋ.ofPoint_range_eq_preimage_weight_one] + ← ℋ.ofPoint_range_eq_preimage_weight_ofPoint] congr! with x simp @@ -189,7 +189,7 @@ lemma ofPoint_mem_homogenize_iff_mem (x : A) (P : ConvexSet R A) : obtain ⟨_, _, h'⟩ := smul_pos_of_mem_homogenize (Set.mem_preimage.mpr h) (ℋ.ofPoint_ne_zero x) obtain ⟨_, ⟨_, _, hyy'⟩, hy'⟩ := Set.mem_smul_set.mp h' have := congrArg ℋ.weight hy' - simp [← hyy', ℋ.weight_one] at this + simp [← hyy', ℋ.weight_ofPoint] at this simp only [this, Set.mem_image, one_smul, exists_eq_right] at h' obtain ⟨_, _, hxx'⟩ := h' simpa [← ℋ.ofPoint_injective hxx'] @@ -215,14 +215,14 @@ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} · apply SetLike.ext' unfold homogenize rw [eq_Ici_zero_smul_inter_preimage_of_pos_of_ne_bot hC zero_lt_one hbot, - ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_one] + ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_ofPoint] apply hull_eq_smul · obtain ⟨y, hyC, hy0⟩ := exists_mem_ne_zero_of_ne_bot hbot let y' := (ℋ.weight y)⁻¹ • y have hy'C : y' ∈ C := C.smul_mem (inv_nonneg.mpr (@hC y hyC hy0).le) hyC have hy' : y' ∈ Set.range ℋ.ofPoint := by - simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] + simpa [y', ℋ.ofPoint_range_eq_preimage_weight_ofPoint] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ · exact C.isConvexSet.inter ℋ.ofPoint.range_isConvexSet diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index 5cc5bef7..95ca61e2 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -7,18 +7,15 @@ module public import Mathlib.LinearAlgebra.AffineSpace.Homogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineMap +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Canonical -import Mathlib.Geometry.Convex.ConvexSpace.Module -import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic - -/-! This file defines affine homogenization axiomatically and proves every object fulfilling the -axioms is linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. +/-! This file defines affine homogenization as any vector space linearly equivalent to +`Homogenization`, the canonical homogenization from Mathlib. It also proves every such object +satisfies the axiomatic description from [Gallier2011GeometricMethods]. ## Implementation notes * The axiomatization in the literature is redundant. The universal property can be proven solely -from the subset of axioms used in `IsHomogenization`, as is done in lemma `extend`. It is -convenient to use the linear equivalence between any homogenization and `Homogenization` -for the proof. +from the subset of axioms used in the `ofEmbed` constructor, as is done by providing `lift`. ## References @@ -26,7 +23,7 @@ for the proof. Engineering*][Gallier2011GeometricMethods] -/ -@[expose] public section +public noncomputable section namespace Affine @@ -40,172 +37,141 @@ variable {A : Type*} [AddTorsor V A] variable {W : Type*} [AddCommGroup W] [Module R W] variable (R A W) in -/-- An embedding of an affine space `A` into a vector space `W` s.t. the image of `A` is exactly the -weight-1 hyperplane under a given linear weight map. -Follows Definition 4.2 in [Gallier2011GeometricMethods] -https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -structure IsHomogenization where - ofPoint : A →ᵃ[R] W - ofPoint_injective : Injective ofPoint - weight : W →ₗ[R] R - ofPoint_range_eq_preimage_weight_one : Set.range ofPoint = weight ⁻¹' {1} - -variable (R A) in -/-- The canonical homogenization is a homogenization. -/ -noncomputable def IsHomogenization.canonical : - IsHomogenization R A (Homogenization R A) where - ofPoint := Homogenization.ofPoint - ofPoint_injective := Homogenization.ofPoint_injective - weight := Homogenization.weight - ofPoint_range_eq_preimage_weight_one := by - ext x - constructor - · rintro ⟨a, rfl⟩ - simp - · exact fun hx ↦ (Homogenization.weight_eq_one_iff.mp hx).imp fun _ hp ↦ hp.symm +/-- A triple of a ring `R`, `R`-affine space `A` and `R`-vector space `W` is a homogenization if +`W` is linearly equivalent to the canonical homogenization. -/ +structure IsHomogenization where ofRepr :: + repr : W ≃ₗ[R] Homogenization R A namespace IsHomogenization variable (ℋ : IsHomogenization R A W) -abbrev ofVector := ℋ.ofPoint.linear +/-- The embedding of the affine space into the homogenization. -/ +@[expose] +def ofPoint : A →ᵃ[R] W := ℋ.repr.symm.toAffineMap.comp Homogenization.ofPoint + +/-- The embedding of the vector space into the homogenization. -/ +@[expose] +def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization.ofVector + +/-- The linear map that is constantly `1` when restricted to `A`. -/ +def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap + +/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector +space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the +axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] +https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ +def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} + (embed_range : Set.range embed = weight ⁻¹' {1}) : + IsHomogenization R A W where + repr := (LinearEquiv.ofBijective (Homogenization.lift embed) + (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm + +/-- The embedding used in the construction becomes the embedding in the homogenization. -/ +theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).ofPoint = embed := by + ext p + exact Homogenization.lift_apply_ofPoint .. + +/-- The weight used in the construction becomes the weight in the homogenization. -/ +theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).weight = weight := by + ext w + unfold IsHomogenization.weight + have : Homogenization.lift embed ((ofEmbed embed_inj embed_range).repr w) = w := by + rw [← LinearEquiv.ofBijective_apply] + exact LinearEquiv.apply_symm_apply _ w + rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] + congr + exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm + +lemma ofPoint_injective : Injective ℋ.ofPoint := by + simpa [ofPoint] using Homogenization.ofPoint_injective theorem ofVector_injective : Injective ℋ.ofVector := by - simp [ℋ.ofPoint_injective] + simpa [ofVector] using Homogenization.ofVector_injective + +theorem weight_eq_zero_iff {x : W} : ℋ.weight x = 0 ↔ ∃ v, x = ℋ.ofVector v := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofVector] using Homogenization.weight_eq_zero_iff + +theorem weight_eq_one_iff {x : W} : ℋ.weight x = 1 ↔ ∃ p, x = ℋ.ofPoint p := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff + +lemma ofPoint_range_eq_preimage_weight_ofPoint : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by + ext + simp [weight_eq_one_iff] + simp [eq_comm] + +lemma ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by + ext + simp [weight_eq_zero_iff] + simp [eq_comm] /-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by + apply SetLike.ext' + rw [LinearMap.coe_range, ofVector_range_eq_preimage_weight_zero, LinearMap.ker] ext x - let a₀ := Classical.arbitrary A - simp only [LinearMap.mem_range, LinearMap.mem_ker] - have : (∃ y, ℋ.ofVector y = x) ↔ ∃ a b : A, ℋ.ofVector (a -ᵥ b) = x := - ⟨fun ⟨y, hy⟩ => ⟨y +ᵥ a₀, a₀, by simp [vadd_vsub, hy]⟩, fun ⟨a, b, hab⟩ => ⟨a -ᵥ b, hab⟩⟩ - rw [this] - have hh := Set.ext_iff.mp ℋ.ofPoint_range_eq_preimage_weight_one - constructor - · rintro ⟨a, b, hab⟩ - simp only [Set.mem_preimage, Set.mem_singleton_iff] at hh - simp [← hab, map_sub, (hh (ℋ.ofPoint b)).mp ⟨b, rfl⟩, (hh (ℋ.ofPoint a)).mp ⟨a, rfl⟩] - · intro h - have ha := Set.mem_preimage.mp <| (hh (ℋ.ofPoint a₀)).mp (by simp) - obtain ⟨b, hb⟩ : x + ℋ.ofPoint a₀ ∈ (Set.range ℋ.ofPoint) := by - simpa [ℋ.ofPoint_range_eq_preimage_weight_one, Set.mem_preimage, map_add, h] - exact ⟨b, a₀, by simp [AffineMap.linearMap_vsub, hb]⟩ - -/-- The homogenization of a point in `A` has weight 1. -/ -lemma weight_one (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by - convert Set.ext_iff.mp ℋ.ofPoint_range_eq_preimage_weight_one (ℋ.ofPoint a₀) - simp [exists_apply_eq_apply, Set.mem_preimage, Set.mem_singleton_iff, true_iff] + simp variable [Nontrivial R] in theorem ofPoint_ne_zero (x : A) : ℋ.ofPoint x ≠ (0 : W) := by intro hn have := congrArg ℋ.weight hn - simp [ℋ.weight_one x] at this + simp [weight, ofPoint] at this + +/-- The homogenization of a point in `A` has weight 1. -/ +lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] /-- The homogenization of a point in `V` has weight 0. -/ -lemma weight_zero (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by - simp [LinearMap.mem_ker.mp, ← ofVector_range_eq_weight_ker] +lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by - refine eq_top_iff'.mpr (fun x ↦ ?_) - let a₀ := Classical.arbitrary A - -- projecting x to weight 0 along a₀ gives sth in the span of image of ofPoint - have hlin : x - ℋ.weight x • ℋ.ofPoint a₀ ∈ Submodule.span R ℋ.ofPoint.range := by - obtain ⟨v, hv⟩ : x - ℋ.weight x • ℋ.ofPoint a₀ ∈ ℋ.ofVector.range := by - simp [ofVector_range_eq_weight_ker, ℋ.weight_one a₀] - have : ℋ.ofVector v = ℋ.ofPoint (v +ᵥ a₀) - ℋ.ofPoint a₀ := by simp - rw [← hv, this] - apply Submodule.sub_mem <;> apply Submodule.subset_span - · exact ⟨v +ᵥ a₀, rfl⟩ - · exact ⟨a₀, rfl⟩ - simpa using - Submodule.add_mem _ hlin <| smul_mem _ (ℋ.weight x) (subset_span ⟨a₀, rfl⟩) - -/-- The canonical linear map from `Homogenization R A` to any homogenization `W` of `A`. -/ -noncomputable def ofCanonical : Homogenization R A →ₗ[R] W := Homogenization.lift ℋ.ofPoint - -@[simp] lemma ofCanonical_ofPoint (a : A) : - ℋ.ofCanonical (Homogenization.ofPoint a) = ℋ.ofPoint a := by - simp [ofCanonical] - -@[simp] lemma ofCanonical_ofVector (v : V) : - ℋ.ofCanonical (Homogenization.ofVector v) = ℋ.ofVector v := by - simp [ofCanonical] - -lemma weight_comp_ofCanonical : - ℋ.weight ∘ₗ ℋ.ofCanonical = (Homogenization.weight : Homogenization R A →ₗ[R] R) := - Homogenization.hom_ext fun a ↦ by simp [weight_one] - -@[simp] lemma weight_ofCanonical (x : Homogenization R A) : - ℋ.weight (ℋ.ofCanonical x) = Homogenization.weight x := - congr($(weight_comp_ofCanonical _) x) - -theorem ofCanonical_bijective : Bijective ℋ.ofCanonical := by + simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint + +lemma weight_comp_repr : + ℋ.weight ∘ₗ ℋ.repr.symm = (Homogenization.weight : Homogenization R A →ₗ[R] R) := + Homogenization.hom_ext fun a ↦ by simp [weight] + +@[simp] lemma weight_repr (x : Homogenization R A) : + ℋ.weight (ℋ.repr.symm x) = Homogenization.weight x := + congr($(weight_comp_repr _) x) + +theorem repr_bijective : Bijective ℋ.repr := by constructor - · rw [injective_iff_map_eq_zero] - intro x hx - have hw : Homogenization.weight x = 0 := by - rw [← ℋ.weight_ofCanonical x, hx, map_zero] - obtain ⟨v, rfl⟩ := Homogenization.weight_eq_zero_iff.mp hw - rw [ofCanonical_ofVector, map_eq_zero_iff _ ℋ.ofVector_injective] at hx - simp [hx] - · rw [← LinearMap.range_eq_top, ← top_le_iff, ← ℋ.span_range_ofPoint, Submodule.span_le, - Set.range_subset_iff] - exact fun a ↦ ⟨Homogenization.ofPoint a, by simp⟩ - -/-- Every homogenization is linearly equivalent to the canonical homogenization. -/ -noncomputable def canonEquiv : W ≃ₗ[R] Homogenization R A := - (LinearEquiv.ofBijective _ ℋ.ofCanonical_bijective).symm - -@[simp] lemma canonEquiv_symm_apply (x : Homogenization R A) : - ℋ.canonEquiv.symm x = ℋ.ofCanonical x := - rfl - -@[simp] lemma ofCanonical_canonEquiv (x : W) : ℋ.ofCanonical (ℋ.canonEquiv x) = x := - ℋ.canonEquiv.symm_apply_apply x - -@[simp] lemma canonEquiv_ofPoint (a : A) : - ℋ.canonEquiv (ℋ.ofPoint a) = Homogenization.ofPoint a := - ℋ.canonEquiv.symm.injective <| by simp - -theorem canonEquiv_canonical_ofPoint : - ℋ.canonEquiv ∘ ℋ.ofPoint = Homogenization.ofPoint := by + · simp [injective_iff_map_eq_zero] + · intro x + use ℋ.repr.symm x + simp + +@[simp] lemma repr_ofPoint (a : A) : + ℋ.repr (ℋ.ofPoint a) = Homogenization.ofPoint a := + by simp [ofPoint] + +theorem repr_canonical_ofPoint : + ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by ext a; simp -theorem weight_canonEquiv : Homogenization.weight ∘ ℋ.canonEquiv = ℋ.weight := by - ext x - rw [Function.comp_apply, ← ℋ.weight_ofCanonical (ℋ.canonEquiv x), - ofCanonical_canonEquiv] - --- proving the universal property using the equiv -/-- A homogenization `W` of `A` satisfies the universal property that every affine map from `A` -into any vector space extends uniquely to a linear map from `W` to the vector space. -/ -theorem extend (U : Type*) [AddCommGroup U] [Module R U] - (f : A →ᵃ[R] U) : - ∃! (F : W →ₗ[R] U), F ∘ ℋ.ofPoint = f := by - refine ⟨Homogenization.lift f ∘ₗ ℋ.canonEquiv.toLinearMap, funext fun a ↦ by simp, ?_⟩ - intro g hg - have : g ∘ₗ ℋ.canonEquiv.symm.toLinearMap = Homogenization.lift f := - Homogenization.hom_ext fun a ↦ by simpa using congrFun hg a - rw [← this, LinearMap.comp_assoc] - simp +variable {U : Type*} [AddCommGroup U] [Module R U] in +/-- An affine map on `A` taking values in a vector space extends uniquely to a linear map on `W`. +-/ +abbrev lift : (A →ᵃ[R] U) ≃+ (W →ₗ[R] U) := + Homogenization.lift.trans (ℋ.repr.arrowCongrAddEquiv (LinearEquiv.refl ..)).symm open AffineMap LinearEquiv in /-- The linear equivalence between the underlying vector space and its embedding. -/ -noncomputable def ofVectorRangeEquiv : V ≃ₗ[R] ℋ.ofVector.range := { +def ofVectorRangeEquiv : V ≃ₗ[R] ℋ.ofVector.range where toFun v := ⟨ℋ.ofVector v, ℋ.ofVector.mem_range_self v⟩ map_add' v w := by simp map_smul' r v := by simp - invFun := - (ofInjective ℋ.ofVector (linear_injective_iff _ |>.mpr ℋ.ofPoint_injective)).invFun - left_inv := - (ofInjective ℋ.ofVector (linear_injective_iff _ |>.mpr ℋ.ofPoint_injective)).left_inv - right_inv v' := by simp -} + invFun := (ofInjective ℋ.ofVector (linear_injective_iff _ |>.mpr ℋ.ofPoint_injective)).invFun + left_inv := LinearEquiv.left_inv _ + right_inv := LinearEquiv.right_inv _ /-- The affine equivalence between the affine space space and its embedding. -/ -public noncomputable def ofPointRangeEquiv : A ≃ᵃ[R] ℋ.ofPoint.range := +public def ofPointRangeEquiv : A ≃ᵃ[R] ℋ.ofPoint.range := .ofBijective ⟨ℋ.ofPoint.rangeRestrict_injective_iff.mpr ℋ.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ @@ -214,6 +180,20 @@ lemma apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : rw [← ℋ.ofPointRangeEquiv.right_inv x] congr; exact ℋ.ofPointRangeEquiv.symm_apply_apply _ +section Instances + +variable (R A) in +/-- The canonical homogenization is a homogenization. -/ +def canonical : IsHomogenization R A (Homogenization R A) := ofRepr <| LinearEquiv.refl .. + +/-- A module is a homogenization of the weight-one hyperplane of any linear functional, +provided that hyperplane is nonempty. -/ +def ofWeight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := + ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + +end Instances + end IsHomogenization end Ring diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean new file mode 100644 index 00000000..c54f7381 --- /dev/null +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean @@ -0,0 +1,62 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig, Martin Winter +-/ +module + +public import Mathlib.LinearAlgebra.AffineSpace.Homogenization + +/-! This file defines affine homogenization axiomatically and proves every object fulfilling the +axioms is linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. + +## Implementation notes +* The axiomatization in the literature is redundant. The universal property can be proven solely +from the subset of axioms used in `IsHomogenization`, as is done in lemma `extend`. It is +convenient to use the linear equivalence between any homogenization and `Homogenization` +for the proof. + +## References + +* [J. Gallier, *Geometric Methods and Applications for Computer Science and + Engineering*][Gallier2011GeometricMethods] + -/ + +public noncomputable section + +namespace Homogenization + +open Function Homogenization + +variable {R : Type*} [Ring R] +variable {V : Type*} [AddCommGroup V] [Module R V] +variable {A : Type*} [AddTorsor V A] +variable {W : Type*} [AddCommGroup W] [Module R W] + +variable {f : A →ᵃ[R] W} {g : W →ₗ[R] R} + +lemma comp_lift_eq_weight_of_range_preimage (f_range : Set.range f = g ⁻¹' {1}) : + g ∘ₗ (lift f) = weight := by + refine hom_ext (fun p ↦ ?_) + have := f_range ▸ Set.mem_range_self p + simpa [LinearMap.comp_apply, lift_apply_ofPoint, weight_ofPoint] using this + +lemma lift_bijective_of_injective_of_range_preimage (f_inj : Injective f) + (f_range : Set.range f = g ⁻¹' {1}) : Bijective (lift f) := by + constructor + · rw [injective_iff_map_eq_zero] + intro a ha + have : weight a = 0 := by simp [← comp_lift_eq_weight_of_range_preimage f_range, ha] + obtain ⟨_, rfl⟩ := weight_eq_zero_iff.mp this + rw [lift_apply_ofVector] at ha + simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr f_inj)).mp ha] + · intro w + obtain p₀ := Classical.arbitrary A + obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by + have hmem := f_range ▸ Set.mem_range_self p₀ + have : g (w - g w • f p₀ + f p₀) = 1 := by + rw [map_add, map_sub, map_smul, hmem, smul_eq_mul, mul_one, sub_self, zero_add] + rw [f_range]; simpa using this + exact ⟨ofVector (a -ᵥ p₀) + g w • ofPoint p₀, by simp [ha]⟩ + +end Homogenization diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index dbed16a0..b6b64557 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -127,7 +127,7 @@ variable [Nontrivial R] rintro (h | ⟨x, ⟨y, hy, rfl⟩, r, h⟩) · exfalso; exact ofPoint_ne_zero _ _ h · have := congrArg ℋ.weight h - simp only [weight_one, ← Nonneg.coe_smul, map_smul, smul_eq_mul, mul_one, + simp only [weight_ofPoint, ← Nonneg.coe_smul, map_smul, smul_eq_mul, mul_one, Eq.comm, Nonneg.coe_eq_one] at this rw [this, one_smul] at h rwa [ℋ.ofPoint_injective h] @@ -250,11 +250,11 @@ variable (ℋ : IsHomogenization R A W) @[simp] lemma dehomogenize_weight_positive : dehomogenize ℋ (ℋ.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by - ext x; simp [dehomogenize, weight_one] + ext x; simp [dehomogenize, weight_ofPoint] lemma nonneg_smulSet_ofPoint_range_le_weight_positive : R≥0 ∙ (Set.range ℋ.ofPoint) ≤ ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_one] + rw [ofPoint_range_eq_preimage_weight_ofPoint] exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : @@ -292,7 +292,7 @@ variable (ℋ : IsHomogenization R A W) · exfalso exact smul_ne_zero hr.ne.symm (ofPoint_ne_zero _ x) h · have := congrArg ℋ.weight h - simp only [map_smul, weight_one, smul_eq_mul, mul_one, Nonneg.mk_smul] at this + simp only [map_smul, weight_ofPoint, smul_eq_mul, mul_one, Nonneg.mk_smul] at this rw [this] at hr h rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, ℋ.ofPoint_injective.eq_iff] at h rwa [h] @@ -339,7 +339,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : R≥0 ∙ (Set.range ℋ.ofPoint) = ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_one] + rw [ofPoint_range_eq_preimage_weight_ofPoint] exact nonneg_smulSet_preimage_one_eq_positive _ @[simp] lemma homogenize_univ : homogenize ℋ (Set.univ : Set A) = ℋ.weight.positive := by From 8e2160844c5161875b1bcf5fe489744d9f9fcf59 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 17 Sep 2026 15:50:28 +0200 Subject: [PATCH 06/39] addin two little lemmas --- .../Geometry/Convex/ConvexSpace/Set/Homogenization.lean | 5 +++++ .../LinearAlgebra/AffineSpace/Homogenization/Basic.lean | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 70a3d0b6..5d099514 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -47,6 +47,11 @@ def homogenizeOrderHom : ConvexSet R A →o PointedCone R W where toFun := homogenize ℋ monotone' := homogenize_monotone _ +@[simp] +lemma homogenize_singleton (p : A) : homogenize ℋ ({p} : ConvexSet R A) = R ∙₊ ℋ.ofPoint p := by + have h : (({p} : ConvexSet R A) : Set A) = {p} := rfl + rw [homogenize, h, Set.image_singleton] + @[simp] lemma homogenize_bot : homogenize ℋ (⊥ : ConvexSet R A) = ⊥ := by simp [homogenize, Bot.bot] diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index 95ca61e2..e73dbc62 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -192,6 +192,11 @@ def ofWeight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineM IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) +@[simp] +lemma ofWeight_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + (ofWeight g).weight = g := by + simp [ofWeight, ofEmbed_weight] + end Instances end IsHomogenization From 4c27f20ddad6eebef093ca3844dd19d424232693 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 21 Sep 2026 10:48:50 +0200 Subject: [PATCH 07/39] cleanup --- .../ConvexSpace/Set/Homogenization.lean | 6 +- .../AffineSpace/Homogenization/Basic.lean | 128 ++++++++---------- .../AffineSpace/Homogenization/Set.lean | 4 +- 3 files changed, 61 insertions(+), 77 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 5d099514..2951a544 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -174,7 +174,7 @@ variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ lemma homogenize_top : homogenize ℋ (⊤ : ConvexSet R A) = ℋ.weight.positive := by rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton ℋ.weight one_pos, - ← ℋ.ofPoint_range_eq_preimage_weight_ofPoint] + ← ℋ.ofPoint_range_eq_preimage_weight_one] congr! with x simp @@ -220,14 +220,14 @@ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} · apply SetLike.ext' unfold homogenize rw [eq_Ici_zero_smul_inter_preimage_of_pos_of_ne_bot hC zero_lt_one hbot, - ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_ofPoint] + ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_one] apply hull_eq_smul · obtain ⟨y, hyC, hy0⟩ := exists_mem_ne_zero_of_ne_bot hbot let y' := (ℋ.weight y)⁻¹ • y have hy'C : y' ∈ C := C.smul_mem (inv_nonneg.mpr (@hC y hyC hy0).le) hyC have hy' : y' ∈ Set.range ℋ.ofPoint := by - simpa [y', ℋ.ofPoint_range_eq_preimage_weight_ofPoint] + simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ · exact C.isConvexSet.inter ℋ.ofPoint.range_isConvexSet diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index e73dbc62..ebcf6654 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -57,36 +57,6 @@ def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization. /-- The linear map that is constantly `1` when restricted to `A`. -/ def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap -/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector -space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the -axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] -https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} - (embed_range : Set.range embed = weight ⁻¹' {1}) : - IsHomogenization R A W where - repr := (LinearEquiv.ofBijective (Homogenization.lift embed) - (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm - -/-- The embedding used in the construction becomes the embedding in the homogenization. -/ -theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).ofPoint = embed := by - ext p - exact Homogenization.lift_apply_ofPoint .. - -/-- The weight used in the construction becomes the weight in the homogenization. -/ -theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).weight = weight := by - ext w - unfold IsHomogenization.weight - have : Homogenization.lift embed ((ofEmbed embed_inj embed_range).repr w) = w := by - rw [← LinearEquiv.ofBijective_apply] - exact LinearEquiv.apply_symm_apply _ w - rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] - congr - exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm - lemma ofPoint_injective : Injective ℋ.ofPoint := by simpa [ofPoint] using Homogenization.ofPoint_injective @@ -99,15 +69,26 @@ theorem weight_eq_zero_iff {x : W} : ℋ.weight x = 0 ↔ ∃ v, x = ℋ.ofVecto theorem weight_eq_one_iff {x : W} : ℋ.weight x = 1 ↔ ∃ p, x = ℋ.ofPoint p := by simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff -lemma ofPoint_range_eq_preimage_weight_ofPoint : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by - ext - simp [weight_eq_one_iff] - simp [eq_comm] +lemma ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by + ext; simp [↓weight_eq_one_iff, eq_comm] lemma ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by - ext - simp [weight_eq_zero_iff] - simp [eq_comm] + ext; simp [↓weight_eq_zero_iff, eq_comm] + +/-- The homogenization of a point in `A` has weight 1. -/ +@[simp] +lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] + +/-- The homogenization of a point in `V` has weight 0. -/ +@[simp] +lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] + +-- the following two are in canonical hom in #43448 +theorem ofPoint_ne_ofVector [Nontrivial R] (x : A) (v : V) : ℋ.ofPoint x ≠ ℋ.ofVector v := + ne_of_apply_ne ℋ.weight <| by simp + +theorem ofPoint_ne_zero [Nontrivial R] (x : A) : ℋ.ofPoint x ≠ 0 := by + simpa using ℋ.ofPoint_ne_ofVector x 0 /-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by @@ -116,43 +97,16 @@ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by ext x simp -variable [Nontrivial R] in -theorem ofPoint_ne_zero (x : A) : ℋ.ofPoint x ≠ (0 : W) := by - intro hn - have := congrArg ℋ.weight hn - simp [weight, ofPoint] at this - -/-- The homogenization of a point in `A` has weight 1. -/ -lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] - -/-- The homogenization of a point in `V` has weight 0. -/ -lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] - theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint lemma weight_comp_repr : - ℋ.weight ∘ₗ ℋ.repr.symm = (Homogenization.weight : Homogenization R A →ₗ[R] R) := - Homogenization.hom_ext fun a ↦ by simp [weight] - -@[simp] lemma weight_repr (x : Homogenization R A) : - ℋ.weight (ℋ.repr.symm x) = Homogenization.weight x := - congr($(weight_comp_repr _) x) - -theorem repr_bijective : Bijective ℋ.repr := by - constructor - · simp [injective_iff_map_eq_zero] - · intro x - use ℋ.repr.symm x - simp - -@[simp] lemma repr_ofPoint (a : A) : - ℋ.repr (ℋ.ofPoint a) = Homogenization.ofPoint a := - by simp [ofPoint] + ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := A) := by + simp [weight, LinearMap.comp_assoc] -theorem repr_canonical_ofPoint : +theorem repr_comp_ofPoint : ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by - ext a; simp + ext a; simp [ofPoint] variable {U : Type*} [AddCommGroup U] [Module R U] in /-- An affine map on `A` taking values in a vector space extends uniquely to a linear map on `W`. @@ -186,16 +140,46 @@ variable (R A) in /-- The canonical homogenization is a homogenization. -/ def canonical : IsHomogenization R A (Homogenization R A) := ofRepr <| LinearEquiv.refl .. +/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector +space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the +axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] +https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ +def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} + (embed_range : Set.range embed = weight ⁻¹' {1}) : + IsHomogenization R A W where + repr := (LinearEquiv.ofBijective (Homogenization.lift embed) + (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm + +/-- The embedding used in the construction becomes the embedding in the homogenization. -/ +theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).ofPoint = embed := by + ext p + exact Homogenization.lift_apply_ofPoint .. + +/-- The weight used in the construction becomes the weight in the homogenization. -/ +theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).weight = weight := by + ext w + unfold IsHomogenization.weight + have : Homogenization.lift embed ((ofEmbed embed_inj embed_range).repr w) = w := by + rw [← LinearEquiv.ofBijective_apply] + exact LinearEquiv.apply_symm_apply _ w + rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] + congr + exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm + /-- A module is a homogenization of the weight-one hyperplane of any linear functional, provided that hyperplane is nonempty. -/ -def ofWeight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : +def ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -lemma ofWeight_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - (ofWeight g).weight = g := by - simp [ofWeight, ofEmbed_weight] +lemma ofWeightOne_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + (ofWeightOne g).weight = g := by + simp [ofWeightOne, ofEmbed_weight] end Instances diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index b6b64557..bcb1ab8b 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -254,7 +254,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range_le_weight_positive : R≥0 ∙ (Set.range ℋ.ofPoint) ≤ ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_ofPoint] + rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : @@ -339,7 +339,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : R≥0 ∙ (Set.range ℋ.ofPoint) = ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_ofPoint] + rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_eq_positive _ @[simp] lemma homogenize_univ : homogenize ℋ (Set.univ : Set A) = ℋ.weight.positive := by From fa3285c0258604d43f80be29f1c80bcfba6ac293 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 24 Sep 2026 16:10:40 +0200 Subject: [PATCH 08/39] making it like PR --- .../AffineSpace/Homogenization/Basic.lean | 147 +++++++++++++----- 1 file changed, 108 insertions(+), 39 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index ebcf6654..a9b6252a 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -1,7 +1,7 @@ /- -Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Copyright (c) 2026 Olivia Röhrig. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig, Martin Winter +Authors: Olivia Röhrig -/ module @@ -9,13 +9,21 @@ public import Mathlib.LinearAlgebra.AffineSpace.Homogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineMap public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Canonical +import Mathlib.Algebra.Module.Submodule.EqLocus + /-! This file defines affine homogenization as any vector space linearly equivalent to -`Homogenization`, the canonical homogenization from Mathlib. It also proves every such object -satisfies the axiomatic description from [Gallier2011GeometricMethods]. +`Homogenization`, the canonical homogenization from Mathlib. It also proves every object +that satisfies the axiomatic description from [Gallier2011GeometricMethods] is a homogenization +in the linear equivalence sense (see `ofEmbed`). Use `IsHomogenization` for convenience if you want +to consider an embedding into a vector space that is not the canonical `Homogenization`. ## Implementation notes +* We transport relevant theorems from `Homogenization`. * The axiomatization in the literature is redundant. The universal property can be proven solely -from the subset of axioms used in the `ofEmbed` constructor, as is done by providing `lift`. +from the remaning axioms, as is done in `lift`. +* We choose the definition via `LinearEquiv` instead of the axiomatization, since the latter only +classifies homogenizations over a ring. The one presented here can be adapted to semirings if affine +spaces over semirings become necessary. ## References @@ -54,34 +62,66 @@ def ofPoint : A →ᵃ[R] W := ℋ.repr.symm.toAffineMap.comp Homogenization.ofP @[expose] def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization.ofVector -/-- The linear map that is constantly `1` when restricted to `A`. -/ -def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap - -lemma ofPoint_injective : Injective ℋ.ofPoint := by +theorem ofPoint_injective : Injective ℋ.ofPoint := by simpa [ofPoint] using Homogenization.ofPoint_injective theorem ofVector_injective : Injective ℋ.ofVector := by simpa [ofVector] using Homogenization.ofVector_injective -theorem weight_eq_zero_iff {x : W} : ℋ.weight x = 0 ↔ ∃ v, x = ℋ.ofVector v := by - simpa [← LinearEquiv.symm_apply_eq, weight, ofVector] using Homogenization.weight_eq_zero_iff +theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by + simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint -theorem weight_eq_one_iff {x : W} : ℋ.weight x = 1 ↔ ∃ p, x = ℋ.ofPoint p := by - simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff +section -lemma ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by - ext; simp [↓weight_eq_one_iff, eq_comm] +variable {U : Type*} [AddCommGroup U] [Module R U] +variable {F : Type*} [FunLike F W U] [LinearMapClass F R _ _] -lemma ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by - ext; simp [↓weight_eq_zero_iff, eq_comm] +-- we duplicate the proof because translating using the typeclass is a pain +theorem hom_ext {f g : F} (h : ∀ x, f (ℋ.ofPoint x) = g (ℋ.ofPoint x)) : f = g := by + apply LinearMap.ofClass_injective + rwa [← LinearMap.eqLocus_eq_top, eq_top_iff, ← ℋ.span_range_ofPoint, Submodule.span_le, + Set.range_subset_iff] + +theorem hom_ext_iff {f g : F} : f = g ↔ ∀ x, f (ℋ.ofPoint x) = g (ℋ.ofPoint x) := + ⟨by rintro rfl _; rfl, ℋ.hom_ext⟩ + +end + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] + +/-- An affine map on `A` taking values in a vector space extends uniquely to a linear map on `W`. +-/ +def lift : (A →ᵃ[R] U) ≃+ (W →ₗ[R] U) := + Homogenization.lift.trans (ℋ.repr.arrowCongrAddEquiv (LinearEquiv.refl ..)).symm + +@[simp] +theorem lift_apply_ofPoint (f : A →ᵃ[R] U) (p : A) : ℋ.lift f (ℋ.ofPoint p) = f p := by + simp [lift, ofPoint] + +@[simp] +theorem lift_apply_ofVector (f : A →ᵃ[R] U) (v : V) : ℋ.lift f (ℋ.ofVector v) = f.linear v := by + simp [lift, ofVector] + +end + +/-- The linear map that is constantly `1` when restricted to `A`. -/ +def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap /-- The homogenization of a point in `A` has weight 1. -/ @[simp] -lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] +theorem weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] /-- The homogenization of a point in `V` has weight 0. -/ @[simp] -lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] +theorem weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] + +theorem weight_eq_zero_iff {x : W} : ℋ.weight x = 0 ↔ ∃ v, x = ℋ.ofVector v := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofVector] using Homogenization.weight_eq_zero_iff + +theorem weight_eq_one_iff {x : W} : ℋ.weight x = 1 ↔ ∃ p, x = ℋ.ofPoint p := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff -- the following two are in canonical hom in #43448 theorem ofPoint_ne_ofVector [Nontrivial R] (x : A) (v : V) : ℋ.ofPoint x ≠ ℋ.ofVector v := @@ -90,6 +130,12 @@ theorem ofPoint_ne_ofVector [Nontrivial R] (x : A) (v : V) : ℋ.ofPoint x ≠ theorem ofPoint_ne_zero [Nontrivial R] (x : A) : ℋ.ofPoint x ≠ 0 := by simpa using ℋ.ofPoint_ne_ofVector x 0 +theorem ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by + ext; simp [↓weight_eq_one_iff, eq_comm] + +theorem ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by + ext; simp [↓weight_eq_zero_iff, eq_comm] + /-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by apply SetLike.ext' @@ -97,22 +143,13 @@ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by ext x simp -theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by - simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint - -lemma weight_comp_repr : - ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := A) := by - simp [weight, LinearMap.comp_assoc] - theorem repr_comp_ofPoint : ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by ext a; simp [ofPoint] -variable {U : Type*} [AddCommGroup U] [Module R U] in -/-- An affine map on `A` taking values in a vector space extends uniquely to a linear map on `W`. --/ -abbrev lift : (A →ᵃ[R] U) ≃+ (W →ₗ[R] U) := - Homogenization.lift.trans (ℋ.repr.arrowCongrAddEquiv (LinearEquiv.refl ..)).symm +theorem weight_comp_repr : + ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := A) := by + simp [weight, LinearMap.comp_assoc] open AffineMap LinearEquiv in /-- The linear equivalence between the underlying vector space and its embedding. -/ @@ -129,26 +166,58 @@ public def ofPointRangeEquiv : A ≃ᵃ[R] ℋ.ofPoint.range := .ofBijective ⟨ℋ.ofPoint.rangeRestrict_injective_iff.mpr ℋ.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ -lemma apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : +theorem apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : ℋ.ofPoint (ℋ.ofPointRangeEquiv.symm x) = x := by rw [← ℋ.ofPointRangeEquiv.right_inv x] congr; exact ℋ.ofPointRangeEquiv.symm_apply_apply _ -section Instances +section + +variable {U : Type*} [AddCommGroup U] [Module R U] {f : A →ᵃ[R] U} {g : U →ₗ[R] R} + +lemma comp_lift_eq_weight_of_range_preimage (f_range : Set.range f = g ⁻¹' {1}) : + g ∘ₗ (ℋ.lift f) = ℋ.weight := by + refine ℋ.hom_ext (fun p ↦ ?_) + have := f_range ▸ Set.mem_range_self p + simpa [LinearMap.comp_apply, ofPoint, weight, lift] using this + +lemma lift_bijective_of_injective_of_range_preimage (f_inj : Injective f) + (f_range : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by + constructor + · rw [injective_iff_map_eq_zero] + intro a ha + have : ℋ.weight a = 0 := by simp [← ℋ.comp_lift_eq_weight_of_range_preimage f_range, ha] + obtain ⟨_, rfl⟩ := ℋ.weight_eq_zero_iff.mp this + rw [ℋ.lift_apply_ofVector] at ha + simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr f_inj)).mp ha] + · intro w + obtain p₀ := Classical.arbitrary A + obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by + rw [f_range] + have : g (w - g w • f p₀ + f p₀) = 1 := by + have : f p₀ ∈ g ⁻¹' {1} := f_range ▸ Set.mem_range_self p₀ + rw [map_add, map_sub, map_smul, this, smul_eq_mul, mul_one, sub_self, zero_add] + simpa using this + exact ⟨ℋ.ofVector (a -ᵥ p₀) + g w • ℋ.ofPoint p₀, by simp [ofPoint, ofVector, lift, ha]⟩ + +end + +section Constructions variable (R A) in /-- The canonical homogenization is a homogenization. -/ def canonical : IsHomogenization R A (Homogenization R A) := ofRepr <| LinearEquiv.refl .. -/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector +/-- Construct a homogenization from an embedding of the affine space `A` into the vector space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : IsHomogenization R A W where - repr := (LinearEquiv.ofBijective (Homogenization.lift embed) - (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm + repr := by + apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm + exact (lift_bijective_of_injective_of_range_preimage (canonical R A) embed_inj embed_range) /-- The embedding used in the construction becomes the embedding in the homogenization. -/ theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) @@ -168,7 +237,7 @@ theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) exact LinearEquiv.apply_symm_apply _ w rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] congr - exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm + exact (comp_lift_eq_weight_of_range_preimage (canonical R A) embed_range).symm /-- A module is a homogenization of the weight-one hyperplane of any linear functional, provided that hyperplane is nonempty. -/ @@ -177,11 +246,11 @@ def ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffi ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -lemma ofWeightOne_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : +theorem ofWeightOne_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : (ofWeightOne g).weight = g := by simp [ofWeightOne, ofEmbed_weight] -end Instances +end Constructions end IsHomogenization From e7804a7291b7403b1ec29e7d699d9b954f69bd00 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 29 Sep 2026 10:26:37 +0200 Subject: [PATCH 09/39] cleanup --- .../ConvexSpace/Set/Homogenization.lean | 6 +- .../AffineSpace/Homogenization/Basic.lean | 116 +++++++++--------- .../AffineSpace/Homogenization/Set.lean | 4 +- 3 files changed, 61 insertions(+), 65 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index dc117afe..ead4413e 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -173,7 +173,7 @@ variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ lemma homogenize_top : homogenize ℋ (⊤ : ConvexSet R A) = ℋ.weight.positive := by rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton ℋ.weight one_pos, - ← ℋ.ofPoint_range_eq_preimage_weight_ofPoint] + ← ℋ.ofPoint_range_eq_preimage_weight_one] congr! with x simp @@ -219,14 +219,14 @@ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} · apply SetLike.ext' unfold homogenize rw [eq_Ici_zero_smul_inter_preimage_of_pos_of_ne_bot hC zero_lt_one hbot, - ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_ofPoint] + ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_one] apply hull_eq_smul · obtain ⟨y, hyC, hy0⟩ := exists_mem_ne_zero_of_ne_bot hbot let y' := (ℋ.weight y)⁻¹ • y have hy'C : y' ∈ C := C.smul_mem (inv_nonneg.mpr (@hC y hyC hy0).le) hyC have hy' : y' ∈ Set.range ℋ.ofPoint := by - simpa [y', ℋ.ofPoint_range_eq_preimage_weight_ofPoint] + simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ · exact C.isConvexSet.inter ℋ.ofPoint.range_isConvexSet diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean index f490b047..46a10ea8 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean @@ -57,36 +57,6 @@ def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization. /-- The linear map that is constantly `1` when restricted to `A`. -/ def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap -/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector -space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the -axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] -https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} - (embed_range : Set.range embed = weight ⁻¹' {1}) : - IsHomogenization R A W where - repr := (LinearEquiv.ofBijective (Homogenization.lift embed) - (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm - -/-- The embedding used in the construction becomes the embedding in the homogenization. -/ -theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).ofPoint = embed := by - ext p - exact Homogenization.lift_apply_ofPoint .. - -/-- The weight used in the construction becomes the weight in the homogenization. -/ -theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).weight = weight := by - ext w - unfold IsHomogenization.weight - have : Homogenization.lift embed ((ofEmbed embed_inj embed_range).repr w) = w := by - rw [← LinearEquiv.ofBijective_apply] - exact LinearEquiv.apply_symm_apply _ w - rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] - congr - exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm - lemma ofPoint_injective : Injective ℋ.ofPoint := by simpa [ofPoint] using Homogenization.ofPoint_injective @@ -99,15 +69,26 @@ theorem weight_eq_zero_iff {x : W} : ℋ.weight x = 0 ↔ ∃ v, x = ℋ.ofVecto theorem weight_eq_one_iff {x : W} : ℋ.weight x = 1 ↔ ∃ p, x = ℋ.ofPoint p := by simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff -lemma ofPoint_range_eq_preimage_weight_ofPoint : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by - ext - simp [weight_eq_one_iff] - simp [eq_comm] +lemma ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by + ext; simp [↓weight_eq_one_iff, eq_comm] lemma ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by - ext - simp [weight_eq_zero_iff] - simp [eq_comm] + ext; simp [↓weight_eq_zero_iff, eq_comm] + +/-- The homogenization of a point in `A` has weight 1. -/ +@[simp] +lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] + +/-- The homogenization of a point in `V` has weight 0. -/ +@[simp] +lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] + +-- the following two are in canonical hom in #43448 +theorem ofPoint_ne_ofVector [Nontrivial R] (x : A) (v : V) : ℋ.ofPoint x ≠ ℋ.ofVector v := + ne_of_apply_ne ℋ.weight <| by simp + +theorem ofPoint_ne_zero [Nontrivial R] (x : A) : ℋ.ofPoint x ≠ 0 := by + simpa using ℋ.ofPoint_ne_ofVector x 0 /-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by @@ -142,27 +123,12 @@ theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint lemma weight_comp_repr : - ℋ.weight ∘ₗ ℋ.repr.symm = (Homogenization.weight : Homogenization R A →ₗ[R] R) := - Homogenization.hom_ext fun a ↦ by simp [weight] - -@[simp] lemma weight_repr (x : Homogenization R A) : - ℋ.weight (ℋ.repr.symm x) = Homogenization.weight x := - congr($(weight_comp_repr _) x) - -theorem repr_bijective : Bijective ℋ.repr := by - constructor - · simp [injective_iff_map_eq_zero] - · intro x - use ℋ.repr.symm x - simp + ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := A) := by + simp [weight, LinearMap.comp_assoc] -@[simp] lemma repr_ofPoint (a : A) : - ℋ.repr (ℋ.ofPoint a) = Homogenization.ofPoint a := - by simp [ofPoint] - -theorem repr_canonical_ofPoint : +theorem repr_comp_ofPoint : ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by - ext a; simp + ext a; simp [ofPoint] variable {U : Type*} [AddCommGroup U] [Module R U] in /-- An affine map on `A` taking values in a vector space extends uniquely to a linear map on `W`. @@ -196,16 +162,46 @@ variable (R A) in /-- The canonical homogenization is a homogenization. -/ def canonical : IsHomogenization R A (Homogenization R A) := ofRepr <| LinearEquiv.refl .. +/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector +space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the +axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] +https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ +def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} + (embed_range : Set.range embed = weight ⁻¹' {1}) : + IsHomogenization R A W where + repr := (LinearEquiv.ofBijective (Homogenization.lift embed) + (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm + +/-- The embedding used in the construction becomes the embedding in the homogenization. -/ +theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).ofPoint = embed := by + ext p + exact Homogenization.lift_apply_ofPoint .. + +/-- The weight used in the construction becomes the weight in the homogenization. -/ +theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).weight = weight := by + ext w + unfold IsHomogenization.weight + have : Homogenization.lift embed ((ofEmbed embed_inj embed_range).repr w) = w := by + rw [← LinearEquiv.ofBijective_apply] + exact LinearEquiv.apply_symm_apply _ w + rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] + congr + exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm + /-- A module is a homogenization of the weight-one hyperplane of any linear functional, provided that hyperplane is nonempty. -/ -def ofWeight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : +def ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -lemma ofWeight_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - (ofWeight g).weight = g := by - simp [ofWeight, ofEmbed_weight] +lemma ofWeightOne_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + (ofWeightOne g).weight = g := by + simp [ofWeightOne, ofEmbed_weight] end Instances diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index b6b64557..bcb1ab8b 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -254,7 +254,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range_le_weight_positive : R≥0 ∙ (Set.range ℋ.ofPoint) ≤ ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_ofPoint] + rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : @@ -339,7 +339,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : R≥0 ∙ (Set.range ℋ.ofPoint) = ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_ofPoint] + rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_eq_positive _ @[simp] lemma homogenize_univ : homogenize ℋ (Set.univ : Set A) = ℋ.weight.positive := by From 635aa70d6a775d991f79b8990b615cf302ecddd7 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 29 Sep 2026 10:41:15 +0200 Subject: [PATCH 10/39] making it like draft PR --- Polyhedral.lean | 4 +- .../Convex/ConvexSpace/Homogenization.lean | 2 +- .../Convex/ConvexSpace/Polytope/Face.lean | 6 +- .../ConvexSpace/Set/Homogenization.lean | 6 +- .../LinearAlgebra/AffineSpace/AffineMap.lean | 127 -------- .../AffineSpace/AffineSubspace/Range.lean | 90 ++++++ .../AffineSpace/Homogenization/Basic.lean | 212 -------------- .../AffineSpace/Homogenization/Canonical.lean | 62 ---- .../Homogenization/IsHomogenization.lean | 272 ++++++++++++++++++ .../AffineSpace/Homogenization/Set.lean | 2 +- 10 files changed, 371 insertions(+), 412 deletions(-) delete mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean create mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean delete mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean delete mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean create mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean diff --git a/Polyhedral.lean b/Polyhedral.lean index 53d06d22..1b028e43 100644 --- a/Polyhedral.lean +++ b/Polyhedral.lean @@ -67,12 +67,12 @@ public import Polyhedral.Mathlib.Geometry.Convex.Fun.Dual public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Closure public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Nonneg -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineMap public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Defs +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Defs public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Dimension -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Set public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Lattice public import Polyhedral.Mathlib.LinearAlgebra.BilinearMap diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean index 2eedc508..5ae1ad42 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean @@ -6,7 +6,7 @@ Authors: Martin Winter, Olivia Röhrig module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Convexity -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization /-! This file proves results about the interaction of homogenization and convexity. -/ diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 0bc19c89..3ae565c1 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -33,7 +33,7 @@ include V in theorem IsPolytope.face_isPolytope (hC : IsPolytope R (C : Set A)) (hF : IsFaceOf F C) : IsPolytope R (F : Set A) := by let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule - have homF := (IsHomogenization.canonical R A).homogenize_isFaceOf hF + have homF := (IsHomogenization.ofHomogenization R A).homogenize_isFaceOf hF have := PointedCone.IsFaceOf.fg (IsPolytope.homogenize_fg _ hC) homF convert FG.dehomogenize_isPolytope this (fun _ a b ↦ weight_pos_of_mem_homogenize a b) simp [dehomogenize_homogenize] @@ -52,10 +52,10 @@ private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polyto GradeOrder ℕ (Face (P : ConvexSet R A)) := by let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule have : PointedCone.FG (homogenize _ (P : ConvexSet R A)) := - IsPolytope.homogenize_fg (IsHomogenization.canonical R A) P.isPolytope + IsPolytope.homogenize_fg (IsHomogenization.ofHomogenization R A) P.isPolytope let := PointedCone.FG.gradeOrder_finrank this refine GradeOrder.liftRight _ - (IsHomogenization.Face.homogenizeIso (IsHomogenization.canonical R A) _).strictMono ?_ + (IsHomogenization.Face.homogenizeIso (IsHomogenization.ofHomogenization R A) _).strictMono ?_ exact fun x y ↦ (apply_covBy_apply_iff _).mpr end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index ead4413e..527db024 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -7,9 +7,7 @@ module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Convexity public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Lineal -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic - -import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization /-! This file defines homogenization of convex sets in affine spaces. -/ @@ -229,7 +227,7 @@ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ - · exact C.isConvexSet.inter ℋ.ofPoint.range_isConvexSet + · exact C.isConvexSet.inter ℋ.ofPoint.isConvexSet_range lemma homogenize_mono_iff {K₁ K₂ : ConvexSet R A} : K₁.homogenize ℋ ≤ K₂.homogenize ℋ ↔ K₁ ≤ K₂ where diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean deleted file mode 100644 index 39719157..00000000 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean +++ /dev/null @@ -1,127 +0,0 @@ -/- -Copyright (c) 2026 Martin Winter, Olivia Röhrig. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Martin Winter, Olivia Röhrig --/ -module - -public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic - -import Mathlib.LinearAlgebra.AffineSpace.AffineMap - -/-! The content of this file should go into `AffineSpace/AffineMap.lean`. -/ - -@[expose] public section - -open Affine Module AffineSubspace - -section - -variable {k V V₁ V₂ P P₁ P₂ : Type*} - -namespace AffineMap - -variable [Ring k] -variable [AddCommGroup V] [Module k V] -variable [AddCommGroup V₁] [Module k V₁] -variable [AddCommGroup V₂] [Module k V₂] -variable [AffineSpace V P] [AffineSpace V₁ P₁] [AffineSpace V₂ P₂] - -/-- The range of an affine map is an affine subspace. -/ -def range (f : P₁ →ᵃ[k] P₂) : AffineSubspace k P₂ where - carrier := Set.range f - smul_vsub_vadd_mem' := by - simp only [Set.mem_range, forall_exists_index] - intro c _ _ _ x₁ h₁ x₂ h₂ x₃ h₃ - exact ⟨c • (x₁ -ᵥ x₂) +ᵥ x₃, by simp [map_vadd, ← h₁, ← h₂, ← h₃]⟩ - -instance instNonemptyRange (f : P₁ →ᵃ[k] P₂) : Nonempty (range f) := - Set.instNonemptyRange f - -@[simp] -theorem mem_range (f : P₁ →ᵃ[k] P₂) (x : P₂) : x ∈ f.range ↔ ∃ (y : P₁), f y = x := - Iff.rfl - -@[simp] -theorem coe_range (f : P₁ →ᵃ[k] P₂) : f.range = Set.range f := rfl - -theorem range_eq_map (f : P₁ →ᵃ[k] P₂) : range f = map f ⊤ := by - ext - simp - -theorem mem_range_self (f : P₁ →ᵃ[k] P₂) (x : P₁) : f x ∈ range f := - ⟨x, rfl⟩ - -@[simp] -theorem range_id : range (AffineMap.id k P₁) = ⊤ := - SetLike.coe_injective Set.range_id - -theorem range_comp (f : P₁ →ᵃ[k] P₂) (g : P₂ →ᵃ[k] P) : range (g.comp f) = map g (range f) := - SetLike.coe_injective (Set.range_comp g f) - -theorem range_comp_le_range (f : P₁ →ᵃ[k] P₂) (g : P₂ →ᵃ[k] P) : range (g.comp f) ≤ range g := - SetLike.coe_mono (Set.range_comp_subset_range f g) - -theorem range_eq_top {f : P₁ →ᵃ[k] P₂} : range f = ⊤ ↔ Function.Surjective f := by - rw [SetLike.ext'_iff, coe_range, top_coe, Set.range_eq_univ] - -theorem range_eq_top_of_surjective (f : P₁ →ᵃ[k] P₂) (hf : Function.Surjective f) : - range f = ⊤ := range_eq_top.mpr hf - -theorem range_le_iff_comap {f : P₁ →ᵃ[k] P₂} {p : AffineSubspace k P₂} : - range f ≤ p ↔ comap f p = ⊤ := by rw [range_eq_map, map_le_iff_le_comap, eq_top_iff] - -theorem map_le_range {f : P₁ →ᵃ[k] P₂} {p : AffineSubspace k P₁} : map f p ≤ range f := - SetLike.coe_mono (Set.image_subset_range f p) - -theorem comap_le_comap_iff {f : P₁ →ᵃ[k] P₂} (hf : range f = ⊤) {p p'} : - comap f p ≤ comap f p' ↔ p ≤ p' := - ⟨fun H ↦ by rwa [SetLike.le_def, (range_eq_top.mp hf).forall], comap_mono⟩ - -theorem comap_injective {f : P₁ →ᵃ[k] P₂} (hf : range f = ⊤) : Function.Injective (comap f) := - fun _ _ h ↦ le_antisymm ((comap_le_comap_iff hf).mp (le_of_eq h)) - ((comap_le_comap_iff hf).mp (ge_of_eq h)) - -@[simp] -theorem map_top (f : P₁ →ᵃ[k] P₂) : map f ⊤ = range f := - (range_eq_map f).symm - -@[simp] -theorem affineSpan_range_eq_range (f : P₁ →ᵃ[k] P₂) : affineSpan k (Set.range f) = f.range := by - simp [← Set.image_univ, ← AffineSubspace.map_span] - -lemma range_direction (f : P₁ →ᵃ[k] P₂) : f.range.direction = f.linear.range := by - apply le_antisymm - · apply Submodule.span_le.mpr - intro _ ⟨p₁, h₁, p₂, h₂, h⟩ - simp only [SetLike.mem_coe, mem_range] at h₁ h₂ - obtain ⟨p₁, rfl⟩ := h₁ - obtain ⟨p₂, rfl⟩ := h₂ - exact ⟨p₁ -ᵥ p₂, h ▸ f.linearMap_vsub _ _⟩ - · apply Submodule.span_le.mp - intro v hv - rw [Submodule.span_coe_eq_restrictScalars] at hv - obtain ⟨w, rfl⟩ := hv - apply Submodule.subset_span - simp only [Set.mem_vsub, SetLike.mem_coe, mem_range, exists_exists_eq_and] - exact ⟨(w +ᵥ Classical.arbitrary P₁), (Classical.arbitrary P₁), by simp⟩ - -lemma range_eq_copmap_top (f : P₁ →ᵃ[k] P₂) : f.range = .map f ⊤ := by ext; simp - -def rangeRestrict (f : P₁ →ᵃ[k] P₂) : P₁ →ᵃ[k] f.range where - toFun p := ⟨f p, p, rfl⟩ - linear := (LinearEquiv.ofEq _ _ f.range_direction.symm).toLinearMap ∘ₗ f.linear.rangeRestrict - map_vadd' _ _ := by ext; simp [map_vadd] - -lemma rangeRestrict_injective_iff (f : P₁ →ᵃ[k] P₂) : - (rangeRestrict f).toFun.Injective ↔ f.toFun.Injective := by - simp only [Function.Injective, rangeRestrict, toFun_eq_coe, coe_mk] - constructor - · intro h p q hpq - exact h <| Subtype.ext hpq - · intro h p q hpq - exact h <| congrArg Subtype.val hpq - -end AffineMap - -end diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean new file mode 100644 index 00000000..009a85e0 --- /dev/null +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2026 Olivia Röhrig. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig +-/ +module + +public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic + +/-! +# Range of affine maps + +The range of an affine map `f : P₁ →ᵃ[R] P₂` is an affine subspace of `P₂`. + +# Implementation note + +Follows `LinearMap.range`. + +-/ + +@[expose] public section + +open Affine Module AffineMap AffineSubspace + +section + +variable {R V₁ V₂ P₁ P₂ : Type*} + +namespace AffineMap + +variable [Ring R] +variable [AddCommGroup V₁] [Module R V₁] +variable [AddCommGroup V₂] [Module R V₂] +variable [AffineSpace V₁ P₁] [AffineSpace V₂ P₂] + +variable (f : P₁ →ᵃ[R] P₂) + +/-- The range of an affine map is an affine subspace. -/ +def range : AffineSubspace R P₂ where + carrier := Set.range f + smul_vsub_vadd_mem' := by + simp only [Set.mem_range, forall_exists_index] + intro c _ _ _ x₁ h₁ x₂ h₂ x₃ h₃ + exact ⟨c • (x₁ -ᵥ x₂) +ᵥ x₃, by simp [map_vadd, ← h₁, ← h₂, ← h₃]⟩ + +/-- The range of an affine map is nonempty. -/ +instance instNonemptyRange : Nonempty (range f) := + Set.instNonemptyRange f + +@[simp, norm_cast] +theorem coe_range : f.range = Set.range f := rfl + +@[simp] +theorem mem_range (x : P₂) : x ∈ f.range ↔ ∃ (y : P₁), f y = x := + Iff.rfl + +theorem range_eq_map_top : f.range = .map f ⊤ := by ext; simp + +theorem mem_range_self (x : P₁) : f x ∈ f.range := by simp + +@[simp] +theorem range_id : (id R P₁).range = ⊤ := by ext; simp + +theorem range_direction_eq_linear_range : f.range.direction = f.linear.range := by + rw [range_eq_map_top, map_direction, direction_top, Submodule.map_top] + +/-- Restrict the codomain of an affine map `f` to `f.range`. -/ +def rangeRestrict : P₁ →ᵃ[R] f.range where + toFun p := ⟨f p, p, rfl⟩ + linear := f.linear.codRestrict f.range.direction + (f.range_direction_eq_linear_range ▸ f.linear.mem_range_self) + map_vadd' _ _ := by ext; simp [map_vadd] + +theorem surjective_rangeRestrict : Function.Surjective ⇑f.rangeRestrict := + fun ⟨_, y, rfl⟩ => ⟨y, rfl⟩ + +@[simp] +theorem range_rangeRestrict : f.rangeRestrict.range = ⊤ := by + ext ⟨_, x, rfl⟩ + simpa [AffineSubspace.mem_top, iff_true] using ⟨x, rfl⟩ + +@[simp] +theorem injective_rangeRestrict_iff : + Function.Injective (rangeRestrict f) ↔ Function.Injective f := by + convert (Function.Injective.of_comp_iff Subtype.val_injective f.rangeRestrict).symm + ext; simp [rangeRestrict] + +end AffineMap + +end diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean deleted file mode 100644 index 46a10ea8..00000000 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ /dev/null @@ -1,212 +0,0 @@ -/- -Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig, Martin Winter --/ -module - -public import Mathlib.LinearAlgebra.AffineSpace.Homogenization -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineMap -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Canonical - -/-! This file defines affine homogenization as any vector space linearly equivalent to -`Homogenization`, the canonical homogenization from Mathlib. It also proves every such object -satisfies the axiomatic description from [Gallier2011GeometricMethods]. - -## Implementation notes -* The axiomatization in the literature is redundant. The universal property can be proven solely -from the subset of axioms used in the `ofEmbed` constructor, as is done by providing `lift`. - -## References - -* [J. Gallier, *Geometric Methods and Applications for Computer Science and - Engineering*][Gallier2011GeometricMethods] - -/ - -public noncomputable section - -namespace Affine - -section Ring - -open Function Submodule - -variable {R : Type*} [Ring R] -variable {V : Type*} [AddCommGroup V] [Module R V] -variable {A : Type*} [AddTorsor V A] -variable {W : Type*} [AddCommGroup W] [Module R W] - -variable (R A W) in -/-- A triple of a ring `R`, `R`-affine space `A` and `R`-vector space `W` is a homogenization if -`W` is linearly equivalent to the canonical homogenization. -/ -structure IsHomogenization where ofRepr :: - repr : W ≃ₗ[R] Homogenization R A - -namespace IsHomogenization - -variable (ℋ : IsHomogenization R A W) - -/-- The embedding of the affine space into the homogenization. -/ -@[expose] -def ofPoint : A →ᵃ[R] W := ℋ.repr.symm.toAffineMap.comp Homogenization.ofPoint - -/-- The embedding of the vector space into the homogenization. -/ -@[expose] -def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization.ofVector - -/-- The linear map that is constantly `1` when restricted to `A`. -/ -def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap - -lemma ofPoint_injective : Injective ℋ.ofPoint := by - simpa [ofPoint] using Homogenization.ofPoint_injective - -theorem ofVector_injective : Injective ℋ.ofVector := by - simpa [ofVector] using Homogenization.ofVector_injective - -theorem weight_eq_zero_iff {x : W} : ℋ.weight x = 0 ↔ ∃ v, x = ℋ.ofVector v := by - simpa [← LinearEquiv.symm_apply_eq, weight, ofVector] using Homogenization.weight_eq_zero_iff - -theorem weight_eq_one_iff {x : W} : ℋ.weight x = 1 ↔ ∃ p, x = ℋ.ofPoint p := by - simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff - -lemma ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by - ext; simp [↓weight_eq_one_iff, eq_comm] - -lemma ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by - ext; simp [↓weight_eq_zero_iff, eq_comm] - -/-- The homogenization of a point in `A` has weight 1. -/ -@[simp] -lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] - -/-- The homogenization of a point in `V` has weight 0. -/ -@[simp] -lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] - --- the following two are in canonical hom in #43448 -theorem ofPoint_ne_ofVector [Nontrivial R] (x : A) (v : V) : ℋ.ofPoint x ≠ ℋ.ofVector v := - ne_of_apply_ne ℋ.weight <| by simp - -theorem ofPoint_ne_zero [Nontrivial R] (x : A) : ℋ.ofPoint x ≠ 0 := by - simpa using ℋ.ofPoint_ne_ofVector x 0 - -/-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ -theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by - apply SetLike.ext' - rw [LinearMap.coe_range, ofVector_range_eq_preimage_weight_zero, LinearMap.ker] - ext x - simp - -theorem mem_range_ofPoint_iff (x : W) : - x ∈ hom.ofPoint.range ↔ hom.weight x = 1 := by - refine ⟨?_, fun h ↦ Eq.mpr (congrFun hom.ofPoint_range_eq_preimage_weight_one x) h⟩ - rintro ⟨y, hy⟩ - rw [← hy, weight_one] - -theorem zero_notMem_affineSpan [Nontrivial R] : - 0 ∉ hom.ofPoint.range := fun hh ↦ by - simpa using mem_range_ofPoint_iff (0 : W) |>.mp hh - -variable [Nontrivial R] in -theorem ofPoint_ne_zero (x : A) : ℋ.ofPoint x ≠ (0 : W) := by - intro hn - have := congrArg ℋ.weight hn - simp [weight, ofPoint] at this - -/-- The homogenization of a point in `A` has weight 1. -/ -lemma weight_ofPoint (a₀ : A) : ℋ.weight (ℋ.ofPoint a₀) = 1 := by simp [weight, ofPoint] - -/-- The homogenization of a point in `V` has weight 0. -/ -lemma weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] - -theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by - simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint - -lemma weight_comp_repr : - ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := A) := by - simp [weight, LinearMap.comp_assoc] - -theorem repr_comp_ofPoint : - ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by - ext a; simp [ofPoint] - -variable {U : Type*} [AddCommGroup U] [Module R U] in -/-- An affine map on `A` taking values in a vector space extends uniquely to a linear map on `W`. --/ -abbrev lift : (A →ᵃ[R] U) ≃+ (W →ₗ[R] U) := - Homogenization.lift.trans (ℋ.repr.arrowCongrAddEquiv (LinearEquiv.refl ..)).symm - -open AffineMap LinearEquiv in -/-- The linear equivalence between the underlying vector space and its embedding. -/ -def ofVectorRangeEquiv : V ≃ₗ[R] ℋ.ofVector.range where - toFun v := ⟨ℋ.ofVector v, ℋ.ofVector.mem_range_self v⟩ - map_add' v w := by simp - map_smul' r v := by simp - invFun := (ofInjective ℋ.ofVector (linear_injective_iff _ |>.mpr ℋ.ofPoint_injective)).invFun - left_inv := LinearEquiv.left_inv _ - right_inv := LinearEquiv.right_inv _ - -/-- The affine equivalence between the affine space space and its embedding. -/ -public def ofPointRangeEquiv : A ≃ᵃ[R] ℋ.ofPoint.range := - .ofBijective - ⟨ℋ.ofPoint.rangeRestrict_injective_iff.mpr ℋ.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ - -lemma apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : - ℋ.ofPoint (ℋ.ofPointRangeEquiv.symm x) = x := by - rw [← ℋ.ofPointRangeEquiv.right_inv x] - congr; exact ℋ.ofPointRangeEquiv.symm_apply_apply _ - -section Instances - -variable (R A) in -/-- The canonical homogenization is a homogenization. -/ -def canonical : IsHomogenization R A (Homogenization R A) := ofRepr <| LinearEquiv.refl .. - -/-- Construct `IsHomogenization R A W` from an embedding of the affine space `A` into the vector -space `W` and a weight map that is the constant 1-map on the embedded `A`. This follows the -axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] -https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -def ofEmbed {embed : A →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} - (embed_range : Set.range embed = weight ⁻¹' {1}) : - IsHomogenization R A W where - repr := (LinearEquiv.ofBijective (Homogenization.lift embed) - (Homogenization.lift_bijective_of_injective_of_range_preimage embed_inj embed_range)).symm - -/-- The embedding used in the construction becomes the embedding in the homogenization. -/ -theorem ofEmbed_ofPoint {embed : A →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).ofPoint = embed := by - ext p - exact Homogenization.lift_apply_ofPoint .. - -/-- The weight used in the construction becomes the weight in the homogenization. -/ -theorem ofEmbed_weight {embed : A →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).weight = weight := by - ext w - unfold IsHomogenization.weight - have : Homogenization.lift embed ((ofEmbed embed_inj embed_range).repr w) = w := by - rw [← LinearEquiv.ofBijective_apply] - exact LinearEquiv.apply_symm_apply _ w - rw [LinearMap.coe_comp, ← this, ← LinearMap.comp_apply] - congr - exact (Homogenization.comp_lift_eq_weight_of_range_preimage embed_range).symm - -/-- A module is a homogenization of the weight-one hyperplane of any linear functional, -provided that hyperplane is nonempty. -/ -def ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := - ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) - -@[simp] -lemma ofWeightOne_weight (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - (ofWeightOne g).weight = g := by - simp [ofWeightOne, ofEmbed_weight] - -end Instances - -end IsHomogenization - -end Ring - -end Affine diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean deleted file mode 100644 index c54f7381..00000000 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Canonical.lean +++ /dev/null @@ -1,62 +0,0 @@ -/- -Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig, Martin Winter --/ -module - -public import Mathlib.LinearAlgebra.AffineSpace.Homogenization - -/-! This file defines affine homogenization axiomatically and proves every object fulfilling the -axioms is linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. - -## Implementation notes -* The axiomatization in the literature is redundant. The universal property can be proven solely -from the subset of axioms used in `IsHomogenization`, as is done in lemma `extend`. It is -convenient to use the linear equivalence between any homogenization and `Homogenization` -for the proof. - -## References - -* [J. Gallier, *Geometric Methods and Applications for Computer Science and - Engineering*][Gallier2011GeometricMethods] - -/ - -public noncomputable section - -namespace Homogenization - -open Function Homogenization - -variable {R : Type*} [Ring R] -variable {V : Type*} [AddCommGroup V] [Module R V] -variable {A : Type*} [AddTorsor V A] -variable {W : Type*} [AddCommGroup W] [Module R W] - -variable {f : A →ᵃ[R] W} {g : W →ₗ[R] R} - -lemma comp_lift_eq_weight_of_range_preimage (f_range : Set.range f = g ⁻¹' {1}) : - g ∘ₗ (lift f) = weight := by - refine hom_ext (fun p ↦ ?_) - have := f_range ▸ Set.mem_range_self p - simpa [LinearMap.comp_apply, lift_apply_ofPoint, weight_ofPoint] using this - -lemma lift_bijective_of_injective_of_range_preimage (f_inj : Injective f) - (f_range : Set.range f = g ⁻¹' {1}) : Bijective (lift f) := by - constructor - · rw [injective_iff_map_eq_zero] - intro a ha - have : weight a = 0 := by simp [← comp_lift_eq_weight_of_range_preimage f_range, ha] - obtain ⟨_, rfl⟩ := weight_eq_zero_iff.mp this - rw [lift_apply_ofVector] at ha - simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr f_inj)).mp ha] - · intro w - obtain p₀ := Classical.arbitrary A - obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by - have hmem := f_range ▸ Set.mem_range_self p₀ - have : g (w - g w • f p₀ + f p₀) = 1 := by - rw [map_add, map_sub, map_smul, hmem, smul_eq_mul, mul_one, sub_self, zero_add] - rw [f_range]; simpa using this - exact ⟨ofVector (a -ᵥ p₀) + g w • ofPoint p₀, by simp [ha]⟩ - -end Homogenization diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean new file mode 100644 index 00000000..cdfd5d63 --- /dev/null +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -0,0 +1,272 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig, Martin Winter +-/ +module + +public import Mathlib.LinearAlgebra.AffineSpace.AffineMap +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range +public import Mathlib.LinearAlgebra.AffineSpace.Homogenization + +/-! This file defines affine homogenization as any vector space linearly equivalent to +`Homogenization`, the canonical homogenization from Mathlib. It also proves every object +that satisfies the axiomatic description from [Gallier2011GeometricMethods] is a homogenization +in the linear equivalence sense (see `ofEmbed`). Use `IsHomogenization` for convenience if you want +to consider an embedding into a vector space that is not the canonical `Homogenization`. + +## Implementation notes +* We transport relevant theorems from `Homogenization`. +* The axiomatization in the literature is redundant. The universal property can be proven solely +from the remaning axioms, as is done in `lift`. +* We choose the definition via `LinearEquiv` instead of the axiomatization, since the latter only +classifies homogenizations over a ring. The one presented here can be adapted to semirings if affine +spaces over semirings become necessary. + +## References + +* [J. Gallier, *Geometric Methods and Applications for Computer Science and + Engineering*][Gallier2011GeometricMethods] + -/ + +public noncomputable section + +namespace Affine + +section Ring + +open Function Submodule + +variable {R : Type*} [Ring R] +variable {V : Type*} [AddCommGroup V] [Module R V] +variable {P : Type*} [AddTorsor V P] +variable {W : Type*} [AddCommGroup W] [Module R W] + +variable (R P W) in +/-- A triple of a ring `R`, `R`-affine space `P` and `R`-vector space `W` is a homogenization if +`W` is linearly equivalent to the canonical homogenization. -/ +@[ext] +structure IsHomogenization where ofRepr :: + /-- The linear equivalence between the vector space and the canonical homogenization. -/ + repr : W ≃ₗ[R] Homogenization R P + +namespace IsHomogenization + +variable (ℋ : IsHomogenization R P W) + +/-- The embedding of the affine space into the homogenization. -/ +def ofPoint : P →ᵃ[R] W := ℋ.repr.symm.toAffineMap.comp Homogenization.ofPoint + +/-- The embedding of the vector space into the homogenization. -/ +def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization.ofVector + +theorem ofPoint_injective : Injective ℋ.ofPoint := by + simpa [ofPoint] using Homogenization.ofPoint_injective + +theorem ofVector_injective : Injective ℋ.ofVector := by + simpa [ofVector] using Homogenization.ofVector_injective + +theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by + simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint + +theorem ofPoint_injective' : Function.Injective (ofPoint : IsHomogenization R P W → P →ᵃ[R] W) := by + intro ℋ ℋ' h + apply IsHomogenization.ext + refine LinearEquiv.symm_bijective.injective <| LinearEquiv.toLinearMap_injective ?_ + apply LinearMap.ext_on_range Homogenization.span_range_ofPoint (DFunLike.congr_fun h) + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] +variable {F : Type*} [FunLike F W U] [LinearMapClass F R _ _] + +theorem hom_ext {f g : F} (h : ∀ x, f (ℋ.ofPoint x) = g (ℋ.ofPoint x)) : f = g := by + apply LinearMap.ofClass_injective + rwa [← LinearMap.cancel_right ℋ.repr.symm.surjective, Homogenization.hom_ext_iff] + +theorem hom_ext_iff {f g : F} : f = g ↔ ∀ x, f (ℋ.ofPoint x) = g (ℋ.ofPoint x) := + ⟨by rintro rfl _; rfl, ℋ.hom_ext⟩ + +end + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] + +/-- An affine map on `P` taking values in a vector space extends uniquely to a linear map on `W`. +-/ +def lift : (P →ᵃ[R] U) ≃+ (W →ₗ[R] U) := + Homogenization.lift.trans (ℋ.repr.arrowCongrAddEquiv (LinearEquiv.refl ..)).symm + +@[simp] +theorem lift_apply_ofPoint (f : P →ᵃ[R] U) (p : P) : ℋ.lift f (ℋ.ofPoint p) = f p := by + simp [lift, ofPoint] + +@[simp] +theorem lift_apply_ofVector (f : P →ᵃ[R] U) (v : V) : ℋ.lift f (ℋ.ofVector v) = f.linear v := by + simp [lift, ofVector] + +@[simp] +theorem lift_symm_apply (f : W →ₗ[R] U) (p : P) : ℋ.lift.symm f p = f (ℋ.ofPoint p) := by + simp [lift, ofPoint] + +end + +/-- The linear map that is constantly `1` when restricted to `P`. -/ +def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap + +/-- The homogenization of a point in `P` has weight 1. -/ +@[simp] +theorem weight_ofPoint (p : P) : ℋ.weight (ℋ.ofPoint p) = 1 := by simp [weight, ofPoint] + +/-- The homogenization of a point in `V` has weight 0. -/ +@[simp] +theorem weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] + +theorem weight_eq_zero_iff {w : W} : ℋ.weight w = 0 ↔ ∃ v, w = ℋ.ofVector v := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofVector] using Homogenization.weight_eq_zero_iff + +theorem weight_eq_one_iff {w : W} : ℋ.weight w = 1 ↔ ∃ p, w = ℋ.ofPoint p := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff + +-- the following two are in canonical hom in #43448 +theorem ofPoint_ne_ofVector [Nontrivial R] (p : P) (v : V) : ℋ.ofPoint p ≠ ℋ.ofVector v := + ne_of_apply_ne ℋ.weight <| by simp + +theorem ofPoint_ne_zero [Nontrivial R] (p : P) : ℋ.ofPoint p ≠ 0 := by + simpa using ℋ.ofPoint_ne_ofVector p 0 + +theorem ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by + ext; simp [↓weight_eq_one_iff, eq_comm] + +theorem ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by + ext; simp [↓weight_eq_zero_iff, eq_comm] + +/-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ +theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by + apply SetLike.ext' + rw [LinearMap.coe_range, ofVector_range_eq_preimage_weight_zero, LinearMap.ker] + ext x + simp + +theorem repr_comp_ofPoint : ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by + ext a; simp [ofPoint] + +theorem weight_comp_repr : ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := P) := by + simp [weight, LinearMap.comp_assoc] + +/-- The affine equivalence between the affine space space and its embedding. -/ +public def ofPointRangeEquiv : P ≃ᵃ[R] ℋ.ofPoint.range := + .ofBijective + ⟨ℋ.ofPoint.injective_rangeRestrict_iff.mpr ℋ.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ + +theorem apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : + ℋ.ofPoint (ℋ.ofPointRangeEquiv.symm x) = x := by + rw [← ℋ.ofPointRangeEquiv.right_inv x] + congr; exact ℋ.ofPointRangeEquiv.symm_apply_apply _ + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] {f : P →ᵃ[R] U} {g : U →ₗ[R] R} + +lemma comp_lift_eq_weight (h : ∀ p, g (f p) = 1) : g ∘ₗ (ℋ.lift f) = ℋ.weight := + ℋ.hom_ext <| by simpa + +lemma lift_bijective_of_injective_of_range_preimage (f_inj : Injective f) + (f_range : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by + have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp f_range.subset + constructor + · rw [injective_iff_map_eq_zero] + intro a ha + have : ℋ.weight a = 0 := by simp [← ℋ.comp_lift_eq_weight g_f, ha] + obtain ⟨_, rfl⟩ := ℋ.weight_eq_zero_iff.mp this + rw [ℋ.lift_apply_ofVector] at ha + simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr f_inj)).mp ha] + · intro w + obtain p₀ := Classical.arbitrary P + obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by simp [f_range, g_f] + exact ⟨ℋ.ofVector (a -ᵥ p₀) + g w • ℋ.ofPoint p₀, by simp [ofPoint, ofVector, lift, ha]⟩ + +end + +section Constructions +variable (R P) in +/-- The canonical homogenization is a homogenization. -/ +@[expose] +def ofHomogenization : IsHomogenization R P (Homogenization R P) := ofRepr <| LinearEquiv.refl .. + +@[simp] +theorem ofPoint_ofHomogenization : (ofHomogenization R P).ofPoint = Homogenization.ofPoint := + (rfl) + +@[simp] +theorem ofVector_ofHomogenization : (ofHomogenization R P).ofVector = Homogenization.ofVector := + (rfl) + +@[simp] +theorem weight_ofHomogenization : (ofHomogenization R P).weight = Homogenization.weight := + (rfl) + +/-- Construct a homogenization from an embedding of the affine space `P` into the vector +space `W` and a weight map that is the constant 1-map on the embedded `P`. This follows the +axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] +https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ +def ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} + (embed_range : Set.range embed = weight ⁻¹' {1}) : + IsHomogenization R P W where + repr := by + apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm + exact lift_bijective_of_injective_of_range_preimage (ofHomogenization R P) embed_inj embed_range + +/-- The embedding used in the construction becomes the embedding in the homogenization. -/ +@[simp] +theorem ofPoint_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).ofPoint = embed := by + ext p + exact Homogenization.lift_apply_ofPoint .. + +@[simp] +theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).ofVector = embed.linear := by + ext p + exact Homogenization.lift_apply_ofVector .. + +/-- The weight used in the construction becomes the weight in the homogenization. -/ +@[simp] +theorem weight_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) + {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + (ofEmbed embed_inj embed_range).weight = weight := by + refine (ofEmbed embed_inj embed_range).hom_ext fun x => ?_ + rw [weight_ofPoint, ofPoint_ofEmbed, eq_comm] + exact congr(embed x ∈ $embed_range).mp <| Set.mem_range_self x + +/-- A module is a homogenization of the weight-one hyperplane of any linear functional, +provided that hyperplane is nonempty. -/ +def ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := + ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + +@[simp] +theorem ofPoint_ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + (ofWeightOne g).ofPoint = ((affineSpan R {1}).comap g.toAffineMap).subtype := by + simp [ofWeightOne] + +@[simp] +theorem ofVector_ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + (ofWeightOne g).ofVector = ((affineSpan R {1}).comap g.toAffineMap).direction.subtype := by + simp [ofWeightOne] + +@[simp] +theorem weight_ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : + (ofWeightOne g).weight = g := by + simp [ofWeightOne] + +end Constructions + +end IsHomogenization + +end Ring + +end Affine diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index bcb1ab8b..27c25db9 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -6,7 +6,7 @@ Authors: Martin Winter module public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Nonneg -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization import Polyhedral.Mathlib.Data.Set.Lattice.Image import Polyhedral.Mathlib.Algebra.Order.Nonneg.Ring From 52c154504c16ccbb31147677b44f5470026da080 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 29 Sep 2026 14:28:45 +0200 Subject: [PATCH 11/39] some suggestions --- .../Convex/ConvexSpace/Polytope/Face.lean | 7 +++---- .../Convex/ConvexSpace/Set/Homogenization.lean | 1 - .../Homogenization/IsHomogenization.lean | 16 ++++++++-------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 3ae565c1..144b2a3c 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -51,11 +51,10 @@ This is private since it does not yet have the correct grading (off-by-one). private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polytope R A) : GradeOrder ℕ (Face (P : ConvexSet R A)) := by let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule - have : PointedCone.FG (homogenize _ (P : ConvexSet R A)) := - IsPolytope.homogenize_fg (IsHomogenization.ofHomogenization R A) P.isPolytope + let ℋ := IsHomogenization.ofHomogenization R A + have : (homogenize _ (P : ConvexSet R A)).FG := IsPolytope.homogenize_fg ℋ P.isPolytope let := PointedCone.FG.gradeOrder_finrank this - refine GradeOrder.liftRight _ - (IsHomogenization.Face.homogenizeIso (IsHomogenization.ofHomogenization R A) _).strictMono ?_ + refine GradeOrder.liftRight _ (IsHomogenization.Face.homogenizeIso ℋ _).strictMono ?_ exact fun x y ↦ (apply_covBy_apply_iff _).mpr end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 527db024..9e3debec 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -44,7 +44,6 @@ def homogenizeOrderHom : ConvexSet R A →o PointedCone R W where toFun := homogenize ℋ monotone' := homogenize_monotone _ -@[simp] lemma homogenize_singleton (p : A) : homogenize ℋ ({p} : ConvexSet R A) = R ∙₊ ℋ.ofPoint p := by have h : (({p} : ConvexSet R A) : Set A) = {p} := rfl rw [homogenize, h, Set.image_singleton] diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index cdfd5d63..887964f7 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -35,7 +35,7 @@ namespace Affine section Ring -open Function Submodule +open Function Submodule AffineSubspace variable {R : Type*} [Ring R] variable {V : Type*} [AddCommGroup V] [Module R V] @@ -244,22 +244,22 @@ theorem weight_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) /-- A module is a homogenization of the weight-one hyperplane of any linear functional, provided that hyperplane is nonempty. -/ -def ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - IsHomogenization R ((affineSpan R {1}).comap g.toAffineMap) W := +def ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : + IsHomogenization R (comap g.toAffineMap {1}) W := ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -theorem ofPoint_ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - (ofWeightOne g).ofPoint = ((affineSpan R {1}).comap g.toAffineMap).subtype := by +theorem ofPoint_ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : + (ofWeightOne g).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightOne] @[simp] -theorem ofVector_ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : - (ofWeightOne g).ofVector = ((affineSpan R {1}).comap g.toAffineMap).direction.subtype := by +theorem ofVector_ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : + (ofWeightOne g).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightOne] @[simp] -theorem weight_ofWeightOne (g : W →ₗ[R] R) [Nonempty ((affineSpan R {1}).comap g.toAffineMap)] : +theorem weight_ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : (ofWeightOne g).weight = g := by simp [ofWeightOne] From c829e9bee0bb428063ec329ebfbf68e4305ca8ed Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 30 Sep 2026 15:41:33 +0200 Subject: [PATCH 12/39] adding constructor for field and nonzero functional --- .../Homogenization/IsHomogenization.lean | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 887964f7..ded5e556 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -269,4 +269,44 @@ end IsHomogenization end Ring +section Field + +namespace IsHomogenization + +open Function Submodule AffineSubspace + +variable {R : Type*} [DivisionRing R] +variable {V : Type*} [AddCommGroup V] [Module R V] +variable {P : Type*} [AddTorsor V P] +variable {W : Type*} [AddCommGroup W] [Module R W] + +instance {g : W →ₗ[R] R} [h : Fact (g ≠ 0)] : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h.out + use (g y)⁻¹ • y + simp [hy] + +/-- A module is a homogenization of the weight-one hyperplane of any nonzero linear functional. -/ +def ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : + IsHomogenization R (comap g.toAffineMap {1}) W := + ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + +@[simp] +theorem ofPoint_ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : + (ofWeightNeZero g).ofPoint = (comap g.toAffineMap {1}).subtype := by + simp [ofWeightNeZero] + +@[simp] +theorem ofVector_ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : + (ofWeightNeZero g).ofVector = (comap g.toAffineMap {1}).direction.subtype := by + simp [ofWeightNeZero] + +@[simp] +theorem weight_ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : + (ofWeightNeZero g).weight = g := by + simp [ofWeightNeZero] + +end IsHomogenization + +end Field + end Affine From e668af42da2fe4e43caa2e228e358c1fdb111f8c Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 30 Sep 2026 16:07:11 +0200 Subject: [PATCH 13/39] renaming face homogenizaIso --- .../Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean | 2 +- .../Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 144b2a3c..3fd6a37a 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -54,7 +54,7 @@ private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polyto let ℋ := IsHomogenization.ofHomogenization R A have : (homogenize _ (P : ConvexSet R A)).FG := IsPolytope.homogenize_fg ℋ P.isPolytope let := PointedCone.FG.gradeOrder_finrank this - refine GradeOrder.liftRight _ (IsHomogenization.Face.homogenizeIso ℋ _).strictMono ?_ + refine GradeOrder.liftRight _ (face_homogenizeIso ℋ P).strictMono ?_ exact fun x y ↦ (apply_covBy_apply_iff _).mpr end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean index 25ceb7a9..1bc03668 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean @@ -107,7 +107,7 @@ its homogenization cone. This isomorphism is used to translate results between face lattices of cones and face lattices of convex sets. -/ -def Face.homogenizeIso (P : ConvexSet R A) : +def _root_.ConvexSet.face_homogenizeIso (P : ConvexSet R A) : Face P ≃o PointedCone.Face (P.homogenize ℋ) where toFun F := ⟨_, ℋ.homogenize_isFaceOf F.isFaceOf⟩ invFun F := ⟨dehomogenize ℋ F.toSubmodule, From 90a36cd3dc7423177bc18f99ba74aef24840d13b Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 6 Oct 2026 12:21:48 +0200 Subject: [PATCH 14/39] inlining nonempty proofs --- .../Homogenization/IsHomogenization.lean | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index ded5e556..c5a249cf 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -243,24 +243,29 @@ theorem weight_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) exact congr(embed x ∈ $embed_range).mp <| Set.mem_range_self x /-- A module is a homogenization of the weight-one hyperplane of any linear functional, -provided that hyperplane is nonempty. -/ -def ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : +provided that hyperplane contains 1. -/ +def ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h IsHomogenization R (comap g.toAffineMap {1}) W := + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -theorem ofPoint_ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : - (ofWeightOne g).ofPoint = (comap g.toAffineMap {1}).subtype := by +theorem ofPoint_ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + (ofWeightOne g h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightOne] @[simp] -theorem ofVector_ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : - (ofWeightOne g).ofVector = (comap g.toAffineMap {1}).direction.subtype := by +theorem ofVector_ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + (ofWeightOne g h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightOne] @[simp] -theorem weight_ofWeightOne (g : W →ₗ[R] R) [Nonempty (comap g.toAffineMap {1})] : - (ofWeightOne g).weight = g := by +theorem weight_ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + (ofWeightOne g h).weight = g := by simp [ofWeightOne] end Constructions @@ -280,29 +285,39 @@ variable {V : Type*} [AddCommGroup V] [Module R V] variable {P : Type*} [AddTorsor V P] variable {W : Type*} [AddCommGroup W] [Module R W] -instance {g : W →ₗ[R] R} [h : Fact (g ≠ 0)] : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h.out - use (g y)⁻¹ • y - simp [hy] - /-- A module is a homogenization of the weight-one hyperplane of any nonzero linear functional. -/ -def ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : +def ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ IsHomogenization R (comap g.toAffineMap {1}) W := + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -theorem ofPoint_ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : - (ofWeightNeZero g).ofPoint = (comap g.toAffineMap {1}).subtype := by +theorem ofPoint_ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + (ofWeightNeZero g h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightNeZero] @[simp] -theorem ofVector_ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : - (ofWeightNeZero g).ofVector = (comap g.toAffineMap {1}).direction.subtype := by +theorem ofVector_ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + (ofWeightNeZero g h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightNeZero] @[simp] -theorem weight_ofWeightNeZero (g : W →ₗ[R] R) [Fact (g ≠ 0)] : - (ofWeightNeZero g).weight = g := by +theorem weight_ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + (ofWeightNeZero g h).weight = g := by simp [ofWeightNeZero] end IsHomogenization From bd4e93545a4228e9e7169c0b5a0a9e1f71f383ec Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 6 Oct 2026 12:33:45 +0200 Subject: [PATCH 15/39] making arg implicit --- .../Homogenization/IsHomogenization.lean | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index c5a249cf..08f24f7b 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -244,28 +244,28 @@ theorem weight_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) /-- A module is a homogenization of the weight-one hyperplane of any linear functional, provided that hyperplane contains 1. -/ -def ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : +def ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h IsHomogenization R (comap g.toAffineMap {1}) W := have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -theorem ofPoint_ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : +theorem ofPoint_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h - (ofWeightOne g h).ofPoint = (comap g.toAffineMap {1}).subtype := by + (ofWeightOne h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightOne] @[simp] -theorem ofVector_ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : +theorem ofVector_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h - (ofWeightOne g h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by + (ofWeightOne h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightOne] @[simp] -theorem weight_ofWeightOne (g : W →ₗ[R] R) (h : 1 ∈ g.range) : +theorem weight_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h - (ofWeightOne g h).weight = g := by + (ofWeightOne h).weight = g := by simp [ofWeightOne] end Constructions @@ -286,7 +286,7 @@ variable {P : Type*} [AddTorsor V P] variable {W : Type*} [AddCommGroup W] [Module R W] /-- A module is a homogenization of the weight-one hyperplane of any nonzero linear functional. -/ -def ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : +def ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ @@ -297,27 +297,27 @@ def ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) @[simp] -theorem ofPoint_ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : +theorem ofPoint_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ - (ofWeightNeZero g h).ofPoint = (comap g.toAffineMap {1}).subtype := by + (ofWeightNeZero h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightNeZero] @[simp] -theorem ofVector_ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : +theorem ofVector_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ - (ofWeightNeZero g h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by + (ofWeightNeZero h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightNeZero] @[simp] -theorem weight_ofWeightNeZero (g : W →ₗ[R] R) (h : g ≠ 0) : +theorem weight_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ - (ofWeightNeZero g h).weight = g := by + (ofWeightNeZero h).weight = g := by simp [ofWeightNeZero] end IsHomogenization From d6c5f29c466a25ed33ab481967e86708f4bea066 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 6 Oct 2026 13:40:20 +0200 Subject: [PATCH 16/39] re-renaming to canonical --- .../Geometry/Convex/ConvexSpace/Polytope/Face.lean | 4 ++-- .../AffineSpace/Homogenization/IsHomogenization.lean | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 3fd6a37a..3ad5e25f 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -33,7 +33,7 @@ include V in theorem IsPolytope.face_isPolytope (hC : IsPolytope R (C : Set A)) (hF : IsFaceOf F C) : IsPolytope R (F : Set A) := by let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule - have homF := (IsHomogenization.ofHomogenization R A).homogenize_isFaceOf hF + have homF := (IsHomogenization.canonical R A).homogenize_isFaceOf hF have := PointedCone.IsFaceOf.fg (IsPolytope.homogenize_fg _ hC) homF convert FG.dehomogenize_isPolytope this (fun _ a b ↦ weight_pos_of_mem_homogenize a b) simp [dehomogenize_homogenize] @@ -51,7 +51,7 @@ This is private since it does not yet have the correct grading (off-by-one). private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polytope R A) : GradeOrder ℕ (Face (P : ConvexSet R A)) := by let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule - let ℋ := IsHomogenization.ofHomogenization R A + let ℋ := IsHomogenization.canonical R A have : (homogenize _ (P : ConvexSet R A)).FG := IsPolytope.homogenize_fg ℋ P.isPolytope let := PointedCone.FG.gradeOrder_finrank this refine GradeOrder.liftRight _ (face_homogenizeIso ℋ P).strictMono ?_ diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 08f24f7b..34b81423 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -193,18 +193,18 @@ section Constructions variable (R P) in /-- The canonical homogenization is a homogenization. -/ @[expose] -def ofHomogenization : IsHomogenization R P (Homogenization R P) := ofRepr <| LinearEquiv.refl .. +def canonical : IsHomogenization R P (Homogenization R P) := ofRepr <| LinearEquiv.refl .. @[simp] -theorem ofPoint_ofHomogenization : (ofHomogenization R P).ofPoint = Homogenization.ofPoint := +theorem ofPoint_canonical : (canonical R P).ofPoint = Homogenization.ofPoint := (rfl) @[simp] -theorem ofVector_ofHomogenization : (ofHomogenization R P).ofVector = Homogenization.ofVector := +theorem ofVector_canonical : (canonical R P).ofVector = Homogenization.ofVector := (rfl) @[simp] -theorem weight_ofHomogenization : (ofHomogenization R P).weight = Homogenization.weight := +theorem weight_canonical : (canonical R P).weight = Homogenization.weight := (rfl) /-- Construct a homogenization from an embedding of the affine space `P` into the vector @@ -216,7 +216,7 @@ def ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) {weight : W IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm - exact lift_bijective_of_injective_of_range_preimage (ofHomogenization R P) embed_inj embed_range + exact lift_bijective_of_injective_of_range_preimage (canonical R P) embed_inj embed_range /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] From 7950d7e6b0a90f320593e60e975a8d18d3118e93 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 6 Oct 2026 13:42:28 +0200 Subject: [PATCH 17/39] using AffineMap.range --- .../AffineSpace/Homogenization/IsHomogenization.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 34b81423..bc494d8b 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -212,7 +212,7 @@ space `W` and a weight map that is the constant 1-map on the embedded `P`. This axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ def ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} - (embed_range : Set.range embed = weight ⁻¹' {1}) : + (embed_range : embed.range = weight ⁻¹' {1}) : IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm @@ -221,14 +221,14 @@ def ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) {weight : W /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] theorem ofPoint_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + {weight : W →ₗ[R] R} (embed_range : embed.range = weight ⁻¹' {1}) : (ofEmbed embed_inj embed_range).ofPoint = embed := by ext p exact Homogenization.lift_apply_ofPoint .. @[simp] theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + {weight : W →ₗ[R] R} (embed_range : embed.range = weight ⁻¹' {1}) : (ofEmbed embed_inj embed_range).ofVector = embed.linear := by ext p exact Homogenization.lift_apply_ofVector .. @@ -236,7 +236,7 @@ theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) /-- The weight used in the construction becomes the weight in the homogenization. -/ @[simp] theorem weight_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : Set.range embed = weight ⁻¹' {1}) : + {weight : W →ₗ[R] R} (embed_range : embed.range = weight ⁻¹' {1}) : (ofEmbed embed_inj embed_range).weight = weight := by refine (ofEmbed embed_inj embed_range).hom_ext fun x => ?_ rw [weight_ofPoint, ofPoint_ofEmbed, eq_comm] From 0e8ef0a051a78fd1de6a06ab1df41556d69fde07 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 6 Oct 2026 13:48:16 +0200 Subject: [PATCH 18/39] using h for hypothesis --- .../Homogenization/IsHomogenization.lean | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index bc494d8b..340e5bb4 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -172,19 +172,19 @@ variable {U : Type*} [AddCommGroup U] [Module R U] {f : P →ᵃ[R] U} {g : U lemma comp_lift_eq_weight (h : ∀ p, g (f p) = 1) : g ∘ₗ (ℋ.lift f) = ℋ.weight := ℋ.hom_ext <| by simpa -lemma lift_bijective_of_injective_of_range_preimage (f_inj : Injective f) - (f_range : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by - have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp f_range.subset +lemma lift_bijective_ohinjective_ohrange_preimage (hinj : Injective f) + (hrange : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by + have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp hrange.subset constructor · rw [injective_iff_map_eq_zero] intro a ha have : ℋ.weight a = 0 := by simp [← ℋ.comp_lift_eq_weight g_f, ha] obtain ⟨_, rfl⟩ := ℋ.weight_eq_zero_iff.mp this rw [ℋ.lift_apply_ofVector] at ha - simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr f_inj)).mp ha] + simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr hinj)).mp ha] · intro w obtain p₀ := Classical.arbitrary P - obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by simp [f_range, g_f] + obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by simp [hrange, g_f] exact ⟨ℋ.ofVector (a -ᵥ p₀) + g w • ℋ.ofPoint p₀, by simp [ofPoint, ofVector, lift, ha]⟩ end @@ -211,36 +211,33 @@ theorem weight_canonical : (canonical R P).weight = Homogenization.weight := space `W` and a weight map that is the constant 1-map on the embedded `P`. This follows the axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -def ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) {weight : W →ₗ[R] R} - (embed_range : embed.range = weight ⁻¹' {1}) : - IsHomogenization R P W where +def ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm - exact lift_bijective_of_injective_of_range_preimage (canonical R P) embed_inj embed_range + exact lift_bijective_ohinjective_ohrange_preimage (canonical R P) hinj hrange /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] -theorem ofPoint_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : embed.range = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).ofPoint = embed := by +theorem ofPoint_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : (ofEmbed hinj hrange).ofPoint = embed := by ext p exact Homogenization.lift_apply_ofPoint .. @[simp] -theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : embed.range = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).ofVector = embed.linear := by +theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : (ofEmbed hinj hrange).ofVector = embed.linear := by ext p exact Homogenization.lift_apply_ofVector .. /-- The weight used in the construction becomes the weight in the homogenization. -/ @[simp] -theorem weight_ofEmbed {embed : P →ᵃ[R] W} (embed_inj : Injective embed) - {weight : W →ₗ[R] R} (embed_range : embed.range = weight ⁻¹' {1}) : - (ofEmbed embed_inj embed_range).weight = weight := by - refine (ofEmbed embed_inj embed_range).hom_ext fun x => ?_ +theorem weight_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) + {weight : W →ₗ[R] R} (hrange : embed.range = weight ⁻¹' {1}) : + (ofEmbed hinj hrange).weight = weight := by + refine (ofEmbed hinj hrange).hom_ext fun x => ?_ rw [weight_ofPoint, ofPoint_ofEmbed, eq_comm] - exact congr(embed x ∈ $embed_range).mp <| Set.mem_range_self x + exact congr(embed x ∈ $hrange).mp <| Set.mem_range_self x /-- A module is a homogenization of the weight-one hyperplane of any linear functional, provided that hyperplane contains 1. -/ From 81ddc4571973d90fb51e1d11d032bb230e43875e Mon Sep 17 00:00:00 2001 From: ooovi <79147175+ooovi@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:55:41 +0200 Subject: [PATCH 19/39] Update Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean Co-authored-by: M. Winter <112132359+martinwintermath@users.noreply.github.com> --- .../AffineSpace/Homogenization/IsHomogenization.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 340e5bb4..4bc747ef 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -112,7 +112,7 @@ theorem lift_symm_apply (f : W →ₗ[R] U) (p : P) : ℋ.lift.symm f p = f (ℋ end -/-- The linear map that is constantly `1` when restricted to `P`. -/ +/-- The linear map that is constant with value `1` when restricted to `P` -/ def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap /-- The homogenization of a point in `P` has weight 1. -/ From 19fb7cdf819a6426cfe9188b113c4a87af74b1d4 Mon Sep 17 00:00:00 2001 From: ooovi <79147175+ooovi@users.noreply.github.com> Date: Wed, 7 Oct 2026 11:01:41 +0200 Subject: [PATCH 20/39] removing non-simple simps --- .../AffineSpace/Homogenization/IsHomogenization.lean | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 4bc747ef..afd0d386 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -247,13 +247,11 @@ def ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) -@[simp] theorem ofPoint_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h (ofWeightOne h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightOne] -@[simp] theorem ofVector_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h (ofWeightOne h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by @@ -293,7 +291,6 @@ def ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) -@[simp] theorem ofPoint_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h @@ -301,7 +298,6 @@ theorem ofPoint_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : (ofWeightNeZero h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightNeZero] -@[simp] theorem ofVector_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h From 49d1d18a2fecdb98085ba5afba5488b1e3b7e029 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 7 Oct 2026 11:06:00 +0200 Subject: [PATCH 21/39] renaming ofEmbed to ofWeightEmbed --- .../Homogenization/IsHomogenization.lean | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index afd0d386..d690aff7 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -12,8 +12,8 @@ public import Mathlib.LinearAlgebra.AffineSpace.Homogenization /-! This file defines affine homogenization as any vector space linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. It also proves every object that satisfies the axiomatic description from [Gallier2011GeometricMethods] is a homogenization -in the linear equivalence sense (see `ofEmbed`). Use `IsHomogenization` for convenience if you want -to consider an embedding into a vector space that is not the canonical `Homogenization`. +in the linear equivalence sense (see `ofWeightEmbed`). Use `IsHomogenization` for convenience if you +want to consider an embedding into a vector space that is not the canonical `Homogenization`. ## Implementation notes * We transport relevant theorems from `Homogenization`. @@ -211,7 +211,7 @@ theorem weight_canonical : (canonical R P).weight = Homogenization.weight := space `W` and a weight map that is the constant 1-map on the embedded `P`. This follows the axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -def ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} +def ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} (hrange : embed.range = weight ⁻¹' {1}) : IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm @@ -219,24 +219,25 @@ def ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[ /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] -theorem ofPoint_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} - (hrange : embed.range = weight ⁻¹' {1}) : (ofEmbed hinj hrange).ofPoint = embed := by +theorem ofPoint_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : (ofWeightEmbed hinj hrange).ofPoint = embed := by ext p exact Homogenization.lift_apply_ofPoint .. @[simp] -theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} - (hrange : embed.range = weight ⁻¹' {1}) : (ofEmbed hinj hrange).ofVector = embed.linear := by +theorem ofVector_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : + (ofWeightEmbed hinj hrange).ofVector = embed.linear := by ext p exact Homogenization.lift_apply_ofVector .. /-- The weight used in the construction becomes the weight in the homogenization. -/ @[simp] -theorem weight_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) +theorem weight_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} (hrange : embed.range = weight ⁻¹' {1}) : - (ofEmbed hinj hrange).weight = weight := by - refine (ofEmbed hinj hrange).hom_ext fun x => ?_ - rw [weight_ofPoint, ofPoint_ofEmbed, eq_comm] + (ofWeightEmbed hinj hrange).weight = weight := by + refine (ofWeightEmbed hinj hrange).hom_ext fun x => ?_ + rw [weight_ofPoint, ofPoint_ofWeightEmbed, eq_comm] exact congr(embed x ∈ $hrange).mp <| Set.mem_range_self x /-- A module is a homogenization of the weight-one hyperplane of any linear functional, @@ -245,7 +246,7 @@ def ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h IsHomogenization R (comap g.toAffineMap {1}) W := have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h - ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) theorem ofPoint_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h @@ -289,7 +290,7 @@ def ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ - ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) theorem ofPoint_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : have : Nonempty (comap g.toAffineMap {1}) := by From 243d83b005dcaf4d9c751b214df47fe46c4c29ed Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 7 Oct 2026 17:16:10 +0200 Subject: [PATCH 22/39] removing bundled convex set --- Polyhedral.lean | 4 +- .../Convex/Cone/Pointed/Convexity.lean | 8 +- .../Convex/ConvexSpace/Homogenization.lean | 43 +-- .../ConvexSpace/Polyhedron/Lattice.lean | 7 +- .../Convex/ConvexSpace/Polytope/Face.lean | 34 +- .../ConvexSpace/Polytope/Homogenization.lean | 43 ++- .../Convex/ConvexSpace/Polytope/Lattice.lean | 11 +- .../ConvexSpace/Set/BundledFace/Basic.lean | 187 ++++++++++ .../Set/BundledFace/Homogenization.lean | 128 +++++++ .../ConvexSpace/Set/BundledFace/Lattice.lean | 142 ++++++++ .../Convex/ConvexSpace/Set/Face/Basic.lean | 214 ++++++------ .../ConvexSpace/Set/Face/Homogenization.lean | 64 ++-- .../Convex/ConvexSpace/Set/Face/Lattice.lean | 82 ++--- .../ConvexSpace/Set/Homogenization.lean | 203 ++++++----- .../LinearAlgebra/AffineSpace/AffineMap.lean | 127 ------- .../AffineSpace/AffineSubspace/Range.lean | 90 +++++ .../AffineSpace/Homogenization/Basic.lean | 230 ------------- .../Homogenization/IsHomogenization.lean | 324 ++++++++++++++++++ .../AffineSpace/Homogenization/Set.lean | 220 ++++++------ 19 files changed, 1327 insertions(+), 834 deletions(-) create mode 100644 Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Basic.lean create mode 100644 Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Homogenization.lean create mode 100644 Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Lattice.lean delete mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean create mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean delete mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean create mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean diff --git a/Polyhedral.lean b/Polyhedral.lean index 53d06d22..1b028e43 100644 --- a/Polyhedral.lean +++ b/Polyhedral.lean @@ -67,12 +67,12 @@ public import Polyhedral.Mathlib.Geometry.Convex.Fun.Dual public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Closure public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Nonneg -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineMap public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Defs +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Defs public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Dimension -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Set public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Lattice public import Polyhedral.Mathlib.LinearAlgebra.BilinearMap diff --git a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean index 35709c33..815bad5e 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean @@ -7,7 +7,7 @@ module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Basic public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Hull -public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice +-- public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Module @@ -37,10 +37,10 @@ lemma isConvexSet (P : PointedCone R M) : IsConvexSet R (P : Set M) := by refine P.finsuppSum_mem _ _ (fun i r ↦ r • i) (fun c hc ↦ ?_) exact P.smul_mem (w.weights_nonneg c) <| hw (Finsupp.mem_support_iff.mpr hc) -@[coe] -def toConvexSet (P : PointedCone R M) : ConvexSet R M := ⟨_, P.isConvexSet⟩ +-- @[coe] +-- def toConvexSet (P : PointedCone R M) : ConvexSet R M := ⟨_, P.isConvexSet⟩ -instance : Coe (PointedCone R M) (ConvexSet R M) := ⟨toConvexSet⟩ +-- instance : Coe (PointedCone R M) (ConvexSet R M) := ⟨toConvexSet⟩ @[simp] theorem hull_convexHull (t : Set M) : hull R (Convexity.convexHull R t) = hull R t := by diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean index 3d997764..5ae1ad42 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Homogenization.lean @@ -6,7 +6,7 @@ Authors: Martin Winter, Olivia Röhrig module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Convexity -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization /-! This file proves results about the interaction of homogenization and convexity. -/ @@ -23,7 +23,7 @@ variable {R : Type*} [Ring R] [PartialOrder R] [IsStrictOrderedRing R] variable {V : Type*} [AddCommGroup V] [Module R V] variable {A : Type*} [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable {W : Type*} [AddCommGroup W] [Module R W] [ConvexSpace R W] -variable [hom : Affine.IsHomogenization R A W] +variable {ℋ : Affine.IsHomogenization R A W} section Module @@ -32,54 +32,55 @@ variable [IsModuleConvexSpace R W] /-- If the homogenization of a point lies in the conic hull of a subset `s` of the homogenization plane, the point can be written as a convex combination of points in the preimage of `s` under the homogenization embedding. -/ -theorem exists_sConvexComb_preimage_of_mem_hull {x} {s : Set W} (hs : s ⊆ Set.range hom.ofPoint) - (hx : hom.ofPoint x ∈ hull R s) : ∃ c' : StdSimplex R A, - sConvexComb c' = x ∧ (c'.weights.support : Set A) ⊆ (hom.ofPoint ⁻¹' s) := by +theorem exists_sConvexComb_preimage_of_mem_hull {x} {s : Set W} (hs : s ⊆ Set.range ℋ.ofPoint) + (hx : ℋ.ofPoint x ∈ hull R s) : ∃ c' : StdSimplex R A, + sConvexComb c' = x ∧ (c'.weights.support : Set A) ⊆ (ℋ.ofPoint ⁻¹' s) := by obtain ⟨c, ha, hb, hc⟩ := mem_hull_set.mp hx -- use the same weights, just un-embed the domain - use StdSimplex.mk (c.comapDomain hom.ofPoint hom.ofPoint_injective.injOn) ?_ ?_ + use StdSimplex.mk (c.comapDomain ℋ.ofPoint ℋ.ofPoint_injective.injOn) ?_ ?_ constructor · -- the convex combo yields x - apply hom.ofPoint_injective - rw [hom.ofPoint.isAffineMap.map_sConvexComb, sConvexComb_eq_sum, - StdSimplex.weights_map, ← hc, Finsupp.mapDomain_comapDomain _ hom.ofPoint_injective] + apply ℋ.ofPoint_injective + rw [ℋ.ofPoint.isAffineMap.map_sConvexComb, sConvexComb_eq_sum, + StdSimplex.weights_map, ← hc, Finsupp.mapDomain_comapDomain _ ℋ.ofPoint_injective] exact ha.trans hs · -- the weights are a subset of the preimage of s simpa using (Set.preimage_mono ha) · -- they're always nonneg intro y - simpa using hb (hom.ofPoint y) + simpa using hb (ℋ.ofPoint y) · -- its actually a convex combo, i.e. weights sum to 1 - have hsum : c.sum (fun a b => b * hom.weight a) = c.sum (fun a b => b) := by + have hsum : c.sum (fun a b => b * ℋ.weight a) = c.sum (fun a b => b) := by refine Finsupp.sum_congr (fun a h => ?_) obtain ⟨_, _, rfl⟩ := (ha.trans hs) h - simp [hom.weight_one] + simp [ℋ.weight_ofPoint] -- apply weights map to both sides - have := congrArg hom.weight hc - simp only [map_finsuppSum, map_smul, smul_eq_mul, hsum, hom.weight_one] at this + have := congrArg ℋ.weight hc + simp only [map_finsuppSum, map_smul, smul_eq_mul, hsum, ℋ.weight_ofPoint] at this rw [← this] simp only [Finsupp.sum, Finsupp.comapDomain_support, Finsupp.comapDomain_apply] - rw [Finset.sum_preimage hom.ofPoint _ (hom.ofPoint_injective.injOn)] + rw [Finset.sum_preimage ℋ.ofPoint _ (ℋ.ofPoint_injective.injOn)] exact fun _ hx hnx ↦ Finsupp.notMem_support_iff.mp fun _ ↦ hnx (hs (ha hx)) /-- The preimage of the conic hull of a set in the homogenization plane is the convex hull of the preimage of the set. -/ -theorem preimage_hull_eq_convexHull_preimage {s : Set W} (hs : s ⊆ Set.range hom.ofPoint) : - hom.ofPoint ⁻¹' hull R s = Convexity.convexHull R (hom.ofPoint ⁻¹' s) := by +theorem preimage_hull_eq_convexHull_preimage {s : Set W} (hs : s ⊆ Set.range ℋ.ofPoint) : + ℋ.ofPoint ⁻¹' hull R s = Convexity.convexHull R (ℋ.ofPoint ⁻¹' s) := by refine subset_antisymm ?_ ?_ · intro x hx obtain ⟨c', rfl, hs⟩ := exists_sConvexComb_preimage_of_mem_hull hs hx exact IsConvexSet.convexHull.sConvexComb_mem (le_trans hs subset_convexHull_self) · apply Set.image_subset_iff.mp - rw [hom.ofPoint.isAffineMap.image_convexHull, Set.image_preimage_eq_iff.mpr hs] + rw [ℋ.ofPoint.isAffineMap.image_convexHull, Set.image_preimage_eq_iff.mpr hs] exact (hull R s).isConvexSet.convexHull_subset_iff.mpr subset_hull +variable (hom) in /-- The homogenization embedding of the convex hull of a set is contained in the hull of the embedding of the set. -/ -theorem preimage_hull_eq_convexHull_preimagke {s : Set A} : - hom.ofPoint '' Convexity.convexHull R s ⊆ hull R (hom.ofPoint '' s) := by +theorem image_hull_eq_convexHull_image {s : Set A} : + ℋ.ofPoint '' Convexity.convexHull R s ⊆ hull R (ℋ.ofPoint '' s) := by apply Set.image_subset_iff.mp - rw [hom.ofPoint.isAffineMap.image_convexHull] + rw [ℋ.ofPoint.isAffineMap.image_convexHull] simpa using (hull R _).isConvexSet.convexHull_subset_iff.mpr subset_hull end Module diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polyhedron/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polyhedron/Lattice.lean index 7ac33064..9f9e4cc5 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polyhedron/Lattice.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polyhedron/Lattice.lean @@ -17,7 +17,7 @@ namespace Convexity open Convexity variable {R : Type*} [Ring R] [PartialOrder R] [IsStrictOrderedRing R] -variable {V : Type*} [AddCommGroup V] [Module R V] -- [ConvexSpace R V] [IsModuleConvexSpace R V] +variable {V : Type*} [AddCommGroup V] [Module R V] variable {A : Type*} [AddTorsor V A] [ConvexSpace R A] variable (R A) in @@ -50,11 +50,6 @@ section IsModuleConvexSpace variable [ConvexSpace R V] [IsModuleConvexSpace R V] [IsAffineConvexSpace R V A] -@[coe] def toConvexSet (P : Polyhedron R A) : ConvexSet R A := - ⟨P, P.isPolyhedron.isConvexSet⟩ - -instance : Coe (Polyhedron R A) (ConvexSet R A) := ⟨toConvexSet⟩ - end IsModuleConvexSpace /- # LE -/ diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 518a7dbe..666d0de3 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -7,6 +7,7 @@ module public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Homogenization +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Lattice import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Finite.Face.Grade import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Homogenization @@ -18,7 +19,7 @@ public section variable {R V A : Type*} -open Convexity ConvexSet Affine +open Convexity IsConvexSet Affine section Field @@ -26,23 +27,22 @@ variable [Field R] [LinearOrder R] [IsStrictOrderedRing R] variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] -variable {C F : ConvexSet R A} +variable {C F : Set A} include V in /-- Faces of polytopes are polytopes. -/ -theorem IsPolytope.face_isPolytope (hC : IsPolytope R (C : Set A)) (hF : IsFaceOf F C) : +theorem IsPolytope.face_isPolytope + (hC : IsPolytope R C) (hF : IsFaceOf R F C) (hcF : IsConvexSet R F) : IsPolytope R (F : Set A) := by - let W := Homogenization R A - let : ConvexSpace R W := ConvexSpace.ofModule - have homC := IsPolytope.homogenize_fg (W := W) hC - have homF := IsHomogenization.homogenize_isFaceOf (W := W) hF - have := PointedCone.IsFaceOf.fg homC homF + let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule + have homF := (IsHomogenization.canonical R A).homogenize_isFaceOf hcF hC.isConvexSet hF + have := PointedCone.IsFaceOf.fg (IsPolytope.homogenize_fg _ hC) homF convert FG.dehomogenize_isPolytope this (fun _ a b ↦ weight_pos_of_mem_homogenize a b) - simp [dehomogenize_homogenize] + rw [dehomogenize_homogenize _ hcF] include V in -instance {P : Polytope R A} : CoeOut (Face (P : ConvexSet R A)) (Polytope R A) where - coe F := ⟨_, IsPolytope.face_isPolytope P.isPolytope F.isFaceOf⟩ +instance {P : Polytope R A} : CoeOut (Face P.isPolytope.isConvexSet) (Polytope R A) where + coe F := ⟨_, IsPolytope.face_isPolytope P.isPolytope F.isFaceOf F.isConvexSet⟩ include V in /-- The face lattice of a polytope as a graded order with grading given by the dimensions of @@ -51,14 +51,12 @@ homogenization cones. This is private since it does not yet have the correct grading (off-by-one). -/ private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polytope R A) : - GradeOrder ℕ (Face (P : ConvexSet R A)) := by - let W := Homogenization R A - letI : ConvexSpace R W := ConvexSpace.ofModule - have : PointedCone.FG (homogenize W (P : ConvexSet R A)) := - IsPolytope.homogenize_fg (W := W) P.isPolytope + GradeOrder ℕ (Face P.isPolytope.isConvexSet) := by + let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule + let ℋ := IsHomogenization.canonical R A + have : (homogenize _ (P : Set A)).FG := IsPolytope.homogenize_fg ℋ P.isPolytope let := PointedCone.FG.gradeOrder_finrank this - refine GradeOrder.liftRight (β := (homogenize W (P : ConvexSet R A)).Face) _ - IsHomogenization.Face.homogenizeIso.strictMono ?_ + refine GradeOrder.liftRight _ (face_homogenizeIso ℋ P.isPolytope.isConvexSet).strictMono ?_ exact fun x y ↦ (apply_covBy_apply_iff _).mpr end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean index 1f1930d8..2f5d3287 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Homogenization.lean @@ -17,7 +17,7 @@ public section variable {R V W A : Type*} -open Convexity ConvexSet Affine IsHomogenization +open Convexity Affine IsHomogenization section Ring @@ -28,46 +28,45 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) open PointedCone /-- The homogenization of a polytope is a finitely generated cone. -/ -theorem IsPolytope.homogenize_fg {C : ConvexSet R A} (hCfg : IsPolytope R (C : Set A)) : - (homogenize W C).FG := by +theorem IsPolytope.homogenize_fg {C : Set A} (hCfg : IsPolytope R C) : + (homogenize ℋ C).FG := by obtain ⟨t, ht⟩ := hCfg - have : C = ⟨convexHull R t, IsConvexSet.convexHull⟩ := SetLike.ext' ht - have := congrArg (ConvexSet.homogenize W) this + have := congrArg (homogenize ℋ) ht rw [this] - use t.map ⟨_, hom.ofPoint_injective⟩ + use t.map ⟨_, ℋ.ofPoint_injective⟩ simp only [Finset.coe_map, Function.Embedding.coeFn_mk, homogenize, - PointedCone.hull, ConvexSet.mk_eq] - rw [hom.ofPoint.isAffineMap.image_convexHull t] - exact (PointedCone.hull_convexHull (hom.ofPoint '' t)).symm + PointedCone.hull] + rw [ℋ.ofPoint.isAffineMap.image_convexHull t] + exact (PointedCone.hull_convexHull (ℋ.ofPoint '' t)).symm /-- A convex set is a polytope iff its homogenization is a finitely generated cone. -/ -theorem IsPolytope.iff_homogenize_fg {C : ConvexSet R A} : - IsPolytope R (C : Set A) ↔ (homogenize W C).FG := by classical - refine ⟨homogenize_fg, fun hfg ↦ ?_⟩ +theorem IsPolytope.iff_homogenize_fg {C : Set A} (hC : IsConvexSet R C) : + IsPolytope R C ↔ (homogenize ℋ C).FG := by classical + refine ⟨homogenize_fg _, fun hfg ↦ ?_⟩ -- get cone generators that lie in the embedding of A obtain ⟨g, hg, hs⟩ := homogenize_fg_ofPoint_range hfg -- un-embed them - use g.preimage hom.ofPoint hom.ofPoint_injective.injOn + use g.preimage ℋ.ofPoint ℋ.ofPoint_injective.injOn -- show they generate C simp only [Finset.coe_preimage] apply le_antisymm · intro x hx rw [← preimage_hull_eq_convexHull_preimage hs] simp only [hg, homogenize] - exact Submodule.mem_span_of_mem <| Set.mem_image_of_mem hom.ofPoint hx - · apply C.isConvexSet.convexHull_subset_iff.mpr + exact Submodule.mem_span_of_mem <| Set.mem_image_of_mem ℋ.ofPoint hx + · apply hC.convexHull_subset_iff.mpr intro x hx simp only [Set.mem_preimage, SetLike.mem_coe] at hx have := Set.mem_preimage.mpr <| Submodule.mem_span_of_mem (R := {c : R // 0 ≤ c}) hx simp_rw [hg, homogenize] at this - rw [preimage_hull_eq_convexHull_preimage (Set.image_subset_range hom.ofPoint C)] at this - rw [← C.isConvexSet.convexHull_eq_self] - simpa [← C.isConvexSet.convexHull_eq_self, Set.preimage_image_eq _ hom.ofPoint_injective] + rw [preimage_hull_eq_convexHull_preimage (Set.image_subset_range ℋ.ofPoint C)] at this + rw [← hC.convexHull_eq_self] + simpa [hC.convexHull_eq_self, Set.preimage_image_eq _ ℋ.ofPoint_injective] end Ring @@ -80,13 +79,13 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable [hom : IsHomogenization R A W] +variable {ℋ : IsHomogenization R A W} open Pointwise Submodule in /-- Dehomogenizing a finitely generated positive cone yields a polytope. -/ theorem FG.dehomogenize_isPolytope {C : PointedCone R W} (h : C.FG) - (hc : C ≤ hom.weight.positive) : IsPolytope R (dehomogenize A C : Set A) := by - rw [IsPolytope.iff_homogenize_fg (W := W)] + (hc : C ≤ ℋ.weight.positive) : IsPolytope R (dehomogenize ℋ C : Set A) := by + rw [IsPolytope.iff_homogenize_fg ℋ (dehomogenize_isConvexSet ℋ C)] simpa [homogenize_dehomogenize_of_le_positive hc] end Field diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean index c49cc73c..0c3b6ecd 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean @@ -5,8 +5,11 @@ Authors: Martin Winter, Olivia Röhrig -/ module -public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice +-- public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Pointwise +public import Polyhedral.Mathlib.Data.SetLike.IsConcrete +public import Polyhedral.Mathlib.Algebra.Group.Pointwise.SetLike.Basic +public import Polyhedral.Mathlib.Algebra.Group.Pointwise.SetLike.Scalar /-! This file defines polytopes as bundles objects. -/ @@ -52,8 +55,8 @@ variable (P) in @[simp] theorem mk_eq {s h} : (⟨s, h⟩ : Polytope R X) = s := by ext; simp -instance : Coe (Polytope R X) (ConvexSet R X) where - coe P := ⟨P, P.isPolytope.isConvexSet⟩ +-- instance : Coe (Polytope R X) (ConvexSet R X) where +-- coe P := ⟨P, P.isPolytope.isConvexSet⟩ /- # LE -/ @@ -162,7 +165,7 @@ instance : Neg (Polytope R X) where instance : IsConcreteNeg (Polytope R X) X := ⟨fun _ => rfl⟩ -instance : InvolutiveNeg (ConvexSet R X) := .ofSetLike .. +-- instance : InvolutiveNeg (ConvexSet R X) := .ofSetLike .. /-! ### Minkowski addition -/ diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Basic.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Basic.lean new file mode 100644 index 00000000..4f7f5062 --- /dev/null +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Basic.lean @@ -0,0 +1,187 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig, Mara Gruß, Valentina Taylor Cerra, Martin Winter +-/ +module + +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice + +/-! This file defines faces of convex sets. + +TODO: align this API with `IsFaceOf` for cones. +-/ + +@[expose] public section + +namespace Convexity + +open Function + +variable {R M M₁ M₂ : Type*} + +section Semiring + +variable [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] +variable [ConvexSpace R M] + +/- NOTE: this is a copy of mathlib convexity API adapted to `ConvexSpace`. -/ +variable (R) in +/-- Open segment in a convex space. Note that `openSegment 𝕜 x x = {x}` instead of being `∅` when +the base semiring has some element between `0` and `1`. -/ +def openSegment (x y : M) : Set M := + { z : M | ∃ (a b : R) (a0 : 0 < a) (b0 : 0 < b) (ab : a + b = 1), + convexCombPair a b a0.le b0.le ab x y = z } + +/- (x,y) = (y,x) -/ +theorem openSegment_symm (x y : M) : openSegment R x y = openSegment R y x := by + ext z + constructor + all_goals (intro h; rcases h with ⟨m, n, hm , hn , hmn , hz⟩; use n, m, hn, hm) + all_goals (rw [convexCombPair_symm] at hz; rw [add_comm] at hmn; use hmn) + +namespace ConvexSet + +/- NOTE: maybe this should be defined on `Set` instead of `ConvexSet`. -/ +/-- A subset `F` of a convex set `C` is a face of `C` iff it is an extreme subset. -/ +structure IsFaceOf (F C : ConvexSet R M) where + le : F ≤ C + left_mem_of_mem_openSegment : ∀ ⦃x⦄, x ∈ C → ∀ ⦃y⦄, y ∈ C → + ∀ ⦃z⦄, z ∈ F → z ∈ openSegment R x y → x ∈ F + +namespace IsFaceOf + +theorem empty {C : ConvexSet R M} : IsFaceOf ∅ C where + le := SetLike.empty_le _ + left_mem_of_mem_openSegment := by simp + +/- A convex set is a face of itself. -/ +theorem refl (C : ConvexSet R M) : C.IsFaceOf C := + ⟨by simp , by intro x hx y hy z hz h; apply hx⟩ + +/- The face relation is transitive. -/ +theorem trans {C F₁ F₂ : ConvexSet R M} (h₁ : F₂.IsFaceOf F₁) (h₂ : F₁.IsFaceOf C) : + F₂.IsFaceOf C := by + constructor + · apply Set.Subset.trans h₁.1 h₂.1 + · intro x hx y hy z hz hhz + have hz' : z ∈ F₁.carrier := Set.mem_of_mem_of_subset hz h₁.1 + exact @h₁.2 x (@h₂.2 x hx y hy z hz' hhz) y (@h₂.2 y hy x hx z hz' (by simpa [openSegment_symm] + using hhz)) z hz hhz + +/- For two faces `F₁, F₂` of `C`, `F₁` is a face of `F₂` iff it is a subset of `F₂`. -/ +theorem iff_le_of_isFaceOf {C F₁ F₂ : ConvexSet R M} (h₁ : F₁.IsFaceOf C) (h₂ : F₂.IsFaceOf C) : + F₁.IsFaceOf F₂ ↔ F₁.carrier ⊆ F₂.carrier := by + constructor + · exact fun h => h.1 + · intro hh + constructor + · exact hh + · intro x hx y hy z hz hhz + exact h₁.2 (Set.mem_of_mem_of_subset hx h₂.1) (Set.mem_of_mem_of_subset hy h₂.1) hz hhz + +/- A convex set is a face of a face iff it is contained in the face and it is a face +of the ambient set. -/ +lemma isFaceOf_iff {F C : ConvexSet R M} (F₁ : ConvexSet R M) (H : F.IsFaceOf C) : + F₁.IsFaceOf F ↔ F₁.carrier ⊆ F.carrier ∧ F₁.IsFaceOf C:= by + apply Iff.intro + · exact fun h => ⟨h.1, trans h H⟩ + · intro h + constructor + · apply h.1 + · intro x hx y hy z hz hhz + exact @h.2.2 x (Set.mem_of_mem_of_subset hx H.1) y (Set.mem_of_mem_of_subset hy H.1) z hz hhz + +/- The intersection of two faces of two convex sets is a face of the intersection of the convex +sets. -/ +theorem inf {S₁ S₂ F₁ F₂ : ConvexSet R M} (h₁ : F₁.IsFaceOf S₁) (h₂ : F₂.IsFaceOf S₂) : + (F₁ ⊓ F₂).IsFaceOf (S₁ ⊓ S₂) := by + constructor + · intro x hx + exact ⟨Set.mem_of_mem_of_subset hx.1 h₁.1, Set.mem_of_mem_of_subset hx.2 h₂.1⟩ + · intro a ha b hb z hz hhz + exact ⟨@h₁.2 a ha.1 b hb.1 z hz.1 hhz, @h₂.2 a ha.2 b hb.2 z hz.2 hhz⟩ + +/- The intersection of two faces is a face. -/ +theorem inf_left {C F₁ F₂ : ConvexSet R M} (h₁ : F₁.IsFaceOf C) (h₂ : F₂.IsFaceOf C) : + (F₁ ⊓ F₂).IsFaceOf C := by + constructor + · exact le_trans inf_le_left h₁.le + · intro x hx y hy z hz hhz + exact ⟨@h₁.2 x hx y hy z hz.1 hhz, @h₂.2 x hx y hy z hz.2 hhz⟩ + +/- The face of two convex sets is a face of the intersection. -/ +theorem inf_right {S₁ S₂ F : ConvexSet R M} (h₁ : F.IsFaceOf S₁) (h₂ : F.IsFaceOf S₂) : + F.IsFaceOf (S₁ ⊓ S₂) := + ⟨Set.subset_inter h₁.1 h₂.1, by intro x hx y hy z hz hhz; exact @h₁.2 x hx.1 y hy.1 z hz hhz⟩ + +variable [ConvexSpace R M₁] +variable [ConvexSpace R M₂] + +/- The image of a face under an injective affine map is a face of the image. -/ +theorem map {f : M₁ → M₂} {F C : ConvexSet R M₁} (hhf : IsAffineMap R f) (hf : Injective f) + (hF : F.IsFaceOf C) : (F.map hhf).IsFaceOf (C.map hhf) := by + constructor + · intro x hx + rcases hx with ⟨y , hy, rfl⟩ + exact Set.mem_image_of_mem _ (Set.mem_of_mem_of_subset hy hF.1) + · intro x hx y hy z hz hhz + rcases hx with ⟨m , hmC, rfl⟩ + rcases hy with ⟨n , hnC, rfl⟩ + rcases hz with ⟨l , hlF, rfl⟩ + have hl : l ∈ Convexity.openSegment R m n := by + rcases hhz with ⟨ a, b, ha, hb, hab, hcomb⟩ + have h : f (convexCombPair a b ha.le hb.le hab m n) = + convexCombPair a b ha.le hb.le hab (f m) (f n) := hhf.map_convexCombPair ha.le hb.le hab m n + have hh : f (convexCombPair a b ha.le hb.le hab m n) = f l := by + simpa [h] using hcomb + exact ⟨ a, b, ha, hb, hab, hf hh⟩ + exact Set.mem_image_of_mem _ (@hF.2 m hmC n hnC l hlF hl) + +/- The preimage of a face is a face of the preimage. -/ +theorem comap_face {f : M₁ → M₂} {F C : ConvexSet R M₂} (hf : IsAffineMap R f) (hF : F.IsFaceOf C) : + (F.comap hf).IsFaceOf (C.comap hf) := by + constructor + · apply Set.preimage_mono hF.1 + · have hF1 := hF.2 + intro x hx y hy z hz hhz + have hhz' : f z ∈ Convexity.openSegment R (f x) (f y) := by + rcases hhz with ⟨ a, b, ha, hb, hab, hcomb⟩ + have hff : f (convexCombPair a b ha.le hb.le hab x y) = + convexCombPair a b ha.le hb.le hab (f x) (f y) := hf.map_convexCombPair ha.le hb.le hab x y + rw [hcomb] at hff + use a, b, ha, hb, hab, hff.symm + specialize @hF1 (f x) (Set.mem_preimage.mp hx ) (f y) (Set.mem_preimage.mp hy) (f z) ( + Set.mem_preimage.mp hz) hhz' + apply Set.mem_preimage.mp hF1 + +/- `F` is a face of `C` iff the image of `F` is a face of the image of `C` under an injective affine +map -/ +theorem isFaceOf_map_iff {f : M₁ → M₂} {F C : ConvexSet R M₁} (hhf : IsAffineMap R f) + (hf : Injective f) : (F.map hhf).IsFaceOf (C.map hhf) ↔ F.IsFaceOf C := by + constructor + · intro h + have hh := comap_face hhf h + have h (A : ConvexSet R M₁) : (A.map hhf).comap hhf = A := by + ext z + constructor + · intro hz + rcases hz with ⟨y, hy, hzy⟩ + rw [hf hzy] at hy + use hy + · intro hz + have hhz : f z ∈ (A.map hhf) := by + use z, hz + apply Set.mem_preimage.mp hhz + rw [h F, h C] at hh + exact hh + · intro h + apply map hhf hf h + +end IsFaceOf + +end ConvexSet + +end Semiring + +end Convexity diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Homogenization.lean new file mode 100644 index 00000000..77cff520 --- /dev/null +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Homogenization.lean @@ -0,0 +1,128 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Martin Winter, Olivia Röhrig +-/ +module + +public import Mathlib.Geometry.Convex.Cone.Face.Lattice +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Lattice +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Homogenization + +/-! This files proves results about faces of convex sets / cones and homogenization. -/ + +@[expose] public section + +namespace Affine.IsHomogenization + +open Set Convexity ConvexSet Submodule + +variable {R V A W : Type*} + +section Field + +variable [Field R] [LinearOrder R] [IsOrderedRing R] +variable [AddCommGroup V] [Module R V] +variable [AddCommGroup W] [Module R W] [ConvexSpace R W] +variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] + +variable [IsModuleConvexSpace R W] + +variable [hom : Affine.IsHomogenization R A W] + +/-- If the homogenization of a point `q` is a positive combination of the homogenization +of two other points, then `q` lies in the open segment between them. -/ +theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} + (h₁ : 0 < r₁) (h₂ : 0 < r₂) (hₜ : 0 < t) + (h : r₁ • hom.ofPoint p₁ + r₂ • hom.ofPoint p₂ = t • hom.ofPoint q) : + q ∈ Convexity.openSegment R p₁ p₂ := by + have : r₁ + r₂ = t := by simpa [hom.weight_one, map_add, map_smul] using congr_arg hom.weight h + have : t⁻¹ • r₁ + t⁻¹ • r₂ = 1 := by + simp_rw [← smul_add, smul_eq_mul, this, mul_comm, Field.mul_inv_cancel _ hₜ.ne.symm] + use (t⁻¹ • r₁), (t⁻¹ • r₂), (smul_pos (by positivity) h₁), (smul_pos (by positivity) h₂), this + apply hom.ofPoint_injective + have : t⁻¹ • (r₁ • hom.ofPoint p₁ + r₂ • hom.ofPoint p₂) = hom.ofPoint q := by + rw [h, smul_smul, inv_mul_cancel₀ (ne_of_gt hₜ), one_smul] + simp [hom.ofPoint.isAffineMap.map_convexCombPair, convexCombPair_eq_sum, ← this, smul_smul] + +/-- If `F` is a face of `P`, then the homogenization of `F` is a face of the homogenization +of `P`. -/ +theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : + (F.homogenize W).IsFaceOf (P.homogenize W) where + le := homogenizeOrderHom.monotone' he.le + mem_of_smul_add_mem := by + intro v w a hv hw ha hvw + have hhom : (P.homogenize W).Salient := homogenize_salient + by_cases hnf : (F : Set A).Nonempty + · have cF := F.isConvexSet.image hom.ofPoint.isAffineMap + apply (Set.ext_iff.mp (PointedCone.hull_eq_smul (hnf.image _) cF) _).mpr + by_cases hv0 : v = 0 + · exact ⟨0, le_rfl, mem_smul_set.mpr (by simpa [hv0] using nonempty_def.mp hnf)⟩ + · by_cases hw0 : w = 0 + · subst hw0 + obtain ⟨r, hr, r', ⟨w, hw, _⟩, hra⟩ := + smul_pos_of_mem_homogenize hvw (by simpa using smul_ne_zero ha.ne.symm hv0) + simp only [add_zero] at ⊢ hra + use a⁻¹ • r, (smul_pos (inv_pos.mpr ha) hr).le, r' + constructor + · use w, hw + simp only + rw [smul_assoc, hra, ← smul_assoc, smul_eq_mul, inv_mul_cancel₀ ha.ne.symm, one_smul] + · obtain ⟨rw, rw0, q, ⟨q', qq, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hw hw0 + obtain ⟨rv, rv0, _, ⟨p', pp, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hv hv0 + have : a • (rv • hom.ofPoint p') + (rw • hom.ofPoint q') ≠ 0 := by + intro hc + exact (smul_ne_zero rw0.ne.symm (ofPoint_ne_zero q')) <| + hhom _ hw _ (PointedCone.smul_mem _ ha.le hv) (by simpa [add_comm] using hc) + obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := smul_pos_of_mem_homogenize hvw this + have := he.left_mem_of_mem_openSegment pp qq qqp ?_ + · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem ofPoint this⟩ + rw [← smul_assoc _ rv] at pdp + exact pos_combo_openSegment (smul_pos ha rv0) rw0 rvw0 pdp.symm + · have := not_nonempty_iff_eq_empty.mp hnf + simp_all only [homogenize, SetLike.coe, image_empty, span_empty, mem_bot] + by_contra hxx + have : -v = a⁻¹ • w := by + simp [← neg_eq_of_add_eq_zero_right hvw, smul_neg, smul_smul, inv_mul_cancel₀ (ne_of_gt ha)] + apply hxx + exact hhom v hv (-v) (by + rw [this] + exact PointedCone.smul_mem _ (by positivity) hw) (add_neg_cancel v) + +variable (A) in +/-- If `F` is a face of `C`, then the dehomogenization of `F` is a face of the dehomogenization +of `C`. -/ +theorem dehomogenize_isFaceOf {F C : PointedCone R W} (hf : F.IsFaceOf C) : + (ConvexSet.dehomogenize A F).IsFaceOf (ConvexSet.dehomogenize A C) where + le := preimage_mono (fun _ x ↦ hf.le x) + left_mem_of_mem_openSegment := by + rintro x hx y hy z hz ⟨a, b, ha, hb, hab, hzo⟩ + refine hf.mem_of_smul_add_mem hx (C.smul_mem hb.le hy) ha ?_ + rwa [← convexCombPair_eq_sum _ _ ha.le hb.le hab, + ← hom.ofPoint.isAffineMap.map_convexCombPair, hzo] + +/-- The isomorphism between the face lattice of a convex set `P` and the face lattice of +its homogenization cone. + +This isomorphism is used to translate results between face lattices of cones and face lattices +of convex sets. +-/ +def Face.homogenizeIso {P : ConvexSet R A} : + Face P ≃o PointedCone.Face (P.homogenize W) where + toFun F := ⟨_, hom.homogenize_isFaceOf F.isFaceOf⟩ + invFun F := ⟨dehomogenize A F.toSubmodule, + by simpa [dehomogenize_homogenize] using dehomogenize_isFaceOf A F.isFaceOf⟩ + map_rel_iff' := by + intro a b + refine ⟨fun h x xm ↦ ?_, fun h _ xm ↦ span_mono (image_mono h) xm⟩ + refine (ofPoint_mem_homogenize_iff_mem W x b.toConvexSet).mp (h ?_) + exact (ofPoint_mem_homogenize_iff_mem W x a.toConvexSet).mpr xm + left_inv _ := by simp [dehomogenize_homogenize] + right_inv F := by + have := homogenize_dehomogenize_of_le_positive + (fun _ h n ↦ weight_pos_of_mem_homogenize (F.isFaceOf.le h) n) + simp [this] + +end Field + +end Affine.IsHomogenization diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Lattice.lean new file mode 100644 index 00000000..5b3d6acc --- /dev/null +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/BundledFace/Lattice.lean @@ -0,0 +1,142 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig, Mara Gruß, Valentina Taylor Cerra, Martin Winter +-/ +module + +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Basic + +import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice + +/-! This file defines faces of convex sets. + +TODO: align this API with `Face` for cones. +-/ + +public section + +variable {R M : Type*} + +namespace Convexity + +section Semiring + +variable [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] +variable [ConvexSpace R M] + +namespace ConvexSet + +/- NOTE: maybe this should be defined on `Set` instead of `ConvexSet`. -/ +/-- A face of a convex set `P`. Represents the face lattice of `P`. -/ +structure Face (P : ConvexSet R M) extends toConvexSet : ConvexSet R M where + isFaceOf : IsFaceOf toConvexSet P + +attribute [coe] Face.toConvexSet + +namespace Face + +variable {P : ConvexSet R M} + +instance : SetLike (Face P) M where + coe F := F.toConvexSet.carrier + coe_injective a b h := by + cases a; cases b; congr; exact SetLike.coe_injective h + +instance : CoeOut (Face P) (ConvexSet R M) := ⟨toConvexSet⟩ + +@[simp] theorem carrier_eq_coe {F : Face P} : F.carrier = F := by rfl + +@[simp] theorem mem_coe {F : Face P} (x : M) : x ∈ F.carrier ↔ x ∈ F := .rfl + +@[ext] theorem ext {F₁ F₂ : Face P} (h : ∀ x, x ∈ F₁ ↔ x ∈ F₂) : F₁ = F₂ := SetLike.ext h + +@[simp] theorem coe_eq_toConvexSet_coe {F : Face P} : (F : Set M) = F.toConvexSet := + SetLike.ext'_iff.mp rfl + +@[simp] theorem mem_mk {s h x} : x ∈ (⟨s, h⟩ : Face P) ↔ x ∈ s := .rfl + +@[simp] theorem mk_eq {s h} : (⟨s, h⟩ : Face P) = s := by ext; simp + +instance : PartialOrder (Face P) := .ofSetLike .. + +instance : OrderBot (Face P) where + bot := ⟨∅, IsFaceOf.empty⟩ + bot_le _ _ := by simp + +lemma nonempty_of_ne_bot {F : Face P} (h : F ≠ ⊥) : (F : Set M).Nonempty := by + rw [Set.nonempty_iff_ne_empty] + intro heq + apply h + ext + simp [← SetLike.mem_coe, heq, Bot.bot] + +instance : OrderTop (Face P) where + top := ⟨P, IsFaceOf.refl P⟩ + le_top F := F.isFaceOf.le + +instance : Inhabited (Face P) := ⟨⊤⟩ + +theorem toConvexSet_le {F : Face P} : F ≤ P := F.isFaceOf.le + +@[simp] +theorem toConvexSet_le_toConvexSet {F₁ F₂ : Face P} : + F₁.toConvexSet ≤ F₂.toConvexSet ↔ F₁ ≤ F₂ := .rfl + +@[simp] +theorem toConvexSet_lt_toConvexSet {F₁ F₂ : Face P} : + F₁.toConvexSet < F₂.toConvexSet ↔ F₁ < F₂ := .rfl + +@[simp] +theorem mem_toConvexSet {F : Face P} (x : M) : x ∈ F.toConvexSet ↔ x ∈ F := .rfl + +@[simp] theorem toConvexSet_bot : ((⊥ : Face P) : ConvexSet R M) = ∅ := rfl + +@[simp] theorem toConvexSet_top : ((⊤ : Face P) : ConvexSet R M) = P := rfl + +/-! ### Infimum, supremum and lattice -/ + +/-- The infimum of two faces `F₁`, `F₂` of `C` is the intersection of the cones `F₁` and `F₂`. -/ +instance : Min (Face P) where + min F₁ F₂ := ⟨F₁ ⊓ F₂, F₁.isFaceOf.inf_left F₂.isFaceOf⟩ + +protected theorem IsFaceOf.sInf (F : Set (ConvexSet R M)) (h : ∀ f ∈ F, f.IsFaceOf P) : + (P ⊓ sInf F).IsFaceOf P where + le _ sm := sm.1 + left_mem_of_mem_openSegment := by + simp only [SetLike.mem_min, SetLike.mem_sInf, and_imp] + intro x hx y hy z hz h₁ h₂ + simpa [hx] using fun F Fs ↦ (h F Fs).left_mem_of_mem_openSegment hx hy (by grind) h₂ + +instance : InfSet (Face P) where + sInf S := + { toConvexSet := P ⊓ sInf {s.1 | s ∈ S} + isFaceOf := IsFaceOf.sInf _ (fun _ ⟨s, _, hs2⟩ ↦ hs2 ▸ s.isFaceOf) } + +instance : SemilatticeInf (Face P) where + inf := min + inf_le_left _ _ _ xi := xi.1 + inf_le_right _ _ _ xi := xi.2 + le_inf _ _ _ h₁₂ h₂₃ _ xi := ⟨h₁₂ xi, h₂₃ xi⟩ + +instance : CompleteSemilatticeInf (Face P) where + __ := instSemilatticeInf + isGLB_sInf S := by + constructor <;> intro f fS + · rw [← toConvexSet_le_toConvexSet] + refine inf_le_of_right_le ?_ + simpa [LE.le] using fun _ xs ↦ xs f fS + · simp only [sInf, Set.sInter_image, Set.mem_ofPred_eq, + Set.iInter_exists, Set.biInter_and', Set.iInter_iInter_eq_right] + simpa [LE.le] using fun x a ↦ ⟨f.2.1 a, fun i hi ↦ (mem_coe x).mp (fS hi a)⟩ + +instance : CompleteLattice (Face P) where + top := ⟨P, .refl _⟩ + le_top _ := toConvexSet_le + __ := completeLatticeOfCompleteSemilatticeInf _ + +end ConvexSet.Face + +end Semiring + +end Convexity diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean index 4f7f5062..e152e527 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean @@ -5,7 +5,7 @@ Authors: Olivia Röhrig, Mara Gruß, Valentina Taylor Cerra, Martin Winter -/ module -public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice +public import Mathlib.Geometry.Convex.ConvexSpace.Defs /-! This file defines faces of convex sets. @@ -40,147 +40,125 @@ theorem openSegment_symm (x y : M) : openSegment R x y = openSegment R y x := by all_goals (intro h; rcases h with ⟨m, n, hm , hn , hmn , hz⟩; use n, m, hn, hm) all_goals (rw [convexCombPair_symm] at hz; rw [add_comm] at hmn; use hmn) -namespace ConvexSet - -/- NOTE: maybe this should be defined on `Set` instead of `ConvexSet`. -/ -/-- A subset `F` of a convex set `C` is a face of `C` iff it is an extreme subset. -/ -structure IsFaceOf (F C : ConvexSet R M) where - le : F ≤ C - left_mem_of_mem_openSegment : ∀ ⦃x⦄, x ∈ C → ∀ ⦃y⦄, y ∈ C → - ∀ ⦃z⦄, z ∈ F → z ∈ openSegment R x y → x ∈ F +variable (R) in +/-- A subset `f` of a set `c` is a face of `c` iff it is an extreme subset. -/ +structure IsFaceOf (f c : Set M) : Prop where + le : f ⊆ c + left_mem_of_mem_openSegment : ∀ ⦃x⦄, x ∈ c → ∀ ⦃y⦄, y ∈ c → + ∀ ⦃z⦄, z ∈ f → z ∈ openSegment R x y → x ∈ f namespace IsFaceOf -theorem empty {C : ConvexSet R M} : IsFaceOf ∅ C where - le := SetLike.empty_le _ +variable {c f c₁ c₂ f₁ f₂ : Set M} + +theorem empty : IsFaceOf R (∅ : Set M) c where + le := Set.empty_subset c left_mem_of_mem_openSegment := by simp -/- A convex set is a face of itself. -/ -theorem refl (C : ConvexSet R M) : C.IsFaceOf C := - ⟨by simp , by intro x hx y hy z hz h; apply hx⟩ +/- A set is a face of itself. -/ +theorem refl : IsFaceOf R c c := + ⟨subset_rfl, fun _ hx _ _ _ _ _ ↦ hx⟩ /- The face relation is transitive. -/ -theorem trans {C F₁ F₂ : ConvexSet R M} (h₁ : F₂.IsFaceOf F₁) (h₂ : F₁.IsFaceOf C) : - F₂.IsFaceOf C := by - constructor - · apply Set.Subset.trans h₁.1 h₂.1 - · intro x hx y hy z hz hhz - have hz' : z ∈ F₁.carrier := Set.mem_of_mem_of_subset hz h₁.1 - exact @h₁.2 x (@h₂.2 x hx y hy z hz' hhz) y (@h₂.2 y hy x hx z hz' (by simpa [openSegment_symm] - using hhz)) z hz hhz - -/- For two faces `F₁, F₂` of `C`, `F₁` is a face of `F₂` iff it is a subset of `F₂`. -/ -theorem iff_le_of_isFaceOf {C F₁ F₂ : ConvexSet R M} (h₁ : F₁.IsFaceOf C) (h₂ : F₂.IsFaceOf C) : - F₁.IsFaceOf F₂ ↔ F₁.carrier ⊆ F₂.carrier := by +theorem trans (h₁ : IsFaceOf R f₂ f₁) (h₂ : IsFaceOf R f₁ c) : IsFaceOf R f₂ c := by + refine ⟨h₁.le.trans h₂.le, ?_⟩ + intro x hx y hy z hz hhz + have hz' : z ∈ f₁ := h₁.le hz + exact h₁.2 (h₂.2 hx hy hz' hhz) (h₂.2 hy hx hz' (by simpa [openSegment_symm] using hhz)) hz hhz + +/- For two faces `f₁, f₂` of `c`, `f₁` is a face of `f₂` iff it is a subset of `f₂`. -/ +theorem iff_le_of_isFaceOf (h₁ : IsFaceOf R f₁ c) (h₂ : IsFaceOf R f₂ c) : + IsFaceOf R f₁ f₂ ↔ f₁ ⊆ f₂ := by constructor - · exact fun h => h.1 + · exact fun h ↦ h.1 · intro hh - constructor - · exact hh - · intro x hx y hy z hz hhz - exact h₁.2 (Set.mem_of_mem_of_subset hx h₂.1) (Set.mem_of_mem_of_subset hy h₂.1) hz hhz + refine ⟨hh, ?_⟩ + intro x hx y hy z hz hhz + exact h₁.2 (h₂.le hx) (h₂.le hy) hz hhz -/- A convex set is a face of a face iff it is contained in the face and it is a face +/- A set is a face of a face iff it is contained in the face and it is a face of the ambient set. -/ -lemma isFaceOf_iff {F C : ConvexSet R M} (F₁ : ConvexSet R M) (H : F.IsFaceOf C) : - F₁.IsFaceOf F ↔ F₁.carrier ⊆ F.carrier ∧ F₁.IsFaceOf C:= by - apply Iff.intro - · exact fun h => ⟨h.1, trans h H⟩ - · intro h - constructor - · apply h.1 - · intro x hx y hy z hz hhz - exact @h.2.2 x (Set.mem_of_mem_of_subset hx H.1) y (Set.mem_of_mem_of_subset hy H.1) z hz hhz - -/- The intersection of two faces of two convex sets is a face of the intersection of the convex -sets. -/ -theorem inf {S₁ S₂ F₁ F₂ : ConvexSet R M} (h₁ : F₁.IsFaceOf S₁) (h₂ : F₂.IsFaceOf S₂) : - (F₁ ⊓ F₂).IsFaceOf (S₁ ⊓ S₂) := by - constructor - · intro x hx - exact ⟨Set.mem_of_mem_of_subset hx.1 h₁.1, Set.mem_of_mem_of_subset hx.2 h₂.1⟩ - · intro a ha b hb z hz hhz - exact ⟨@h₁.2 a ha.1 b hb.1 z hz.1 hhz, @h₂.2 a ha.2 b hb.2 z hz.2 hhz⟩ +lemma isFaceOf_iff (H : IsFaceOf R f c) : + IsFaceOf R f₁ f ↔ f₁ ⊆ f ∧ IsFaceOf R f₁ c := by + refine ⟨fun h ↦ ⟨h.1, trans h H⟩, fun h ↦ ⟨h.1, ?_⟩⟩ + intro x hx y hy z hz hhz + exact h.2.2 (H.le hx) (H.le hy) hz hhz + +/- The intersection of two faces of two sets is a face of the intersection of the sets. -/ +theorem inf (h₁ : IsFaceOf R f₁ c₁) (h₂ : IsFaceOf R f₂ c₂) : + IsFaceOf R (f₁ ∩ f₂) (c₁ ∩ c₂) := by + refine ⟨fun x hx ↦ ⟨h₁.le hx.1, h₂.le hx.2⟩, ?_⟩ + intro a ha b hb z hz hhz + exact ⟨h₁.2 ha.1 hb.1 hz.1 hhz, h₂.2 ha.2 hb.2 hz.2 hhz⟩ /- The intersection of two faces is a face. -/ -theorem inf_left {C F₁ F₂ : ConvexSet R M} (h₁ : F₁.IsFaceOf C) (h₂ : F₂.IsFaceOf C) : - (F₁ ⊓ F₂).IsFaceOf C := by - constructor - · exact le_trans inf_le_left h₁.le - · intro x hx y hy z hz hhz - exact ⟨@h₁.2 x hx y hy z hz.1 hhz, @h₂.2 x hx y hy z hz.2 hhz⟩ +theorem inf_left (h₁ : IsFaceOf R f₁ c) (h₂ : IsFaceOf R f₂ c) : IsFaceOf R (f₁ ∩ f₂) c := by + refine ⟨fun x hx ↦ h₁.le hx.1, ?_⟩ + intro x hx y hy z hz hhz + exact ⟨h₁.2 hx hy hz.1 hhz, h₂.2 hx hy hz.2 hhz⟩ + +/- A face of two sets is a face of the intersection. -/ +theorem inf_right (h₁ : IsFaceOf R f c₁) (h₂ : IsFaceOf R f c₂) : IsFaceOf R f (c₁ ∩ c₂) := + ⟨Set.subset_inter h₁.1 h₂.1, fun _ hx _ hy _ hz hhz ↦ h₁.2 hx.1 hy.1 hz hhz⟩ -/- The face of two convex sets is a face of the intersection. -/ -theorem inf_right {S₁ S₂ F : ConvexSet R M} (h₁ : F.IsFaceOf S₁) (h₂ : F.IsFaceOf S₂) : - F.IsFaceOf (S₁ ⊓ S₂) := - ⟨Set.subset_inter h₁.1 h₂.1, by intro x hx y hy z hz hhz; exact @h₁.2 x hx.1 y hy.1 z hz hhz⟩ +/-- The intersection of a set `c` with any family of faces of `c` is a face of `c`. -/ +theorem sInf {c : Set M} {Fs : Set (Set M)} (h : ∀ f ∈ Fs, IsFaceOf R f c) : + IsFaceOf R (c ∩ ⋂₀ Fs) c where + le _ sm := sm.1 + left_mem_of_mem_openSegment := by + intro x hx y hy z hz hxyz + refine ⟨hx, fun F hF => ?_⟩ + exact (h F hF).left_mem_of_mem_openSegment hx hy (hz.2 F hF) hxyz -variable [ConvexSpace R M₁] -variable [ConvexSpace R M₂] +section map + +variable [ConvexSpace R M₁] [ConvexSpace R M₂] +variable {c₁ f₁ : Set M₁} {c₂ f₂ : Set M₂} /- The image of a face under an injective affine map is a face of the image. -/ -theorem map {f : M₁ → M₂} {F C : ConvexSet R M₁} (hhf : IsAffineMap R f) (hf : Injective f) - (hF : F.IsFaceOf C) : (F.map hhf).IsFaceOf (C.map hhf) := by - constructor - · intro x hx - rcases hx with ⟨y , hy, rfl⟩ - exact Set.mem_image_of_mem _ (Set.mem_of_mem_of_subset hy hF.1) - · intro x hx y hy z hz hhz - rcases hx with ⟨m , hmC, rfl⟩ - rcases hy with ⟨n , hnC, rfl⟩ - rcases hz with ⟨l , hlF, rfl⟩ - have hl : l ∈ Convexity.openSegment R m n := by - rcases hhz with ⟨ a, b, ha, hb, hab, hcomb⟩ - have h : f (convexCombPair a b ha.le hb.le hab m n) = - convexCombPair a b ha.le hb.le hab (f m) (f n) := hhf.map_convexCombPair ha.le hb.le hab m n - have hh : f (convexCombPair a b ha.le hb.le hab m n) = f l := by - simpa [h] using hcomb - exact ⟨ a, b, ha, hb, hab, hf hh⟩ - exact Set.mem_image_of_mem _ (@hF.2 m hmC n hnC l hlF hl) +theorem map {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) + (hF : IsFaceOf R f₁ c₁) : IsFaceOf R (φ '' f₁) (φ '' c₁) := by + refine ⟨fun x ⟨y, hy, hyx⟩ ↦ ⟨y, hF.le hy, hyx⟩, ?_⟩ + intro x hx y hy z hz hhz + rcases hx with ⟨m, hmC, rfl⟩ + rcases hy with ⟨n, hnC, rfl⟩ + rcases hz with ⟨l, hlF, rfl⟩ + have hl : l ∈ openSegment R m n := by + rcases hhz with ⟨a, b, ha, hb, hab, hcomb⟩ + have h : φ (convexCombPair a b ha.le hb.le hab m n) = + convexCombPair a b ha.le hb.le hab (φ m) (φ n) := + hφ.map_convexCombPair ha.le hb.le hab m n + have hh : φ (convexCombPair a b ha.le hb.le hab m n) = φ l := by + simpa [h] using hcomb + exact ⟨a, b, ha, hb, hab, hinj hh⟩ + exact Set.mem_image_of_mem _ (hF.2 hmC hnC hlF hl) /- The preimage of a face is a face of the preimage. -/ -theorem comap_face {f : M₁ → M₂} {F C : ConvexSet R M₂} (hf : IsAffineMap R f) (hF : F.IsFaceOf C) : - (F.comap hf).IsFaceOf (C.comap hf) := by - constructor - · apply Set.preimage_mono hF.1 - · have hF1 := hF.2 - intro x hx y hy z hz hhz - have hhz' : f z ∈ Convexity.openSegment R (f x) (f y) := by - rcases hhz with ⟨ a, b, ha, hb, hab, hcomb⟩ - have hff : f (convexCombPair a b ha.le hb.le hab x y) = - convexCombPair a b ha.le hb.le hab (f x) (f y) := hf.map_convexCombPair ha.le hb.le hab x y - rw [hcomb] at hff - use a, b, ha, hb, hab, hff.symm - specialize @hF1 (f x) (Set.mem_preimage.mp hx ) (f y) (Set.mem_preimage.mp hy) (f z) ( - Set.mem_preimage.mp hz) hhz' - apply Set.mem_preimage.mp hF1 +theorem comap_face {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hF : IsFaceOf R f₂ c₂) : + IsFaceOf R (φ ⁻¹' f₂) (φ ⁻¹' c₂) := by + refine ⟨Set.preimage_mono hF.1, ?_⟩ + intro x hx y hy z hz hhz + have hhz' : φ z ∈ openSegment R (φ x) (φ y) := by + rcases hhz with ⟨a, b, ha, hb, hab, hcomb⟩ + have hff : φ (convexCombPair a b ha.le hb.le hab x y) = + convexCombPair a b ha.le hb.le hab (φ x) (φ y) := + hφ.map_convexCombPair ha.le hb.le hab x y + rw [hcomb] at hff + exact ⟨a, b, ha, hb, hab, hff.symm⟩ + exact hF.2 hx hy hz hhz' /- `F` is a face of `C` iff the image of `F` is a face of the image of `C` under an injective affine map -/ -theorem isFaceOf_map_iff {f : M₁ → M₂} {F C : ConvexSet R M₁} (hhf : IsAffineMap R f) - (hf : Injective f) : (F.map hhf).IsFaceOf (C.map hhf) ↔ F.IsFaceOf C := by - constructor - · intro h - have hh := comap_face hhf h - have h (A : ConvexSet R M₁) : (A.map hhf).comap hhf = A := by - ext z - constructor - · intro hz - rcases hz with ⟨y, hy, hzy⟩ - rw [hf hzy] at hy - use hy - · intro hz - have hhz : f z ∈ (A.map hhf) := by - use z, hz - apply Set.mem_preimage.mp hhz - rw [h F, h C] at hh - exact hh - · intro h - apply map hhf hf h +theorem isFaceOf_map_iff {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) : + IsFaceOf R (φ '' f₁) (φ '' c₁) ↔ IsFaceOf R f₁ c₁ := by + refine ⟨fun h ↦ ?_, map hφ hinj⟩ + have h' := comap_face hφ h + rwa [Set.preimage_image_eq _ hinj, Set.preimage_image_eq _ hinj] at h' -end IsFaceOf -end ConvexSet +end map + +end IsFaceOf end Semiring diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean index 77cff520..b57e1b72 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean @@ -15,7 +15,7 @@ public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Homogenization namespace Affine.IsHomogenization -open Set Convexity ConvexSet Submodule +open Set Convexity IsConvexSet Submodule variable {R V A W : Type*} @@ -28,59 +28,60 @@ variable [AddTorsor V A] [ConvexSpace R A] [IsAffineConvexSpace R V A] variable [IsModuleConvexSpace R W] -variable [hom : Affine.IsHomogenization R A W] +variable (ℋ : Affine.IsHomogenization R A W) +variable {ℋ} in /-- If the homogenization of a point `q` is a positive combination of the homogenization of two other points, then `q` lies in the open segment between them. -/ theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} (h₁ : 0 < r₁) (h₂ : 0 < r₂) (hₜ : 0 < t) - (h : r₁ • hom.ofPoint p₁ + r₂ • hom.ofPoint p₂ = t • hom.ofPoint q) : + (h : r₁ • ℋ.ofPoint p₁ + r₂ • ℋ.ofPoint p₂ = t • ℋ.ofPoint q) : q ∈ Convexity.openSegment R p₁ p₂ := by - have : r₁ + r₂ = t := by simpa [hom.weight_one, map_add, map_smul] using congr_arg hom.weight h + have : r₁ + r₂ = t := by simpa [ℋ.weight_ofPoint, map_add, map_smul] using congr_arg ℋ.weight h have : t⁻¹ • r₁ + t⁻¹ • r₂ = 1 := by simp_rw [← smul_add, smul_eq_mul, this, mul_comm, Field.mul_inv_cancel _ hₜ.ne.symm] use (t⁻¹ • r₁), (t⁻¹ • r₂), (smul_pos (by positivity) h₁), (smul_pos (by positivity) h₂), this - apply hom.ofPoint_injective - have : t⁻¹ • (r₁ • hom.ofPoint p₁ + r₂ • hom.ofPoint p₂) = hom.ofPoint q := by + apply ℋ.ofPoint_injective + have : t⁻¹ • (r₁ • ℋ.ofPoint p₁ + r₂ • ℋ.ofPoint p₂) = ℋ.ofPoint q := by rw [h, smul_smul, inv_mul_cancel₀ (ne_of_gt hₜ), one_smul] - simp [hom.ofPoint.isAffineMap.map_convexCombPair, convexCombPair_eq_sum, ← this, smul_smul] + simp [ℋ.ofPoint.isAffineMap.map_convexCombPair, convexCombPair_eq_sum, ← this, smul_smul] /-- If `F` is a face of `P`, then the homogenization of `F` is a face of the homogenization of `P`. -/ -theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : - (F.homogenize W).IsFaceOf (P.homogenize W) where - le := homogenizeOrderHom.monotone' he.le +theorem homogenize_isFaceOf {F P : Set A} (hF : IsConvexSet R F) (hP : IsConvexSet R P) + (he : IsFaceOf R F P) : (homogenize ℋ F).IsFaceOf (homogenize ℋ P) where + le := (homogenizeOrderHom ℋ).monotone' he.le mem_of_smul_add_mem := by intro v w a hv hw ha hvw - have hhom : (P.homogenize W).Salient := homogenize_salient + have hhom := homogenize_salient ℋ P by_cases hnf : (F : Set A).Nonempty - · have cF := F.isConvexSet.image hom.ofPoint.isAffineMap + · have cF := hF.image ℋ.ofPoint.isAffineMap apply (Set.ext_iff.mp (PointedCone.hull_eq_smul (hnf.image _) cF) _).mpr by_cases hv0 : v = 0 · exact ⟨0, le_rfl, mem_smul_set.mpr (by simpa [hv0] using nonempty_def.mp hnf)⟩ · by_cases hw0 : w = 0 · subst hw0 obtain ⟨r, hr, r', ⟨w, hw, _⟩, hra⟩ := - smul_pos_of_mem_homogenize hvw (by simpa using smul_ne_zero ha.ne.symm hv0) + smul_pos_of_mem_homogenize hF hvw (by simpa using smul_ne_zero ha.ne.symm hv0) simp only [add_zero] at ⊢ hra use a⁻¹ • r, (smul_pos (inv_pos.mpr ha) hr).le, r' constructor · use w, hw simp only rw [smul_assoc, hra, ← smul_assoc, smul_eq_mul, inv_mul_cancel₀ ha.ne.symm, one_smul] - · obtain ⟨rw, rw0, q, ⟨q', qq, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hw hw0 - obtain ⟨rv, rv0, _, ⟨p', pp, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hv hv0 - have : a • (rv • hom.ofPoint p') + (rw • hom.ofPoint q') ≠ 0 := by + · obtain ⟨rw, rw0, q, ⟨q', qq, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hP hw hw0 + obtain ⟨rv, rv0, _, ⟨p', pp, rfl⟩, _, _⟩ := smul_pos_of_mem_homogenize hP hv hv0 + have : a • (rv • ℋ.ofPoint p') + (rw • ℋ.ofPoint q') ≠ 0 := by intro hc - exact (smul_ne_zero rw0.ne.symm (ofPoint_ne_zero q')) <| + exact (smul_ne_zero rw0.ne.symm (ℋ.ofPoint_ne_zero q')) <| hhom _ hw _ (PointedCone.smul_mem _ ha.le hv) (by simpa [add_comm] using hc) - obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := smul_pos_of_mem_homogenize hvw this + obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := smul_pos_of_mem_homogenize hF hvw this have := he.left_mem_of_mem_openSegment pp qq qqp ?_ - · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem ofPoint this⟩ + · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem ℋ.ofPoint this⟩ rw [← smul_assoc _ rv] at pdp exact pos_combo_openSegment (smul_pos ha rv0) rw0 rvw0 pdp.symm · have := not_nonempty_iff_eq_empty.mp hnf - simp_all only [homogenize, SetLike.coe, image_empty, span_empty, mem_bot] + simp_all only [homogenize, image_empty, span_empty, mem_bot] by_contra hxx have : -v = a⁻¹ • w := by simp [← neg_eq_of_add_eq_zero_right hvw, smul_neg, smul_smul, inv_mul_cancel₀ (ne_of_gt ha)] @@ -89,17 +90,16 @@ theorem homogenize_isFaceOf {F P : ConvexSet R A} (he : F.IsFaceOf P) : rw [this] exact PointedCone.smul_mem _ (by positivity) hw) (add_neg_cancel v) -variable (A) in /-- If `F` is a face of `C`, then the dehomogenization of `F` is a face of the dehomogenization of `C`. -/ theorem dehomogenize_isFaceOf {F C : PointedCone R W} (hf : F.IsFaceOf C) : - (ConvexSet.dehomogenize A F).IsFaceOf (ConvexSet.dehomogenize A C) where + IsFaceOf R (dehomogenize ℋ F) (dehomogenize ℋ C) where le := preimage_mono (fun _ x ↦ hf.le x) left_mem_of_mem_openSegment := by rintro x hx y hy z hz ⟨a, b, ha, hb, hab, hzo⟩ refine hf.mem_of_smul_add_mem hx (C.smul_mem hb.le hy) ha ?_ rwa [← convexCombPair_eq_sum _ _ ha.le hb.le hab, - ← hom.ofPoint.isAffineMap.map_convexCombPair, hzo] + ← ℋ.ofPoint.isAffineMap.map_convexCombPair, hzo] /-- The isomorphism between the face lattice of a convex set `P` and the face lattice of its homogenization cone. @@ -107,17 +107,19 @@ its homogenization cone. This isomorphism is used to translate results between face lattices of cones and face lattices of convex sets. -/ -def Face.homogenizeIso {P : ConvexSet R A} : - Face P ≃o PointedCone.Face (P.homogenize W) where - toFun F := ⟨_, hom.homogenize_isFaceOf F.isFaceOf⟩ - invFun F := ⟨dehomogenize A F.toSubmodule, - by simpa [dehomogenize_homogenize] using dehomogenize_isFaceOf A F.isFaceOf⟩ +def _root_.Convexity.face_homogenizeIso {P : Set A} (hP : IsConvexSet R P) : + Face hP ≃o PointedCone.Face (homogenize ℋ P) where + toFun F := ⟨_, ℋ.homogenize_isFaceOf F.isConvexSet hP F.isFaceOf⟩ + invFun F := ⟨dehomogenize ℋ F.toSubmodule, dehomogenize_isConvexSet ℋ F.toSubmodule, + by simpa [dehomogenize_homogenize ℋ hP] using dehomogenize_isFaceOf ℋ F.isFaceOf⟩ map_rel_iff' := by intro a b refine ⟨fun h x xm ↦ ?_, fun h _ xm ↦ span_mono (image_mono h) xm⟩ - refine (ofPoint_mem_homogenize_iff_mem W x b.toConvexSet).mp (h ?_) - exact (ofPoint_mem_homogenize_iff_mem W x a.toConvexSet).mpr xm - left_inv _ := by simp [dehomogenize_homogenize] + refine (ofPoint_mem_homogenize_iff_mem _ x b.isConvexSet).mp (h ?_) + exact (ofPoint_mem_homogenize_iff_mem _ x a.isConvexSet).mpr xm + left_inv F := by + simp only [Face.carrier_eq_coe, Face.ext_iff] + exact dehomogenize_homogenize ℋ F.isConvexSet right_inv F := by have := homogenize_dehomogenize_of_le_positive (fun _ h n ↦ weight_pos_of_mem_homogenize (F.isFaceOf.le h) n) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean index 5b3d6acc..3a19368e 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean @@ -6,8 +6,10 @@ Authors: Olivia Röhrig, Mara Gruß, Valentina Taylor Cerra, Martin Winter module public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Basic +public import Polyhedral.Mathlib.Geometry.Convex.Set +import Polyhedral.Mathlib.Data.SetLike.IsConcrete -import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice +-- import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice /-! This file defines faces of convex sets. @@ -25,43 +27,40 @@ section Semiring variable [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] variable [ConvexSpace R M] -namespace ConvexSet +namespace IsConvexSet -/- NOTE: maybe this should be defined on `Set` instead of `ConvexSet`. -/ /-- A face of a convex set `P`. Represents the face lattice of `P`. -/ -structure Face (P : ConvexSet R M) extends toConvexSet : ConvexSet R M where - isFaceOf : IsFaceOf toConvexSet P +@[ext] +structure Face {p : Set M} (P : IsConvexSet R p) where + carrier : Set M + isConvexSet : IsConvexSet R carrier + isFaceOf : IsFaceOf R carrier p -attribute [coe] Face.toConvexSet +attribute [coe] Face.carrier namespace Face -variable {P : ConvexSet R M} +variable {p : Set M} {P : IsConvexSet R p} instance : SetLike (Face P) M where - coe F := F.toConvexSet.carrier + coe F := F.carrier coe_injective a b h := by - cases a; cases b; congr; exact SetLike.coe_injective h + cases a; cases b; congr -instance : CoeOut (Face P) (ConvexSet R M) := ⟨toConvexSet⟩ +instance : CoeOut (Face P) (Set M) := ⟨carrier⟩ @[simp] theorem carrier_eq_coe {F : Face P} : F.carrier = F := by rfl @[simp] theorem mem_coe {F : Face P} (x : M) : x ∈ F.carrier ↔ x ∈ F := .rfl -@[ext] theorem ext {F₁ F₂ : Face P} (h : ∀ x, x ∈ F₁ ↔ x ∈ F₂) : F₁ = F₂ := SetLike.ext h +@[simp] theorem mem_mk {s c h x} : x ∈ (⟨s, c, h⟩ : Face P) ↔ x ∈ s := .rfl -@[simp] theorem coe_eq_toConvexSet_coe {F : Face P} : (F : Set M) = F.toConvexSet := - SetLike.ext'_iff.mp rfl - -@[simp] theorem mem_mk {s h x} : x ∈ (⟨s, h⟩ : Face P) ↔ x ∈ s := .rfl - -@[simp] theorem mk_eq {s h} : (⟨s, h⟩ : Face P) = s := by ext; simp +@[simp] theorem mk_eq {s c h} : (⟨s, c, h⟩ : Face P) = s := by ext; simp instance : PartialOrder (Face P) := .ofSetLike .. instance : OrderBot (Face P) where - bot := ⟨∅, IsFaceOf.empty⟩ + bot := ⟨_, IsConvexSet.empty, IsFaceOf.empty⟩ bot_le _ _ := by simp lemma nonempty_of_ne_bot {F : Face P} (h : F ≠ ⊥) : (F : Set M).Nonempty := by @@ -72,46 +71,32 @@ lemma nonempty_of_ne_bot {F : Face P} (h : F ≠ ⊥) : (F : Set M).Nonempty := simp [← SetLike.mem_coe, heq, Bot.bot] instance : OrderTop (Face P) where - top := ⟨P, IsFaceOf.refl P⟩ + top := ⟨_, P, IsFaceOf.refl⟩ le_top F := F.isFaceOf.le instance : Inhabited (Face P) := ⟨⊤⟩ -theorem toConvexSet_le {F : Face P} : F ≤ P := F.isFaceOf.le +theorem toConvexSet_le {F : Face P} : F.carrier ≤ p := F.isFaceOf.le @[simp] theorem toConvexSet_le_toConvexSet {F₁ F₂ : Face P} : - F₁.toConvexSet ≤ F₂.toConvexSet ↔ F₁ ≤ F₂ := .rfl + F₁.carrier ≤ F₂.carrier ↔ F₁ ≤ F₂ := .rfl -@[simp] -theorem toConvexSet_lt_toConvexSet {F₁ F₂ : Face P} : - F₁.toConvexSet < F₂.toConvexSet ↔ F₁ < F₂ := .rfl +@[simp] theorem toConvexSet_bot : ((⊥ : Face P) : Set M) = ∅ := rfl -@[simp] -theorem mem_toConvexSet {F : Face P} (x : M) : x ∈ F.toConvexSet ↔ x ∈ F := .rfl - -@[simp] theorem toConvexSet_bot : ((⊥ : Face P) : ConvexSet R M) = ∅ := rfl - -@[simp] theorem toConvexSet_top : ((⊤ : Face P) : ConvexSet R M) = P := rfl +@[simp] theorem toConvexSet_top : ((⊤ : Face P) : Set M) = p := rfl /-! ### Infimum, supremum and lattice -/ -/-- The infimum of two faces `F₁`, `F₂` of `C` is the intersection of the cones `F₁` and `F₂`. -/ +/-- The infimum of two faces `F₁`, `F₂` of `P` is the intersection of `F₁` and `F₂`. -/ instance : Min (Face P) where - min F₁ F₂ := ⟨F₁ ⊓ F₂, F₁.isFaceOf.inf_left F₂.isFaceOf⟩ - -protected theorem IsFaceOf.sInf (F : Set (ConvexSet R M)) (h : ∀ f ∈ F, f.IsFaceOf P) : - (P ⊓ sInf F).IsFaceOf P where - le _ sm := sm.1 - left_mem_of_mem_openSegment := by - simp only [SetLike.mem_min, SetLike.mem_sInf, and_imp] - intro x hx y hy z hz h₁ h₂ - simpa [hx] using fun F Fs ↦ (h F Fs).left_mem_of_mem_openSegment hx hy (by grind) h₂ + min F₁ F₂ := ⟨_, F₁.isConvexSet.inter F₂.isConvexSet, F₁.isFaceOf.inf_left F₂.isFaceOf⟩ instance : InfSet (Face P) where sInf S := - { toConvexSet := P ⊓ sInf {s.1 | s ∈ S} - isFaceOf := IsFaceOf.sInf _ (fun _ ⟨s, _, hs2⟩ ↦ hs2 ▸ s.isFaceOf) } + { carrier := p ⊓ sInf {s.1 | s ∈ S} + isConvexSet := P.inter (IsConvexSet.sInter fun s ⟨s, hs, sh⟩ ↦ sh ▸ s.isConvexSet) + isFaceOf := IsFaceOf.sInf (by rintro _ ⟨s, hs, rfl⟩; exact s.isFaceOf) } instance : SemilatticeInf (Face P) where inf := min @@ -125,17 +110,18 @@ instance : CompleteSemilatticeInf (Face P) where constructor <;> intro f fS · rw [← toConvexSet_le_toConvexSet] refine inf_le_of_right_le ?_ - simpa [LE.le] using fun _ xs ↦ xs f fS - · simp only [sInf, Set.sInter_image, Set.mem_ofPred_eq, - Set.iInter_exists, Set.biInter_and', Set.iInter_iInter_eq_right] - simpa [LE.le] using fun x a ↦ ⟨f.2.1 a, fun i hi ↦ (mem_coe x).mp (fS hi a)⟩ + simp only [carrier_eq_coe, Set.sInf_eq_sInter] + exact fun _ xs ↦ xs f (by simpa) + · simp only [sInf, carrier_eq_coe, Set.mem_ofPred_eq, forall_exists_index, and_imp, + forall_apply_eq_imp_iff₂, SetLike.mem_coe, Set.inf_eq_inter] + simpa [LE.le] using fun x a ↦ ⟨f.isFaceOf.le a, fun i hi ↦ (mem_coe x).mp (fS hi a)⟩ instance : CompleteLattice (Face P) where - top := ⟨P, .refl _⟩ + top := ⟨_, P, .refl⟩ le_top _ := toConvexSet_le __ := completeLatticeOfCompleteSemilatticeInf _ -end ConvexSet.Face +end IsConvexSet.Face end Semiring diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 30ad36ed..f7388bbb 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -7,9 +7,7 @@ module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Convexity public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Lineal -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic - -import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization /-! This file defines homogenization of convex sets in affine spaces. -/ @@ -17,7 +15,7 @@ import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice open Convexity Pointwise Set PointedCone Submodule -namespace Convexity.ConvexSet +namespace Convexity variable {R V A W : Type*} @@ -28,62 +26,67 @@ open Convexity variable [Ring R] [PartialOrder R] [IsStrictOrderedRing R] variable [AddCommGroup V] [Module R V] variable [AddCommGroup W] [Module R W] -variable [AddTorsor V A] [ConvexSpace R A] +variable [AddTorsor V A] -variable [hom : Affine.IsHomogenization R A W] +variable (ℋ : Affine.IsHomogenization R A W) -variable (W) in /-- The homogenization cone of a convex set in an affine space. -/ -def homogenize (P : ConvexSet R A) : PointedCone R W := hull R (hom.ofPoint '' P) +def homogenize (P : Set A) : PointedCone R W := hull R (ℋ.ofPoint '' P) -lemma homogenize_mono {K₁ K₂ : ConvexSet R A} (h : K₁ ≤ K₂) : - K₁.homogenize W ≤ K₂.homogenize W := Submodule.span_mono <| Set.image_mono h +lemma homogenize_mono {K₁ K₂ : Set A} (h : K₁ ≤ K₂) : + homogenize ℋ K₁ ≤ homogenize ℋ K₂ := Submodule.span_mono <| Set.image_mono h -lemma homogenize_monotone : Monotone (homogenize W : ConvexSet R A → PointedCone R W) := - fun _ _ => homogenize_mono +lemma homogenize_monotone : Monotone (homogenize ℋ : Set A → PointedCone R W) := + fun _ _ => homogenize_mono _ /-- Homogenization from convex set to convex cones as an order homomorphism. -/ -def homogenizeOrderHom : ConvexSet R A →o PointedCone R W where - toFun := homogenize W - monotone' := homogenize_monotone +def homogenizeOrderHom : Set A →o PointedCone R W where + toFun := homogenize ℋ + monotone' := homogenize_monotone _ + +lemma homogenize_singleton (p : A) : homogenize ℋ {p} = R ∙₊ ℋ.ofPoint p := by + rw [homogenize, Set.image_singleton] @[simp] -lemma homogenize_bot : homogenize W (⊥ : ConvexSet R A) = ⊥ := by +lemma homogenize_bot : homogenize ℋ ∅ = ⊥ := by simp [homogenize] @[simp] -lemma homogenize_eq_bot_iff (P : ConvexSet R A) : homogenize W P = ⊥ ↔ P = ⊥ := by - refine ⟨fun h ↦ ?_, by simp +contextual [-SetLike.bot_eq_empty]⟩ +lemma homogenize_eq_bot_iff (P : Set A) : homogenize ℋ P = ⊥ ↔ P = ∅ := by + refine ⟨fun h ↦ ?_, by simp +contextual [homogenize]⟩ ext x - simp only [homogenize, span_eq_bot, mem_image, SetLike.mem_coe, forall_exists_index, and_imp, + simp only [homogenize, span_eq_bot, mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at h - simpa using fun hx ↦ hom.ofPoint_ne_zero _ (h x hx) + simpa using fun hx ↦ ℋ.ofPoint_ne_zero _ (h x hx) -/- NOTE: `homogenize_top`, stating `homogenize W (⊤ : ConvexSet R A) = hom.weight.positive`, +/- NOTE: `homogenize_top`, stating `homogenize ℋ (⊤ : Set A) = ℋ.weight.positive`, only holds over linearly ordered fields and is proven in the `Field` section below. Over a general ordered ring it fails: for `R = ℤ[ε]` with `ε` a positive infinitesimal, the point `(1, ε)` lies in `weight.positive` but not in the cone hull of the weight-one hyperplane, since all nonnegative coefficients bounded by `ε` lie in the ideal `(ε)`. -/ -lemma homogenize_le_weight_positive (K : ConvexSet R A) : - homogenize W K ≤ hom.weight.positive := by +lemma homogenize_le_weight_positive (K : Set A) : + homogenize ℋ K ≤ ℋ.weight.positive := by exact LinearMap.hull_le_positive_of_subset_preimage_singleton one_pos fun _ ↦ by rintro ⟨x, -, rfl⟩ - simp [hom.weight_one] + simp [ℋ.weight_ofPoint] -lemma weight_pos_of_mem_homogenize {x} {P : ConvexSet R A} (h : x ∈ homogenize W P) (hx : x ≠ 0) : - 0 < hom.weight x := homogenize_le_weight_positive P h hx +variable {ℋ} in +lemma weight_pos_of_mem_homogenize {x} {P : Set A} (h : x ∈ homogenize ℋ P) (hx : x ≠ 0) : + 0 < ℋ.weight x := homogenize_le_weight_positive _ P h hx -lemma weight_nonneg_of_mem_homogenize {x : W} {P : ConvexSet R A} (h : x ∈ homogenize W P) : - 0 ≤ hom.weight x := - (LinearMap.mem_positive'.mp (homogenize_le_weight_positive (W := W) P h)).1 +variable {ℋ} in +lemma weight_nonneg_of_mem_homogenize {x : W} {P : Set A} (h : x ∈ homogenize ℋ P) : + 0 ≤ ℋ.weight x := + (LinearMap.mem_positive'.mp (homogenize_le_weight_positive _ P h)).1 -lemma homogenize_salient {K : ConvexSet R A} : PointedCone.Salient (homogenize W K) := - Salient.of_le_salient hom.weight.positive_salient (homogenize_le_weight_positive K) +lemma homogenize_salient (K : Set A) : PointedCone.Salient (homogenize ℋ K) := + Salient.of_le_salient ℋ.weight.positive_salient (homogenize_le_weight_positive _ K) -theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize W C).FG) : - ∃ g : Finset W, PointedCone.hull R g = homogenize W C ∧ - (g : Set W) ⊆ Set.range hom.ofPoint := by +variable {ℋ} in +theorem homogenize_fg_ofPoint_range {C : Set A} (h : (homogenize ℋ C).FG) : + ∃ g : Finset W, PointedCone.hull R g = homogenize ℋ C ∧ + (g : Set W) ⊆ Set.range ℋ.ofPoint := by obtain ⟨g, hg⟩ := h -- express each generator as a positive combo of stuff in the embedding of C have gsum {x} (hx : x ∈ g) := mem_hull_set.mp (hg ▸ (Submodule.mem_span_of_mem hx)) @@ -91,7 +94,7 @@ theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize W C).FG -- collect all said stuff and use as the new generators let g' := g.attach.biUnion (fun x => (Classical.choose (gsum x.2)).support) use g' - have g'sub : (g' : Set W) ⊆ hom.ofPoint '' C := by + have g'sub : (g' : Set W) ⊆ ℋ.ofPoint '' C := by simpa [g'] using fun _ b ↦ (Classical.choose_spec (gsum b)).1 have gsubhull : (g : Set W) ⊆ hull R (g' : Set W) := by intro x hx @@ -104,40 +107,35 @@ theorem homogenize_fg_ofPoint_range {C : ConvexSet R A} (h : (homogenize W C).FG section Module -variable [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] -variable (A) in -def dehomogenize (C : PointedCone R W) : ConvexSet R A := - ⟨_, C.isConvexSet.preimage hom.ofPoint.isAffineMap⟩ +def dehomogenize (C : PointedCone R W) : Set A := ℋ.ofPoint ⁻¹' C alias _root_.PointedCone.dehomogenize := dehomogenize @[simp] -lemma dehomogenize_bot : dehomogenize A (⊥ : PointedCone R W) = ⊥ := by +lemma dehomogenize_bot : dehomogenize ℋ (⊥ : PointedCone R W) = ∅ := by ext simp [dehomogenize, Affine.IsHomogenization.ofPoint_ne_zero] @[simp] -lemma dehomogenize_top : dehomogenize A (⊤ : PointedCone R W) = ⊤ := by +lemma dehomogenize_top : dehomogenize ℋ (⊤ : PointedCone R W) = univ := by ext - simp [dehomogenize, SetLike.mem_coe.mp] + simp [dehomogenize] @[simp] -lemma dehomogenize_weight_positive : dehomogenize A hom.weight.positive = ⊤ := - SetLike.eq_top_of_forall fun _ ↦ LinearMap.mem_positive'.mpr (by simp [hom.weight_one]) +lemma dehomogenize_weight_positive : dehomogenize ℋ ℋ.weight.positive = ⊤ := by + simp [dehomogenize, LinearMap.positive] -variable (A) in lemma dehomogenize_mono {C₁ C₂ : PointedCone R W} (h : C₁ ≤ C₂) : - dehomogenize A C₁ ≤ dehomogenize A C₂ := Set.preimage_mono <| Set.preimage_mono h + dehomogenize ℋ C₁ ≤ dehomogenize ℋ C₂ := Set.preimage_mono <| Set.preimage_mono h -- Q: why Set.preimage_mono twice? -variable (A) in -lemma dehomogenize_monotone : Monotone (dehomogenize A : PointedCone R W → ConvexSet R A) := - fun _ _ => dehomogenize_mono A +lemma dehomogenize_monotone : Monotone (dehomogenize ℋ) := + fun _ _ => dehomogenize_mono _ -- This lemma is just `Set.image_preimage_eq_inter_range` in disguise. It is likely not needed. lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : - hom.ofPoint '' dehomogenize A C = (C : Set W) ∩ hom.ofPoint.range := by + ℋ.ofPoint '' dehomogenize ℋ C = (C : Set W) ∩ ℋ.ofPoint.range := by ext x simp only [Set.mem_image, SetLike.mem_coe, Set.mem_inter_iff, AffineMap.mem_range] constructor @@ -147,11 +145,20 @@ lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : use y simpa +section + +variable [ConvexSpace R A] [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] + +lemma dehomogenize_isConvexSet (C : PointedCone R W) : IsConvexSet R (dehomogenize ℋ C) := + C.isConvexSet.preimage ℋ.ofPoint.isAffineMap + /-- The preimage of the conic hull of a set in the homogenization plane is the convex hull of the preimage of the set. -/ theorem hull_image_ofPoint_eq_homogenize_convexHull {s : Set A} : - hull R (hom.ofPoint '' s) = homogenize W (ConvexSet.convexHull R s) := by - simp [homogenize, ConvexSet.convexHull, hom.ofPoint.isAffineMap.image_convexHull] + hull R (ℋ.ofPoint '' s) = homogenize ℋ (convexHull R s) := by + simp [homogenize, ℋ.ofPoint.isAffineMap.image_convexHull] + +end end Module @@ -162,85 +169,95 @@ section Field variable [Field R] [LinearOrder R] [IsOrderedRing R] variable [AddCommGroup V] [Module R V] variable [AddCommGroup W] [Module R W] -variable [AddTorsor V A] [ConvexSpace R A] +variable [AddTorsor V A] -variable [hom : Affine.IsHomogenization R A W] +variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ -lemma homogenize_top : homogenize W (⊤ : ConvexSet R A) = hom.weight.positive := by - rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton hom.weight one_pos, - ← hom.ofPoint_range_eq_preimage_weight_one] +lemma homogenize_top : homogenize ℋ (univ : Set A) = ℋ.weight.positive := by + rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton ℋ.weight one_pos, + ← ℋ.ofPoint_range_eq_preimage_weight_one] congr! with x simp -variable [ConvexSpace R W] [IsAffineConvexSpace R V A] [IsModuleConvexSpace R W] +section -lemma smul_pos_of_mem_homogenize {P : ConvexSet R A} {x} (h : x ∈ homogenize W P) (hx : x ≠ 0) : - x ∈ Set.Ioi (0 : R) • hom.ofPoint '' (P : Set A) := +variable [ConvexSpace R A] [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A] + +variable {ℋ} in +lemma smul_pos_of_mem_homogenize {P : Set A} (hP : IsConvexSet R P) {x} (h : x ∈ homogenize ℋ P) + (hx : x ≠ 0) : + x ∈ Set.Ioi (0 : R) • ℋ.ofPoint '' (P : Set A) := (mem_hull_iff_mem_pos_smul_of_convex_nonzero - (P.isConvexSet.image hom.ofPoint.isAffineMap) hx).mp h + (hP.image ℋ.ofPoint.isAffineMap) hx).mp h -- TODO: This lemma should be proven for general sets (homogenizing to SubMulAction) and then -- applied here as a special case. -variable (W) in -lemma ofPoint_mem_homogenize_iff_mem (x : A) (P : ConvexSet R A) : - hom.ofPoint x ∈ homogenize W P ↔ x ∈ P := by - refine ⟨fun h ↦ ?_, fun h ↦ mem_span_of_mem (Set.mem_image_of_mem hom.ofPoint h)⟩ - obtain ⟨_, _, h'⟩ := smul_pos_of_mem_homogenize (Set.mem_preimage.mpr h) (hom.ofPoint_ne_zero x) +lemma ofPoint_mem_homogenize_iff_mem (x : A) {P : Set A} (hP : IsConvexSet R P) : + ℋ.ofPoint x ∈ homogenize ℋ P ↔ x ∈ P := by + refine ⟨fun h ↦ ?_, fun h ↦ mem_span_of_mem (Set.mem_image_of_mem ℋ.ofPoint h)⟩ + obtain ⟨_, _, h'⟩ := smul_pos_of_mem_homogenize hP (Set.mem_preimage.mpr h) (ℋ.ofPoint_ne_zero x) obtain ⟨_, ⟨_, _, hyy'⟩, hy'⟩ := Set.mem_smul_set.mp h' - have := congrArg hom.weight hy' - simp [← hyy', hom.weight_one] at this + have := congrArg ℋ.weight hy' + simp [← hyy', ℋ.weight_ofPoint] at this simp only [this, Set.mem_image, one_smul, exists_eq_right] at h' obtain ⟨_, _, hxx'⟩ := h' - simpa [← hom.ofPoint_injective hxx'] + simpa [← ℋ.ofPoint_injective hxx'] /-- Dehomogenizing the homogenization of a convex set yields the same set again. -/ -@[simp] theorem dehomogenize_homogenize (P : ConvexSet R A) : - dehomogenize A (homogenize W P) = P := by - ext x; exact ofPoint_mem_homogenize_iff_mem _ _ _ - -lemma homogenize_injective : Function.Injective (homogenize (hom := hom) W) := by - intro P Q h - have hh := congr_arg (ConvexSet.dehomogenize A) h - simp [dehomogenize_homogenize] at hh +@[simp] theorem dehomogenize_homogenize {P : Set A} (hP : IsConvexSet R P) : + dehomogenize ℋ (homogenize ℋ P) = P := by + ext x; exact ofPoint_mem_homogenize_iff_mem _ _ hP + +lemma homogenize_injective_isConvexSet {P Q : Set A} (hP : IsConvexSet R P) (hQ : IsConvexSet R Q) + (h : homogenize ℋ P = homogenize ℋ Q) : P = Q := by + have hh := congr_arg (dehomogenize ℋ) h + simp [dehomogenize_homogenize _ hP, dehomogenize_homogenize _ hQ] at hh assumption +variable {ℋ} in /-- If the entire cone save the origin are at positive weight, homogenizing the dehomogenization of the homogenize yields the cone again. -/ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} - (hC : C ≤ hom.weight.positive) : homogenize W (dehomogenize A C) = C := by + (hC : C ≤ ℋ.weight.positive) : homogenize ℋ (dehomogenize ℋ C) = C := by by_cases hbot : C = ⊥ · simp [hbot, homogenize, dehomogenize] · apply SetLike.ext' unfold homogenize rw [eq_Ici_zero_smul_inter_preimage_of_pos_of_ne_bot hC zero_lt_one hbot, - ofPoint_dehomogenize_eq_inter_ofPoint, ← hom.ofPoint_range_eq_preimage_weight_one] + ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_one] apply hull_eq_smul · obtain ⟨y, hyC, hy0⟩ := exists_mem_ne_zero_of_ne_bot hbot - let y' := (hom.weight y)⁻¹ • y + let y' := (ℋ.weight y)⁻¹ • y have hy'C : y' ∈ C := C.smul_mem (inv_nonneg.mpr (@hC y hyC hy0).le) hyC - have hy' : y' ∈ Set.range hom.ofPoint := by - simpa [y', hom.ofPoint_range_eq_preimage_weight_one] + have hy' : y' ∈ Set.range ℋ.ofPoint := by + simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ - · exact C.isConvexSet.inter hom.ofPoint.isConvexSet_range + · exact C.isConvexSet.inter ℋ.ofPoint.isConvexSet_range -lemma homogenize_mono_iff {K₁ K₂ : ConvexSet R A} : - K₁.homogenize W ≤ K₂.homogenize W ↔ K₁ ≤ K₂ where - mp h := by simpa using dehomogenize_mono A h - mpr := homogenize_mono +lemma homogenize_mono_iff {K₁ K₂ : Set A} (h₁ : IsConvexSet R K₁) (h₂ : IsConvexSet R K₂) : + homogenize ℋ K₁ ≤ homogenize ℋ K₂ ↔ K₁ ≤ K₂ where + mp h := by simpa [dehomogenize_homogenize _ h₁, dehomogenize_homogenize _ h₂] + using dehomogenize_mono ℋ h + mpr := homogenize_mono _ -- Issue #66 /-- The lattice of convex sets is isomorphic to the lattice of convex sub-cones of the positive cone. -/ -def homogenizeOrderEquiv : ConvexSet R A ≃o Set.Iic hom.weight.positive where - toFun K := ⟨_, K.homogenize_le_weight_positive⟩ - invFun C := dehomogenize A C.1 - left_inv K := dehomogenize_homogenize K +def homogenizeOrderEquiv : {s : Set A // IsConvexSet R s} ≃o Set.Iic ℋ.weight.positive where + toFun K := ⟨_, homogenize_le_weight_positive _ K.val⟩ + invFun C := ⟨dehomogenize ℋ C.1, dehomogenize_isConvexSet _ _⟩ + left_inv K := by simp [dehomogenize_homogenize _ K.prop] right_inv C := by dsimp; congr; exact homogenize_dehomogenize_of_le_positive C.2 - map_rel_iff' := homogenize_mono_iff + map_rel_iff' := by + refine homogenize_mono_iff _ ?_ ?_ + · expose_names; exact a.prop + · expose_names; exact b.prop + +end end Field -end Convexity.ConvexSet +end Convexity diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean deleted file mode 100644 index 39719157..00000000 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean +++ /dev/null @@ -1,127 +0,0 @@ -/- -Copyright (c) 2026 Martin Winter, Olivia Röhrig. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Martin Winter, Olivia Röhrig --/ -module - -public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic - -import Mathlib.LinearAlgebra.AffineSpace.AffineMap - -/-! The content of this file should go into `AffineSpace/AffineMap.lean`. -/ - -@[expose] public section - -open Affine Module AffineSubspace - -section - -variable {k V V₁ V₂ P P₁ P₂ : Type*} - -namespace AffineMap - -variable [Ring k] -variable [AddCommGroup V] [Module k V] -variable [AddCommGroup V₁] [Module k V₁] -variable [AddCommGroup V₂] [Module k V₂] -variable [AffineSpace V P] [AffineSpace V₁ P₁] [AffineSpace V₂ P₂] - -/-- The range of an affine map is an affine subspace. -/ -def range (f : P₁ →ᵃ[k] P₂) : AffineSubspace k P₂ where - carrier := Set.range f - smul_vsub_vadd_mem' := by - simp only [Set.mem_range, forall_exists_index] - intro c _ _ _ x₁ h₁ x₂ h₂ x₃ h₃ - exact ⟨c • (x₁ -ᵥ x₂) +ᵥ x₃, by simp [map_vadd, ← h₁, ← h₂, ← h₃]⟩ - -instance instNonemptyRange (f : P₁ →ᵃ[k] P₂) : Nonempty (range f) := - Set.instNonemptyRange f - -@[simp] -theorem mem_range (f : P₁ →ᵃ[k] P₂) (x : P₂) : x ∈ f.range ↔ ∃ (y : P₁), f y = x := - Iff.rfl - -@[simp] -theorem coe_range (f : P₁ →ᵃ[k] P₂) : f.range = Set.range f := rfl - -theorem range_eq_map (f : P₁ →ᵃ[k] P₂) : range f = map f ⊤ := by - ext - simp - -theorem mem_range_self (f : P₁ →ᵃ[k] P₂) (x : P₁) : f x ∈ range f := - ⟨x, rfl⟩ - -@[simp] -theorem range_id : range (AffineMap.id k P₁) = ⊤ := - SetLike.coe_injective Set.range_id - -theorem range_comp (f : P₁ →ᵃ[k] P₂) (g : P₂ →ᵃ[k] P) : range (g.comp f) = map g (range f) := - SetLike.coe_injective (Set.range_comp g f) - -theorem range_comp_le_range (f : P₁ →ᵃ[k] P₂) (g : P₂ →ᵃ[k] P) : range (g.comp f) ≤ range g := - SetLike.coe_mono (Set.range_comp_subset_range f g) - -theorem range_eq_top {f : P₁ →ᵃ[k] P₂} : range f = ⊤ ↔ Function.Surjective f := by - rw [SetLike.ext'_iff, coe_range, top_coe, Set.range_eq_univ] - -theorem range_eq_top_of_surjective (f : P₁ →ᵃ[k] P₂) (hf : Function.Surjective f) : - range f = ⊤ := range_eq_top.mpr hf - -theorem range_le_iff_comap {f : P₁ →ᵃ[k] P₂} {p : AffineSubspace k P₂} : - range f ≤ p ↔ comap f p = ⊤ := by rw [range_eq_map, map_le_iff_le_comap, eq_top_iff] - -theorem map_le_range {f : P₁ →ᵃ[k] P₂} {p : AffineSubspace k P₁} : map f p ≤ range f := - SetLike.coe_mono (Set.image_subset_range f p) - -theorem comap_le_comap_iff {f : P₁ →ᵃ[k] P₂} (hf : range f = ⊤) {p p'} : - comap f p ≤ comap f p' ↔ p ≤ p' := - ⟨fun H ↦ by rwa [SetLike.le_def, (range_eq_top.mp hf).forall], comap_mono⟩ - -theorem comap_injective {f : P₁ →ᵃ[k] P₂} (hf : range f = ⊤) : Function.Injective (comap f) := - fun _ _ h ↦ le_antisymm ((comap_le_comap_iff hf).mp (le_of_eq h)) - ((comap_le_comap_iff hf).mp (ge_of_eq h)) - -@[simp] -theorem map_top (f : P₁ →ᵃ[k] P₂) : map f ⊤ = range f := - (range_eq_map f).symm - -@[simp] -theorem affineSpan_range_eq_range (f : P₁ →ᵃ[k] P₂) : affineSpan k (Set.range f) = f.range := by - simp [← Set.image_univ, ← AffineSubspace.map_span] - -lemma range_direction (f : P₁ →ᵃ[k] P₂) : f.range.direction = f.linear.range := by - apply le_antisymm - · apply Submodule.span_le.mpr - intro _ ⟨p₁, h₁, p₂, h₂, h⟩ - simp only [SetLike.mem_coe, mem_range] at h₁ h₂ - obtain ⟨p₁, rfl⟩ := h₁ - obtain ⟨p₂, rfl⟩ := h₂ - exact ⟨p₁ -ᵥ p₂, h ▸ f.linearMap_vsub _ _⟩ - · apply Submodule.span_le.mp - intro v hv - rw [Submodule.span_coe_eq_restrictScalars] at hv - obtain ⟨w, rfl⟩ := hv - apply Submodule.subset_span - simp only [Set.mem_vsub, SetLike.mem_coe, mem_range, exists_exists_eq_and] - exact ⟨(w +ᵥ Classical.arbitrary P₁), (Classical.arbitrary P₁), by simp⟩ - -lemma range_eq_copmap_top (f : P₁ →ᵃ[k] P₂) : f.range = .map f ⊤ := by ext; simp - -def rangeRestrict (f : P₁ →ᵃ[k] P₂) : P₁ →ᵃ[k] f.range where - toFun p := ⟨f p, p, rfl⟩ - linear := (LinearEquiv.ofEq _ _ f.range_direction.symm).toLinearMap ∘ₗ f.linear.rangeRestrict - map_vadd' _ _ := by ext; simp [map_vadd] - -lemma rangeRestrict_injective_iff (f : P₁ →ᵃ[k] P₂) : - (rangeRestrict f).toFun.Injective ↔ f.toFun.Injective := by - simp only [Function.Injective, rangeRestrict, toFun_eq_coe, coe_mk] - constructor - · intro h p q hpq - exact h <| Subtype.ext hpq - · intro h p q hpq - exact h <| congrArg Subtype.val hpq - -end AffineMap - -end diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean new file mode 100644 index 00000000..009a85e0 --- /dev/null +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2026 Olivia Röhrig. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig +-/ +module + +public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic + +/-! +# Range of affine maps + +The range of an affine map `f : P₁ →ᵃ[R] P₂` is an affine subspace of `P₂`. + +# Implementation note + +Follows `LinearMap.range`. + +-/ + +@[expose] public section + +open Affine Module AffineMap AffineSubspace + +section + +variable {R V₁ V₂ P₁ P₂ : Type*} + +namespace AffineMap + +variable [Ring R] +variable [AddCommGroup V₁] [Module R V₁] +variable [AddCommGroup V₂] [Module R V₂] +variable [AffineSpace V₁ P₁] [AffineSpace V₂ P₂] + +variable (f : P₁ →ᵃ[R] P₂) + +/-- The range of an affine map is an affine subspace. -/ +def range : AffineSubspace R P₂ where + carrier := Set.range f + smul_vsub_vadd_mem' := by + simp only [Set.mem_range, forall_exists_index] + intro c _ _ _ x₁ h₁ x₂ h₂ x₃ h₃ + exact ⟨c • (x₁ -ᵥ x₂) +ᵥ x₃, by simp [map_vadd, ← h₁, ← h₂, ← h₃]⟩ + +/-- The range of an affine map is nonempty. -/ +instance instNonemptyRange : Nonempty (range f) := + Set.instNonemptyRange f + +@[simp, norm_cast] +theorem coe_range : f.range = Set.range f := rfl + +@[simp] +theorem mem_range (x : P₂) : x ∈ f.range ↔ ∃ (y : P₁), f y = x := + Iff.rfl + +theorem range_eq_map_top : f.range = .map f ⊤ := by ext; simp + +theorem mem_range_self (x : P₁) : f x ∈ f.range := by simp + +@[simp] +theorem range_id : (id R P₁).range = ⊤ := by ext; simp + +theorem range_direction_eq_linear_range : f.range.direction = f.linear.range := by + rw [range_eq_map_top, map_direction, direction_top, Submodule.map_top] + +/-- Restrict the codomain of an affine map `f` to `f.range`. -/ +def rangeRestrict : P₁ →ᵃ[R] f.range where + toFun p := ⟨f p, p, rfl⟩ + linear := f.linear.codRestrict f.range.direction + (f.range_direction_eq_linear_range ▸ f.linear.mem_range_self) + map_vadd' _ _ := by ext; simp [map_vadd] + +theorem surjective_rangeRestrict : Function.Surjective ⇑f.rangeRestrict := + fun ⟨_, y, rfl⟩ => ⟨y, rfl⟩ + +@[simp] +theorem range_rangeRestrict : f.rangeRestrict.range = ⊤ := by + ext ⟨_, x, rfl⟩ + simpa [AffineSubspace.mem_top, iff_true] using ⟨x, rfl⟩ + +@[simp] +theorem injective_rangeRestrict_iff : + Function.Injective (rangeRestrict f) ↔ Function.Injective f := by + convert (Function.Injective.of_comp_iff Subtype.val_injective f.rangeRestrict).symm + ext; simp [rangeRestrict] + +end AffineMap + +end diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean deleted file mode 100644 index 306753ed..00000000 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Basic.lean +++ /dev/null @@ -1,230 +0,0 @@ -/- -Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig, Martin Winter --/ -module - -public import Mathlib.LinearAlgebra.AffineSpace.Homogenization -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineMap - -import Mathlib.Geometry.Convex.ConvexSpace.Module -import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic - -/-! This file defines affine homogenization axiomatically and proves every object fulfilling the -axioms is linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. - -## Implementation notes -* The axiomatization in the literature is redundant. The universal property can be proven solely -from the subset of axioms used in `IsHomogenization`, as is done in lemma `extend`. It is -convenient to use the linear equivalence between any homogenization and `Homogenization` -for the proof. - -## References - -* [J. Gallier, *Geometric Methods and Applications for Computer Science and - Engineering*][Gallier2011GeometricMethods] - -/ - -@[expose] public section - -namespace Affine - -section Ring - -open Function Submodule - -variable {R : Type*} [Ring R] -variable {V : Type*} [AddCommGroup V] [Module R V] -variable {A : Type*} [AddTorsor V A] -variable {W : Type*} [AddCommGroup W] [Module R W] - -variable (R A W) in -/-- An embedding of an affine space `A` into a vector space `W` s.t. the image of `A` is exactly the -weight-1 hyperplane under a given linear weight map. -Follows Definition 4.2 in [Gallier2011GeometricMethods] -https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ -class IsHomogenization where - ofPoint : A →ᵃ[R] W - ofPoint_injective : Injective ofPoint - weight : W →ₗ[R] R - ofPoint_range_eq_preimage_weight_one : Set.range ofPoint = weight ⁻¹' {1} - -variable (R A) in -/-- The canonical homogenization is a homogenization. -/ -noncomputable instance IsHomogenization.canonical : - IsHomogenization R A (Homogenization R A) where - ofPoint := Homogenization.ofPoint - ofPoint_injective := Homogenization.ofPoint_injective - weight := Homogenization.weight - ofPoint_range_eq_preimage_weight_one := by - ext x - constructor - · rintro ⟨a, rfl⟩ - simp - · exact fun hx ↦ (Homogenization.weight_eq_one_iff.mp hx).imp fun _ hp ↦ hp.symm - -namespace IsHomogenization - -variable [hom : IsHomogenization R A W] - -abbrev ofVector := hom.ofPoint.linear - -theorem ofVector_injective : Injective hom.ofVector := by - simp [hom.ofPoint_injective] - -/-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ -theorem ofVector_range_eq_weight_ker : hom.ofVector.range = hom.weight.ker := by - ext x - let a₀ := Classical.arbitrary A - simp only [LinearMap.mem_range, LinearMap.mem_ker] - have : (∃ y, hom.ofVector y = x) ↔ ∃ a b : A, hom.ofVector (a -ᵥ b) = x := - ⟨fun ⟨y, hy⟩ => ⟨y +ᵥ a₀, a₀, by simp [vadd_vsub, hy]⟩, fun ⟨a, b, hab⟩ => ⟨a -ᵥ b, hab⟩⟩ - rw [this] - have hh := Set.ext_iff.mp hom.ofPoint_range_eq_preimage_weight_one - constructor - · rintro ⟨a, b, hab⟩ - simp only [Set.mem_preimage, Set.mem_singleton_iff] at hh - simp [← hab, map_sub, (hh (ofPoint b)).mp ⟨b, rfl⟩, (hh (ofPoint a)).mp ⟨a, rfl⟩] - · intro h - have ha := Set.mem_preimage.mp <| (hh (hom.ofPoint a₀)).mp (by simp) - obtain ⟨b, hb⟩ : x + hom.ofPoint a₀ ∈ (Set.range hom.ofPoint) := by - simpa [hom.ofPoint_range_eq_preimage_weight_one, Set.mem_preimage, map_add, h] - exact ⟨b, a₀, by simp [AffineMap.linearMap_vsub, hb]⟩ - -/-- The homogenization of a point in `A` has weight 1. -/ -lemma weight_one (a₀ : A) : hom.weight (hom.ofPoint a₀) = 1 := by - convert Set.ext_iff.mp hom.ofPoint_range_eq_preimage_weight_one (hom.ofPoint a₀) - simp [exists_apply_eq_apply, Set.mem_preimage, Set.mem_singleton_iff, true_iff] - -theorem mem_range_ofPoint_iff (x : W) : - x ∈ hom.ofPoint.range ↔ hom.weight x = 1 := by - refine ⟨?_, fun h ↦ Eq.mpr (congrFun hom.ofPoint_range_eq_preimage_weight_one x) h⟩ - rintro ⟨y, hy⟩ - rw [← hy, weight_one] - -theorem zero_notMem_affineSpan [Nontrivial R] : - 0 ∉ hom.ofPoint.range := fun hh ↦ by - simpa using mem_range_ofPoint_iff (0 : W) |>.mp hh - -variable [Nontrivial R] in -theorem ofPoint_ne_zero (x : A) : hom.ofPoint x ≠ (0 : W) := by - grind [zero_notMem_affineSpan, AffineMap.mem_range] - -/-- The homogenization of a point in `V` has weight 0. -/ -lemma weight_zero (v : V) : hom.weight (hom.ofVector v) = 0 := by - simp [LinearMap.mem_ker.mp, ← ofVector_range_eq_weight_ker] - -theorem span_range_ofPoint : span R (Set.range hom.ofPoint) = ⊤ := by - refine eq_top_iff'.mpr (fun x ↦ ?_) - let a₀ := Classical.arbitrary A - -- projecting x to weight 0 along a₀ gives sth in the span of image of ofPoint - have hlin : x - hom.weight x • hom.ofPoint a₀ ∈ Submodule.span R hom.ofPoint.range := by - obtain ⟨v, hv⟩ : x - hom.weight x • hom.ofPoint a₀ ∈ hom.ofVector.range := by - simp [ofVector_range_eq_weight_ker, weight_one a₀] - have : hom.ofVector v = hom.ofPoint (v +ᵥ a₀) - hom.ofPoint a₀ := by simp - rw [← hv, this] - apply Submodule.sub_mem <;> apply Submodule.subset_span - · exact ⟨v +ᵥ a₀, rfl⟩ - · exact ⟨a₀, rfl⟩ - simpa using - Submodule.add_mem _ hlin <| smul_mem _ (hom.weight x) (subset_span ⟨a₀, rfl⟩) - -variable (hom) in -/-- The canonical linear map from `Homogenization R A` to any homogenization `W` of `A`. -/ -noncomputable def ofCanonical : Homogenization R A →ₗ[R] W := Homogenization.lift hom.ofPoint - -@[simp] lemma ofCanonical_ofPoint (a : A) : - hom.ofCanonical (Homogenization.ofPoint a) = hom.ofPoint a := by - simp [ofCanonical] - -@[simp] lemma ofCanonical_ofVector (v : V) : - hom.ofCanonical (Homogenization.ofVector v) = hom.ofVector v := by - simp [ofCanonical] - -lemma weight_comp_ofCanonical : - hom.weight ∘ₗ hom.ofCanonical = (Homogenization.weight : Homogenization R A →ₗ[R] R) := - Homogenization.hom_ext fun a ↦ by simp [weight_one] - -@[simp] lemma weight_ofCanonical (x : Homogenization R A) : - hom.weight (hom.ofCanonical x) = Homogenization.weight x := - congr($(weight_comp_ofCanonical (hom := hom)) x) - -theorem ofCanonical_bijective : Bijective hom.ofCanonical := by - constructor - · rw [injective_iff_map_eq_zero] - intro x hx - have hw : Homogenization.weight x = 0 := by - rw [← weight_ofCanonical (W := W) x, hx, map_zero] - obtain ⟨v, rfl⟩ := Homogenization.weight_eq_zero_iff.mp hw - rw [ofCanonical_ofVector, map_eq_zero_iff _ hom.ofVector_injective] at hx - simp [hx] - · rw [← LinearMap.range_eq_top, ← top_le_iff, ← hom.span_range_ofPoint, Submodule.span_le, - Set.range_subset_iff] - exact fun a ↦ ⟨Homogenization.ofPoint a, by simp⟩ - -/-- Every homogenization is linearly equivalent to the canonical homogenization. -/ -noncomputable def canonEquiv : W ≃ₗ[R] Homogenization R A := - (LinearEquiv.ofBijective _ hom.ofCanonical_bijective).symm - -@[simp] lemma canonEquiv_symm_apply (x : Homogenization R A) : - hom.canonEquiv.symm x = hom.ofCanonical x := - rfl - -@[simp] lemma ofCanonical_canonEquiv (x : W) : hom.ofCanonical (hom.canonEquiv x) = x := - hom.canonEquiv.symm_apply_apply x - -@[simp] lemma canonEquiv_ofPoint (a : A) : - hom.canonEquiv (hom.ofPoint a) = Homogenization.ofPoint a := - hom.canonEquiv.symm.injective <| by simp - -theorem canonEquiv_canonical_ofPoint : - hom.canonEquiv ∘ hom.ofPoint = Homogenization.ofPoint := by - ext a; simp - -theorem weight_canonEquiv : Homogenization.weight ∘ hom.canonEquiv = hom.weight := by - ext x - rw [Function.comp_apply, ← weight_ofCanonical (W := W) (hom.canonEquiv x), - ofCanonical_canonEquiv] - --- proving the universal property using the equiv -/-- A homogenization `W` of `A` satisfies the universal property that every affine map from `A` -into any vector space extends uniquely to a linear map from `W` to the vector space. -/ -theorem extend (U : Type*) [AddCommGroup U] [Module R U] - (f : A →ᵃ[R] U) : - ∃! (F : W →ₗ[R] U), F ∘ hom.ofPoint = f := by - refine ⟨Homogenization.lift f ∘ₗ hom.canonEquiv.toLinearMap, funext fun a ↦ by simp, ?_⟩ - intro g hg - have : g ∘ₗ hom.canonEquiv.symm.toLinearMap = Homogenization.lift f := - Homogenization.hom_ext fun a ↦ by simpa using congrFun hg a - rw [← this, LinearMap.comp_assoc] - simp - -open AffineMap LinearEquiv in -/-- The linear equivalence between the underlying vector space and its embedding. -/ -noncomputable def ofVectorRangeEquiv : V ≃ₗ[R] hom.ofVector.range := { - toFun v := ⟨hom.ofVector v, hom.ofVector.mem_range_self v⟩ - map_add' v w := by simp - map_smul' r v := by simp - invFun := - (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr ofPoint_injective)).invFun - left_inv := - (ofInjective hom.ofVector (linear_injective_iff _ |>.mpr ofPoint_injective)).left_inv - right_inv v' := by simp -} - -/-- The affine equivalence between the affine space space and its embedding. -/ -public noncomputable def ofPointRangeEquiv : A ≃ᵃ[R] hom.ofPoint.range := - .ofBijective - ⟨hom.ofPoint.rangeRestrict_injective_iff.mpr hom.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ - -lemma apply_ofPointRangeEquiv_symm (x : hom.ofPoint.range) : - hom.ofPoint (ofPointRangeEquiv.symm x) = x := by - rw [← ofPointRangeEquiv.right_inv x] - congr; exact ofPointRangeEquiv.symm_apply_apply _ - -end IsHomogenization - -end Ring - -end Affine diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean new file mode 100644 index 00000000..340e5bb4 --- /dev/null +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -0,0 +1,324 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig, Martin Winter +-/ +module + +public import Mathlib.LinearAlgebra.AffineSpace.AffineMap +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range +public import Mathlib.LinearAlgebra.AffineSpace.Homogenization + +/-! This file defines affine homogenization as any vector space linearly equivalent to +`Homogenization`, the canonical homogenization from Mathlib. It also proves every object +that satisfies the axiomatic description from [Gallier2011GeometricMethods] is a homogenization +in the linear equivalence sense (see `ofEmbed`). Use `IsHomogenization` for convenience if you want +to consider an embedding into a vector space that is not the canonical `Homogenization`. + +## Implementation notes +* We transport relevant theorems from `Homogenization`. +* The axiomatization in the literature is redundant. The universal property can be proven solely +from the remaning axioms, as is done in `lift`. +* We choose the definition via `LinearEquiv` instead of the axiomatization, since the latter only +classifies homogenizations over a ring. The one presented here can be adapted to semirings if affine +spaces over semirings become necessary. + +## References + +* [J. Gallier, *Geometric Methods and Applications for Computer Science and + Engineering*][Gallier2011GeometricMethods] + -/ + +public noncomputable section + +namespace Affine + +section Ring + +open Function Submodule AffineSubspace + +variable {R : Type*} [Ring R] +variable {V : Type*} [AddCommGroup V] [Module R V] +variable {P : Type*} [AddTorsor V P] +variable {W : Type*} [AddCommGroup W] [Module R W] + +variable (R P W) in +/-- A triple of a ring `R`, `R`-affine space `P` and `R`-vector space `W` is a homogenization if +`W` is linearly equivalent to the canonical homogenization. -/ +@[ext] +structure IsHomogenization where ofRepr :: + /-- The linear equivalence between the vector space and the canonical homogenization. -/ + repr : W ≃ₗ[R] Homogenization R P + +namespace IsHomogenization + +variable (ℋ : IsHomogenization R P W) + +/-- The embedding of the affine space into the homogenization. -/ +def ofPoint : P →ᵃ[R] W := ℋ.repr.symm.toAffineMap.comp Homogenization.ofPoint + +/-- The embedding of the vector space into the homogenization. -/ +def ofVector : V →ₗ[R] W := ℋ.repr.symm.toLinearMap ∘ₗ Homogenization.ofVector + +theorem ofPoint_injective : Injective ℋ.ofPoint := by + simpa [ofPoint] using Homogenization.ofPoint_injective + +theorem ofVector_injective : Injective ℋ.ofVector := by + simpa [ofVector] using Homogenization.ofVector_injective + +theorem span_range_ofPoint : span R (Set.range ℋ.ofPoint) = ⊤ := by + simpa [Set.range_comp, ofPoint] using Homogenization.span_range_ofPoint + +theorem ofPoint_injective' : Function.Injective (ofPoint : IsHomogenization R P W → P →ᵃ[R] W) := by + intro ℋ ℋ' h + apply IsHomogenization.ext + refine LinearEquiv.symm_bijective.injective <| LinearEquiv.toLinearMap_injective ?_ + apply LinearMap.ext_on_range Homogenization.span_range_ofPoint (DFunLike.congr_fun h) + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] +variable {F : Type*} [FunLike F W U] [LinearMapClass F R _ _] + +theorem hom_ext {f g : F} (h : ∀ x, f (ℋ.ofPoint x) = g (ℋ.ofPoint x)) : f = g := by + apply LinearMap.ofClass_injective + rwa [← LinearMap.cancel_right ℋ.repr.symm.surjective, Homogenization.hom_ext_iff] + +theorem hom_ext_iff {f g : F} : f = g ↔ ∀ x, f (ℋ.ofPoint x) = g (ℋ.ofPoint x) := + ⟨by rintro rfl _; rfl, ℋ.hom_ext⟩ + +end + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] + +/-- An affine map on `P` taking values in a vector space extends uniquely to a linear map on `W`. +-/ +def lift : (P →ᵃ[R] U) ≃+ (W →ₗ[R] U) := + Homogenization.lift.trans (ℋ.repr.arrowCongrAddEquiv (LinearEquiv.refl ..)).symm + +@[simp] +theorem lift_apply_ofPoint (f : P →ᵃ[R] U) (p : P) : ℋ.lift f (ℋ.ofPoint p) = f p := by + simp [lift, ofPoint] + +@[simp] +theorem lift_apply_ofVector (f : P →ᵃ[R] U) (v : V) : ℋ.lift f (ℋ.ofVector v) = f.linear v := by + simp [lift, ofVector] + +@[simp] +theorem lift_symm_apply (f : W →ₗ[R] U) (p : P) : ℋ.lift.symm f p = f (ℋ.ofPoint p) := by + simp [lift, ofPoint] + +end + +/-- The linear map that is constantly `1` when restricted to `P`. -/ +def weight : W →ₗ[R] R := Homogenization.weight ∘ₗ ℋ.repr.toLinearMap + +/-- The homogenization of a point in `P` has weight 1. -/ +@[simp] +theorem weight_ofPoint (p : P) : ℋ.weight (ℋ.ofPoint p) = 1 := by simp [weight, ofPoint] + +/-- The homogenization of a point in `V` has weight 0. -/ +@[simp] +theorem weight_ofVector (v : V) : ℋ.weight (ℋ.ofVector v) = 0 := by simp [weight, ofVector] + +theorem weight_eq_zero_iff {w : W} : ℋ.weight w = 0 ↔ ∃ v, w = ℋ.ofVector v := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofVector] using Homogenization.weight_eq_zero_iff + +theorem weight_eq_one_iff {w : W} : ℋ.weight w = 1 ↔ ∃ p, w = ℋ.ofPoint p := by + simpa [← LinearEquiv.symm_apply_eq, weight, ofPoint] using Homogenization.weight_eq_one_iff + +-- the following two are in canonical hom in #43448 +theorem ofPoint_ne_ofVector [Nontrivial R] (p : P) (v : V) : ℋ.ofPoint p ≠ ℋ.ofVector v := + ne_of_apply_ne ℋ.weight <| by simp + +theorem ofPoint_ne_zero [Nontrivial R] (p : P) : ℋ.ofPoint p ≠ 0 := by + simpa using ℋ.ofPoint_ne_ofVector p 0 + +theorem ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by + ext; simp [↓weight_eq_one_iff, eq_comm] + +theorem ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by + ext; simp [↓weight_eq_zero_iff, eq_comm] + +/-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ +theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by + apply SetLike.ext' + rw [LinearMap.coe_range, ofVector_range_eq_preimage_weight_zero, LinearMap.ker] + ext x + simp + +theorem repr_comp_ofPoint : ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by + ext a; simp [ofPoint] + +theorem weight_comp_repr : ℋ.weight ∘ₗ ℋ.repr.symm = Homogenization.weight (P := P) := by + simp [weight, LinearMap.comp_assoc] + +/-- The affine equivalence between the affine space space and its embedding. -/ +public def ofPointRangeEquiv : P ≃ᵃ[R] ℋ.ofPoint.range := + .ofBijective + ⟨ℋ.ofPoint.injective_rangeRestrict_iff.mpr ℋ.ofPoint_injective, fun ⟨_, a, rfl⟩ => ⟨a, rfl⟩⟩ + +theorem apply_ofPointRangeEquiv_symm (x : ℋ.ofPoint.range) : + ℋ.ofPoint (ℋ.ofPointRangeEquiv.symm x) = x := by + rw [← ℋ.ofPointRangeEquiv.right_inv x] + congr; exact ℋ.ofPointRangeEquiv.symm_apply_apply _ + +section + +variable {U : Type*} [AddCommGroup U] [Module R U] {f : P →ᵃ[R] U} {g : U →ₗ[R] R} + +lemma comp_lift_eq_weight (h : ∀ p, g (f p) = 1) : g ∘ₗ (ℋ.lift f) = ℋ.weight := + ℋ.hom_ext <| by simpa + +lemma lift_bijective_ohinjective_ohrange_preimage (hinj : Injective f) + (hrange : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by + have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp hrange.subset + constructor + · rw [injective_iff_map_eq_zero] + intro a ha + have : ℋ.weight a = 0 := by simp [← ℋ.comp_lift_eq_weight g_f, ha] + obtain ⟨_, rfl⟩ := ℋ.weight_eq_zero_iff.mp this + rw [ℋ.lift_apply_ofVector] at ha + simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr hinj)).mp ha] + · intro w + obtain p₀ := Classical.arbitrary P + obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by simp [hrange, g_f] + exact ⟨ℋ.ofVector (a -ᵥ p₀) + g w • ℋ.ofPoint p₀, by simp [ofPoint, ofVector, lift, ha]⟩ + +end + +section Constructions +variable (R P) in +/-- The canonical homogenization is a homogenization. -/ +@[expose] +def canonical : IsHomogenization R P (Homogenization R P) := ofRepr <| LinearEquiv.refl .. + +@[simp] +theorem ofPoint_canonical : (canonical R P).ofPoint = Homogenization.ofPoint := + (rfl) + +@[simp] +theorem ofVector_canonical : (canonical R P).ofVector = Homogenization.ofVector := + (rfl) + +@[simp] +theorem weight_canonical : (canonical R P).weight = Homogenization.weight := + (rfl) + +/-- Construct a homogenization from an embedding of the affine space `P` into the vector +space `W` and a weight map that is the constant 1-map on the embedded `P`. This follows the +axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] +https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ +def ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : IsHomogenization R P W where + repr := by + apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm + exact lift_bijective_ohinjective_ohrange_preimage (canonical R P) hinj hrange + +/-- The embedding used in the construction becomes the embedding in the homogenization. -/ +@[simp] +theorem ofPoint_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : (ofEmbed hinj hrange).ofPoint = embed := by + ext p + exact Homogenization.lift_apply_ofPoint .. + +@[simp] +theorem ofVector_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} + (hrange : embed.range = weight ⁻¹' {1}) : (ofEmbed hinj hrange).ofVector = embed.linear := by + ext p + exact Homogenization.lift_apply_ofVector .. + +/-- The weight used in the construction becomes the weight in the homogenization. -/ +@[simp] +theorem weight_ofEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) + {weight : W →ₗ[R] R} (hrange : embed.range = weight ⁻¹' {1}) : + (ofEmbed hinj hrange).weight = weight := by + refine (ofEmbed hinj hrange).hom_ext fun x => ?_ + rw [weight_ofPoint, ofPoint_ofEmbed, eq_comm] + exact congr(embed x ∈ $hrange).mp <| Set.mem_range_self x + +/-- A module is a homogenization of the weight-one hyperplane of any linear functional, +provided that hyperplane contains 1. -/ +def ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + IsHomogenization R (comap g.toAffineMap {1}) W := + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + +@[simp] +theorem ofPoint_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + (ofWeightOne h).ofPoint = (comap g.toAffineMap {1}).subtype := by + simp [ofWeightOne] + +@[simp] +theorem ofVector_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + (ofWeightOne h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by + simp [ofWeightOne] + +@[simp] +theorem weight_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : + have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h + (ofWeightOne h).weight = g := by + simp [ofWeightOne] + +end Constructions + +end IsHomogenization + +end Ring + +section Field + +namespace IsHomogenization + +open Function Submodule AffineSubspace + +variable {R : Type*} [DivisionRing R] +variable {V : Type*} [AddCommGroup V] [Module R V] +variable {P : Type*} [AddTorsor V P] +variable {W : Type*} [AddCommGroup W] [Module R W] + +/-- A module is a homogenization of the weight-one hyperplane of any nonzero linear functional. -/ +def ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + IsHomogenization R (comap g.toAffineMap {1}) W := + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + ofEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + +@[simp] +theorem ofPoint_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + (ofWeightNeZero h).ofPoint = (comap g.toAffineMap {1}).subtype := by + simp [ofWeightNeZero] + +@[simp] +theorem ofVector_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + (ofWeightNeZero h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by + simp [ofWeightNeZero] + +@[simp] +theorem weight_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : + have : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + (ofWeightNeZero h).weight = g := by + simp [ofWeightNeZero] + +end IsHomogenization + +end Field + +end Affine diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index b830599e..27c25db9 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -6,7 +6,7 @@ Authors: Martin Winter module public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Nonneg -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Basic +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization import Polyhedral.Mathlib.Data.Set.Lattice.Image import Polyhedral.Mathlib.Algebra.Order.Nonneg.Ring @@ -34,84 +34,84 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) variable {x : A} {s : Set A} -variable (R W) in -def homogenize (s : Set A) : SubMulAction₀ R≥0 W := R≥0 ∙ (hom.ofPoint '' s) +def homogenize (s : Set A) : SubMulAction₀ R≥0 W := R≥0 ∙ (ℋ.ofPoint '' s) -- potential notations for homogenization: `R≥0 ∙[W] s` or `R ∙₊[W] s` -- -- /- Note that the character `∙` U+2219 used below is different from the scalar multiplication -- character `•` U+2022. -/ --- /-- Notation for the homogenizationof a set `s`, short for `homogenize R W s`. -/ --- scoped notation:70 R:70 " ∙[" W "] " s:70 => homogenize R W s +-- /-- Notation for the homogenizationof a set `s`, short for `homogenize ℋ s`. -/ +-- scoped notation:70 R:70 " ∙[" W "] " s:70 => homogenize ℋ s lemma mem_homogenize {s : Set A} {x : W} : - x ∈ homogenize R W s ↔ x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize ℋ s ↔ x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • ℋ.ofPoint y := by simp [homogenize, mem_smulSet] -lemma mem_homogenize_iff_exist_lt_zero {s : Set A} {x : W} (hx : x ∈ homogenize R W s) : - x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 < r ∧ x = r • hom.ofPoint y := by +variable {ℋ} in +lemma mem_homogenize_iff_exist_lt_zero {s : Set A} {x : W} (hx : x ∈ homogenize ℋ s) : + x = 0 ∨ ∃ y ∈ s, ∃ r : R, 0 < r ∧ x = r • ℋ.ofPoint y := by obtain (rfl | ⟨y, ⟨z, hz, rfl⟩, _, ⟨r, _⟩, hr0, rfl⟩) := mem_smulSet_iff_exists_ne_zero hx · exact .inl rfl · exact .inr ⟨z, hz, r, by rwa [← zero_lt_iff] at hr0, rfl⟩ lemma mem_homogenize_iff_ne_zero {s : Set A} {x : W} (hx : x ≠ 0) : - x ∈ homogenize R W s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by + x ∈ homogenize ℋ s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • ℋ.ofPoint y := by simp [homogenize, mem_smulSet_of_ne_zero hx] lemma mem_homogenize_iff_nonempty {s : Set A} {x : W} (hs : s.Nonempty) : - x ∈ homogenize R W s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • hom.ofPoint y := by - have : (hom.ofPoint '' s).Nonempty := Set.image_nonempty.mpr hs + x ∈ homogenize ℋ s ↔ ∃ y ∈ s, ∃ r : R, 0 ≤ r ∧ x = r • ℋ.ofPoint y := by + have : (ℋ.ofPoint '' s).Nonempty := Set.image_nonempty.mpr hs simp [homogenize, mem_smulSet_of_nonempty this] -@[simp] lemma homogenize_empty : homogenize R W (∅ : Set A) = ⊥ := by +@[simp] lemma homogenize_empty : homogenize ℋ (∅ : Set A) = ⊥ := by ext x; simp [homogenize] -lemma ofPoint_image_subset_homogenize : hom.ofPoint '' s ⊆ homogenize R W s := +lemma ofPoint_image_subset_homogenize : ℋ.ofPoint '' s ⊆ homogenize ℋ s := subset_smulSet -lemma ofPoint_mem_homogenize (hx : x ∈ s) : hom.ofPoint x ∈ homogenize R W s := - ofPoint_image_subset_homogenize ⟨x, hx, rfl⟩ +lemma ofPoint_mem_homogenize (hx : x ∈ s) : ℋ.ofPoint x ∈ homogenize ℋ s := + ofPoint_image_subset_homogenize _ ⟨x, hx, rfl⟩ lemma smul_ofPoint_mem_homogenize {r : R} (hr : 0 ≤ r) (h : x ∈ s) : - r • hom.ofPoint x ∈ homogenize R W s := - smul_mem _ ⟨r, hr⟩ (ofPoint_mem_homogenize h) + r • ℋ.ofPoint x ∈ homogenize ℋ s := + smul_mem _ ⟨r, hr⟩ (ofPoint_mem_homogenize _ h) -lemma homogenize_mono {s t : Set A} (h : s ⊆ t) : homogenize R W s ≤ homogenize R W t := +lemma homogenize_mono {s t : Set A} (h : s ⊆ t) : homogenize ℋ s ≤ homogenize ℋ t := smulSet_mono <| Set.image_mono h -lemma homogenize_monotone : Monotone (homogenize R W : Set A → SubMulAction₀ R≥0 W) := - fun _ _ => homogenize_mono +lemma homogenize_monotone : Monotone (homogenize ℋ : Set A → SubMulAction₀ R≥0 W) := + fun _ _ => homogenize_mono _ /-- Homogenization from sets to `SubMulAction₀` as an order homomorphism. -/ def homogenizeOrderHom : Set A →o SubMulAction₀ R≥0 W where - toFun := homogenize R W - monotone' := homogenize_monotone + toFun := homogenize ℋ + monotone' := homogenize_monotone _ lemma homogenize_union (s t : Set A) : - homogenize R W (s ∪ t) = homogenize R W s ⊔ homogenize R W t := by + homogenize ℋ (s ∪ t) = homogenize ℋ s ⊔ homogenize ℋ t := by simp only [homogenize, Set.image_union, smulSet_union] lemma homogenize_inter_le (s t : Set A) : - homogenize R W (s ∩ t) ≤ homogenize R W s ⊓ homogenize R W t := by + homogenize ℋ (s ∩ t) ≤ homogenize ℋ s ⊓ homogenize ℋ t := by unfold homogenize - rw [Set.image_inter hom.ofPoint_injective] + rw [Set.image_inter ℋ.ofPoint_injective] exact smulSet_inter_le _ _ lemma homogenize_sSup (S : Set (Set A)) : - homogenize R W (sSup S) = sSup (homogenize R W '' S) := by + homogenize ℋ (sSup S) = sSup (homogenize ℋ '' S) := by unfold homogenize rw [Set.image_sSup, smulSet_sSup, Set.image_image] def homogenizeSSupHom : sSupHom (Set A) (SubMulAction₀ R≥0 W) where - toFun := homogenize R W - map_sSup' := homogenize_sSup + toFun := homogenize ℋ + map_sSup' := homogenize_sSup _ lemma homogenize_sInf_le (S : Set (Set A)) : - homogenize R W (sInf S) ≤ sInf (homogenize R W '' S) := by + homogenize ℋ (sInf S) ≤ sInf (homogenize ℋ '' S) := by unfold homogenize apply le_trans <| smulSet_mono (Set.image_sInter_subset_sInf_image _ _) apply le_trans (smulSet_sInf_le _) @@ -122,42 +122,42 @@ section Nontrivial variable [Nontrivial R] @[simp] lemma ofPoint_mem_homogenize_iff {x : A} {s : Set A} : - hom.ofPoint x ∈ homogenize R W s ↔ x ∈ s where + ℋ.ofPoint x ∈ homogenize ℋ s ↔ x ∈ s where mp := by rintro (h | ⟨x, ⟨y, hy, rfl⟩, r, h⟩) - · exfalso; exact ofPoint_ne_zero _ h - · have := congrArg hom.weight h - simp only [weight_one, ← Nonneg.coe_smul, map_smul, smul_eq_mul, mul_one, + · exfalso; exact ofPoint_ne_zero _ _ h + · have := congrArg ℋ.weight h + simp only [weight_ofPoint, ← Nonneg.coe_smul, map_smul, smul_eq_mul, mul_one, Eq.comm, Nonneg.coe_eq_one] at this rw [this, one_smul] at h - rwa [hom.ofPoint_injective h] - mpr := ofPoint_mem_homogenize + rwa [ℋ.ofPoint_injective h] + mpr := ofPoint_mem_homogenize _ lemma ofPoint_mem_homogenize_singleton {x y : A} : - hom.ofPoint x ∈ homogenize R W {y} ↔ x = y := by simp + ℋ.ofPoint x ∈ homogenize ℋ {y} ↔ x = y := by simp lemma homogenize_injective : - Injective (homogenize R W : Set A → SubMulAction₀ R≥0 W) := by + Injective (homogenize ℋ : Set A → SubMulAction₀ R≥0 W) := by intro s t h; ext repeat rw [← ofPoint_mem_homogenize_iff (R := R) (W := W)] rw [h] -@[simp] lemma homogenize_inj {s t : Set A} : homogenize R W s = homogenize R W t ↔ s = t := - homogenize_injective.eq_iff +@[simp] lemma homogenize_inj {s t : Set A} : homogenize ℋ s = homogenize ℋ t ↔ s = t := + (homogenize_injective _).eq_iff -lemma homogenize_strictMono : StrictMono (homogenize R W : Set A → SubMulAction₀ R≥0 W) := - homogenize_monotone.strictMono_of_injective homogenize_injective +lemma homogenize_strictMono : StrictMono (homogenize ℋ : Set A → SubMulAction₀ R≥0 W) := + (homogenize_monotone _).strictMono_of_injective (homogenize_injective _) lemma homogenize_mono_iff {s t : Set A} : - homogenize R W s ≤ homogenize R W t ↔ s ⊆ t where + homogenize ℋ s ≤ homogenize ℋ t ↔ s ⊆ t where mp := by intro h x hx rw [← ofPoint_mem_homogenize_iff (R := R) (W := W)] at ⊢ hx exact h hx - mpr := homogenize_mono + mpr := homogenize_mono _ lemma homogenize_singleton_eq {x y : A} : - homogenize R W {x} = homogenize R W {y} ↔ x = y := by simp + homogenize ℋ {x} = homogenize ℋ {y} ↔ x = y := by simp end Nontrivial @@ -170,44 +170,43 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) variable {x : A} {s : Set A} -variable (A) in def _root_.SubMulAction₀.dehomogenize (S : SubMulAction₀ R≥0 W) : Set A := - hom.ofPoint ⁻¹' S + ℋ.ofPoint ⁻¹' S lemma dehomogenize_mono {S T : SubMulAction₀ R≥0 W} (h : S ≤ T) : - dehomogenize A S ≤ dehomogenize A T := + dehomogenize ℋ S ≤ dehomogenize ℋ T := Set.preimage_mono h -lemma dehomogenize_monotone : Monotone (dehomogenize A : SubMulAction₀ R≥0 W → Set A) := - fun _ _ => dehomogenize_mono +lemma dehomogenize_monotone : Monotone (dehomogenize ℋ : SubMulAction₀ R≥0 W → Set A) := + fun _ _ => dehomogenize_mono _ /-- Homogenization from sets to `SubMulAction₀` as an order homomorphism. -/ def dehomogenizeOrderHom : SubMulAction₀ R≥0 W →o Set A where - toFun := dehomogenize A - monotone' := dehomogenize_monotone + toFun := dehomogenize ℋ + monotone' := dehomogenize_monotone _ -lemma dehomogenize_top : dehomogenize A (⊤ : SubMulAction₀ R≥0 W) = Set.univ := by +lemma dehomogenize_top : dehomogenize ℋ (⊤ : SubMulAction₀ R≥0 W) = Set.univ := by ext x; simp [dehomogenize] lemma dehomogenize_inf (s t : SubMulAction₀ R≥0 W) : - dehomogenize A (s ⊓ t) = dehomogenize A s ∩ dehomogenize A t := by + dehomogenize ℋ (s ⊓ t) = dehomogenize ℋ s ∩ dehomogenize ℋ t := by ext x; simp [dehomogenize] lemma dehomogenize_sup (s t : SubMulAction₀ R≥0 W) : - dehomogenize A (s ⊔ t) = dehomogenize A s ∪ dehomogenize A t := by + dehomogenize ℋ (s ⊔ t) = dehomogenize ℋ s ∪ dehomogenize ℋ t := by ext x; simp [dehomogenize] def dehomogenizeLatticeHom : LatticeHom (SubMulAction₀ R≥0 W) (Set A) where - toFun := dehomogenize A - map_sup' := dehomogenize_sup - map_inf' := dehomogenize_inf + toFun := dehomogenize ℋ + map_sup' := dehomogenize_sup _ + map_inf' := dehomogenize_inf _ lemma dehomogenize_sInf (S : Set (SubMulAction₀ R≥0 W)) : - dehomogenize A (sInf S) = sInf (dehomogenize A '' S) := by + dehomogenize ℋ (sInf S) = sInf (dehomogenize ℋ '' S) := by ext x; simp [dehomogenize] section Nontrivial @@ -215,27 +214,27 @@ section Nontrivial variable [Nontrivial R] lemma dehomogenize_sSup (S : Set (SubMulAction₀ R≥0 W)) : - dehomogenize A (sSup S) = sSup (dehomogenize A '' S) := by - ext x; simpa [dehomogenize] using fun h => (ofPoint_ne_zero x h).elim + dehomogenize ℋ (sSup S) = sSup (dehomogenize ℋ '' S) := by + ext x; simpa [dehomogenize] using fun h => (ofPoint_ne_zero _ x h).elim def dehomogenizeCompleteLatticeHom : CompleteLatticeHom (SubMulAction₀ R≥0 W) (Set A) where - toFun := dehomogenize A - map_sInf' := dehomogenize_sInf - map_sSup' := dehomogenize_sSup + toFun := dehomogenize ℋ + map_sInf' := dehomogenize_sInf _ + map_sSup' := dehomogenize_sSup _ -@[simp] lemma dehomogenize_bot : (⊥ : SubMulAction₀ R≥0 W).dehomogenize A = ∅ := by - ext x; simp only [Set.mem_empty_iff_false, iff_false]; exact ofPoint_ne_zero _ +@[simp] lemma dehomogenize_bot : (⊥ : SubMulAction₀ R≥0 W).dehomogenize ℋ = ∅ := by + ext x; simp only [Set.mem_empty_iff_false, iff_false]; exact ofPoint_ne_zero _ _ variable [IsOrderedRing R] in /-- Dehomogenizing the homogenization of a set yields the same set again. -/ @[simp] theorem dehomogenize_homogenize (s : Set A) : - dehomogenize A (homogenize R W s) = s := by + dehomogenize ℋ (homogenize ℋ s) = s := by ext x; simp [dehomogenize] end Nontrivial variable [IsOrderedRing R] in -lemma homogenize_gc : GaloisConnection (homogenize R W) (dehomogenize A) := +lemma homogenize_gc : GaloisConnection (homogenize ℋ) (dehomogenize ℋ) := .compose Set.image_preimage smulSet_gc end Ring_no_OrderedRing @@ -247,32 +246,32 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) @[simp] lemma dehomogenize_weight_positive : - dehomogenize A (hom.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by - ext x; simp [dehomogenize, weight_one] + dehomogenize ℋ (ℋ.weight.positive : SubMulAction₀ R≥0 W) = Set.univ := by + ext x; simp [dehomogenize, weight_ofPoint] lemma nonneg_smulSet_ofPoint_range_le_weight_positive : - R≥0 ∙ (Set.range hom.ofPoint) ≤ hom.weight.positive := by + R≥0 ∙ (Set.range ℋ.ofPoint) ≤ ℋ.weight.positive := by rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : - homogenize R W (Set.univ : Set A) ≤ hom.weight.positive := by - simpa [homogenize] using nonneg_smulSet_ofPoint_range_le_weight_positive + homogenize ℋ (Set.univ : Set A) ≤ ℋ.weight.positive := by + simpa [homogenize] using nonneg_smulSet_ofPoint_range_le_weight_positive _ lemma homogenize_le_weight_positive (s : Set A) : - homogenize R W s ≤ hom.weight.positive := - le_trans (homogenize_mono (Set.subset_univ _)) homogenize_univ_le_weight_positive + homogenize ℋ s ≤ ℋ.weight.positive := + le_trans (homogenize_mono _ (Set.subset_univ _)) (homogenize_univ_le_weight_positive _) @[simp] theorem homogenize_dehomogenize_le_weight_positive {S : SubMulAction₀ R≥0 W} : - homogenize R W (S.dehomogenize A) ≤ S ⊓ hom.weight.positive := by - have aux : Set.range hom.ofPoint = hom.ofPoint.range := rfl + homogenize ℋ (S.dehomogenize ℋ) ≤ S ⊓ ℋ.weight.positive := by + have aux : Set.range ℋ.ofPoint = ℋ.ofPoint.range := rfl rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, aux] refine le_trans (smulSet_inter_le _ _) ?_ simp only [smulSet_eq, le_inf_iff, inf_le_left, true_and] - exact le_trans inf_le_right nonneg_smulSet_ofPoint_range_le_weight_positive + exact le_trans inf_le_right (nonneg_smulSet_ofPoint_range_le_weight_positive _) end IsStrictOrderedRing @@ -283,49 +282,49 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] [Module.IsTorsionFree R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) /-- For the weaker version with `r = 1` see `ofPoint_mem_homogenize_iff`. -/ @[simp] lemma smul_ofPoint_mem_homogenize_iff {r : R} (hr : 0 < r) {x : A} (s : Set A) : - r • hom.ofPoint x ∈ homogenize R W s ↔ x ∈ s where + r • ℋ.ofPoint x ∈ homogenize ℋ s ↔ x ∈ s where mp := by rintro (h | ⟨x, ⟨y, hy, rfl⟩, ⟨r', hr'⟩, h⟩) · exfalso - exact smul_ne_zero hr.ne.symm (ofPoint_ne_zero x) h - · have := congrArg hom.weight h - simp only [map_smul, weight_one, smul_eq_mul, mul_one, Nonneg.mk_smul] at this + exact smul_ne_zero hr.ne.symm (ofPoint_ne_zero _ x) h + · have := congrArg ℋ.weight h + simp only [map_smul, weight_ofPoint, smul_eq_mul, mul_one, Nonneg.mk_smul] at this rw [this] at hr h - rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, ofPoint_injective.eq_iff] at h + rw [Nonneg.mk_smul, smul_right_inj hr.ne.symm, ℋ.ofPoint_injective.eq_iff] at h rwa [h] - mpr := smul_ofPoint_mem_homogenize hr.le + mpr := smul_ofPoint_mem_homogenize _ hr.le lemma homogenize_inter (s t : Set A) : - homogenize R W (s ∩ t) = homogenize R W s ⊓ homogenize R W t := by + homogenize ℋ (s ∩ t) = homogenize ℋ s ⊓ homogenize ℋ t := by apply le_antisymm - · exact homogenize_inter_le s t + · exact homogenize_inter_le _ s t · rintro x hx obtain (rfl | ⟨y, hys, r, hr, rfl⟩) := mem_homogenize_iff_exist_lt_zero hx.1 · exact SubMulAction₀.zero_mem - refine smul_ofPoint_mem_homogenize hr.le ⟨hys, ?_⟩ - exact (smul_ofPoint_mem_homogenize_iff hr t).mp hx.2 + refine smul_ofPoint_mem_homogenize _ hr.le ⟨hys, ?_⟩ + exact (smul_ofPoint_mem_homogenize_iff _ hr t).mp hx.2 /-- Homogenization from sets to `SubMulAction₀` as a lattice homomorphism. -/ def homogenizeLatticeHom : LatticeHom (Set A) (SubMulAction₀ R≥0 W) where - toFun := homogenize R W - map_sup' := homogenize_union - map_inf' := homogenize_inter + toFun := homogenize ℋ + map_sup' := homogenize_union _ + map_inf' := homogenize_inter _ lemma homogenize_sInf {S : Set (Set A)} (hS : S.Nonempty) : - homogenize R W (sInf S) = sInf (homogenize R W '' S) := by + homogenize ℋ (sInf S) = sInf (homogenize ℋ '' S) := by apply le_antisymm - · exact homogenize_sInf_le S + · exact homogenize_sInf_le _ S intro x hx simp only [SetLike.mem_sInf, Set.mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] at hx obtain (rfl | ⟨y, hys, r, hr, rfl⟩) := mem_homogenize_iff_exist_lt_zero (hx _ hS.choose_spec) · exact SubMulAction₀.zero_mem - exact smul_ofPoint_mem_homogenize hr.le fun t ht => - (smul_ofPoint_mem_homogenize_iff hr t).mp (hx _ ht) + exact smul_ofPoint_mem_homogenize _ hr.le fun t ht => + (smul_ofPoint_mem_homogenize_iff _ hr t).mp (hx _ ht) end IsCancelMulZero_IsTorsionFree @@ -336,15 +335,15 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : - R≥0 ∙ (Set.range hom.ofPoint) = hom.weight.positive := by + R≥0 ∙ (Set.range ℋ.ofPoint) = ℋ.weight.positive := by rw [ofPoint_range_eq_preimage_weight_one] exact nonneg_smulSet_preimage_one_eq_positive _ -@[simp] lemma homogenize_univ : homogenize R W (Set.univ : Set A) = hom.weight.positive := by - simpa [homogenize] using nonneg_smulSet_ofPoint_range +@[simp] lemma homogenize_univ : homogenize ℋ (Set.univ : Set A) = ℋ.weight.positive := by + simpa [homogenize] using nonneg_smulSet_ofPoint_range _ end DivisionRing @@ -355,23 +354,24 @@ variable [AddCommGroup V] [Module R V] variable [AddTorsor V A] variable [AddCommGroup W] [Module R W] -variable [hom : IsHomogenization R A W] +variable (ℋ : IsHomogenization R A W) @[simp] theorem homogenize_dehomogenize {S : SubMulAction₀ R≥0 W} : - homogenize R W (S.dehomogenize A) = S ⊓ hom.weight.positive := by + homogenize ℋ (S.dehomogenize ℋ) = S ⊓ ℋ.weight.positive := by rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, smulSet_inter_left, nonneg_smulSet_ofPoint_range] +variable {ℋ} in @[simp] theorem homogenize_dehomogenize_of_le_weight_positive {S : SubMulAction₀ R≥0 W} - (hS : S ≤ hom.weight.positive) : homogenize R W (S.dehomogenize A) = S := by + (hS : S ≤ ℋ.weight.positive) : homogenize ℋ (S.dehomogenize ℋ) = S := by simp [homogenize_dehomogenize, hS] -def homogenizeOrderIso : Set A ≃o Set.Iic (hom.weight.positive : SubMulAction₀ R≥0 W) where - toFun s := ⟨_, homogenize_le_weight_positive s⟩ - invFun S := S.1.dehomogenize A - left_inv := dehomogenize_homogenize +def homogenizeOrderIso : Set A ≃o Set.Iic (ℋ.weight.positive : SubMulAction₀ R≥0 W) where + toFun s := ⟨_, homogenize_le_weight_positive _ s⟩ + invFun S := S.1.dehomogenize ℋ + left_inv := dehomogenize_homogenize _ right_inv S := by simp only [homogenize_dehomogenize_of_le_weight_positive S.2] - map_rel_iff' := homogenize_mono_iff + map_rel_iff' := homogenize_mono_iff _ end LinearOrderDivisionRing From a4f97c9fc4228ca32ee6ed9002a523eac604f24f Mon Sep 17 00:00:00 2001 From: ooovi <79147175+ooovi@users.noreply.github.com> Date: Wed, 7 Oct 2026 17:25:20 +0200 Subject: [PATCH 23/39] nit --- .../Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean index 815bad5e..19b879aa 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean @@ -7,7 +7,6 @@ module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Basic public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Hull --- public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Module @@ -37,11 +36,6 @@ lemma isConvexSet (P : PointedCone R M) : IsConvexSet R (P : Set M) := by refine P.finsuppSum_mem _ _ (fun i r ↦ r • i) (fun c hc ↦ ?_) exact P.smul_mem (w.weights_nonneg c) <| hw (Finsupp.mem_support_iff.mpr hc) --- @[coe] --- def toConvexSet (P : PointedCone R M) : ConvexSet R M := ⟨_, P.isConvexSet⟩ - --- instance : Coe (PointedCone R M) (ConvexSet R M) := ⟨toConvexSet⟩ - @[simp] theorem hull_convexHull (t : Set M) : hull R (Convexity.convexHull R t) = hull R t := by apply le_antisymm From 8f0823f6cfb2fdf3a001a7da37c7892a021fc1a0 Mon Sep 17 00:00:00 2001 From: ooovi <79147175+ooovi@users.noreply.github.com> Date: Wed, 7 Oct 2026 17:26:39 +0200 Subject: [PATCH 24/39] nit --- .../Geometry/Convex/ConvexSpace/Polytope/Lattice.lean | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean index 0c3b6ecd..e1c12558 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Lattice.lean @@ -5,7 +5,6 @@ Authors: Martin Winter, Olivia Röhrig -/ module --- public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Pointwise public import Polyhedral.Mathlib.Data.SetLike.IsConcrete public import Polyhedral.Mathlib.Algebra.Group.Pointwise.SetLike.Basic @@ -55,9 +54,6 @@ variable (P) in @[simp] theorem mk_eq {s h} : (⟨s, h⟩ : Polytope R X) = s := by ext; simp --- instance : Coe (Polytope R X) (ConvexSet R X) where --- coe P := ⟨P, P.isPolytope.isConvexSet⟩ - /- # LE -/ instance : PartialOrder (Polytope R X) := .ofSetLike .. @@ -165,8 +161,6 @@ instance : Neg (Polytope R X) where instance : IsConcreteNeg (Polytope R X) X := ⟨fun _ => rfl⟩ --- instance : InvolutiveNeg (ConvexSet R X) := .ofSetLike .. - /-! ### Minkowski addition -/ instance : Add (Polytope R X) where From 9b66d86d5014234c49941d1db3a93f980543fc95 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 7 Oct 2026 22:53:23 +0200 Subject: [PATCH 25/39] typo --- .../AffineSpace/Homogenization/IsHomogenization.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index d690aff7..06e7ca9a 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -172,7 +172,7 @@ variable {U : Type*} [AddCommGroup U] [Module R U] {f : P →ᵃ[R] U} {g : U lemma comp_lift_eq_weight (h : ∀ p, g (f p) = 1) : g ∘ₗ (ℋ.lift f) = ℋ.weight := ℋ.hom_ext <| by simpa -lemma lift_bijective_ohinjective_ohrange_preimage (hinj : Injective f) +lemma lift_bijective_injective_range_preimage (hinj : Injective f) (hrange : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp hrange.subset constructor @@ -215,7 +215,7 @@ def ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W (hrange : embed.range = weight ⁻¹' {1}) : IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm - exact lift_bijective_ohinjective_ohrange_preimage (canonical R P) hinj hrange + exact lift_bijective_injective_range_preimage (canonical R P) hinj hrange /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] From 6a0aff819e0ad55b811a02564bfa6d75300fab96 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 9 Oct 2026 10:30:57 +0200 Subject: [PATCH 26/39] own lemma for nonempty --- .../AffineSpace/AffineSubspace/Basic.lean | 23 +++++++++++++ .../Homogenization/IsHomogenization.lean | 32 ++++++++----------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean index 720b29ba..7d34e4ca 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean @@ -7,6 +7,7 @@ module public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic public import Polyhedral.Mathlib.Algebra.Group.Pointwise.SetLike.Basic +import Mathlib.RingTheory.SimpleModule.Basic /-! This file adds features for affine spaces. @@ -62,4 +63,26 @@ instance : Neg (AffineSubspace R V) where instance : IsConcreteNeg (AffineSubspace R V) V := ⟨fun _ => rfl⟩ +lemma nonempty_comap_of_nonempty_of_surjective {E : AffineSubspace R R} (hE : (E : Set R).Nonempty) + {g : V →ₗ[R] R} (hg : Function.Surjective g) : Nonempty (E.comap g.toAffineMap) := by + obtain ⟨e, he⟩ := hE + obtain ⟨_, rfl⟩ := hg e + exact ⟨_, AffineSubspace.mem_comap.mpr he⟩ + end Module + +section DivisionRing + +open AffineSubspace + +variable {R : Type*} [DivisionRing R] +variable {V : Type*} [AddCommGroup V] [Module R V] + +variable {g : V →ₗ[R] R} + +lemma comap_nonempty_of_ne_zero (h : g ≠ 0) : Nonempty (comap g.toAffineMap {1}) := by + obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h + apply nonempty_comap_of_nonempty_of_surjective (Set.singleton_nonempty 1) + exact g.surjective_of_ne_zero h + +end DivisionRing diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 06e7ca9a..85f2c844 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -9,6 +9,8 @@ public import Mathlib.LinearAlgebra.AffineSpace.AffineMap public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range public import Mathlib.LinearAlgebra.AffineSpace.Homogenization +public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic + /-! This file defines affine homogenization as any vector space linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. It also proves every object that satisfies the axiomatic description from [Gallier2011GeometricMethods] is a homogenization @@ -281,36 +283,28 @@ variable {V : Type*} [AddCommGroup V] [Module R V] variable {P : Type*} [AddTorsor V P] variable {W : Type*} [AddCommGroup W] [Module R W] +variable {g : W →ₗ[R] R} (h : g ≠ 0) + /-- A module is a homogenization of the weight-one hyperplane of any nonzero linear functional. -/ -def ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : - have : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h - exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ +def ofWeightNeZero : + have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h IsHomogenization R (comap g.toAffineMap {1}) W := - have : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h - exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ + have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) -theorem ofPoint_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : - have : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h - exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ +theorem ofPoint_ofWeightNeZero : + have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h (ofWeightNeZero h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightNeZero] -theorem ofVector_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : - have : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h - exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ +theorem ofVector_ofWeightNeZero : + have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h (ofWeightNeZero h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightNeZero] @[simp] -theorem weight_ofWeightNeZero {g : W →ₗ[R] R} (h : g ≠ 0) : - have : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h - exact ⟨(g y)⁻¹ • y, by simp [hy]⟩ +theorem weight_ofWeightNeZero : + have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h (ofWeightNeZero h).weight = g := by simp [ofWeightNeZero] From 254e0a37d91f6deb3b73c3d15e15170ff1593e2a Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 9 Oct 2026 11:01:59 +0200 Subject: [PATCH 27/39] using AffineMap.range --- .../Homogenization/IsHomogenization.lean | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 85f2c844..f3740f0d 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -214,21 +214,23 @@ space `W` and a weight map that is the constant 1-map on the embedded `P`. This axiomatization in Definition 4.2 of [Gallier2011GeometricMethods] https://www.cis.upenn.edu/~jean/gma-v2-root.pdf -/ def ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} - (hrange : embed.range = weight ⁻¹' {1}) : IsHomogenization R P W where + (hrange : embed.range = comap weight.toAffineMap {1}) : IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm - exact lift_bijective_injective_range_preimage (canonical R P) hinj hrange + have : embed.range = weight ⁻¹' {1} := by ext; simp [hrange] + exact lift_bijective_injective_range_preimage (canonical R P) hinj this /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] theorem ofPoint_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} - (hrange : embed.range = weight ⁻¹' {1}) : (ofWeightEmbed hinj hrange).ofPoint = embed := by + (hrange : embed.range = comap weight.toAffineMap {1}) : + (ofWeightEmbed hinj hrange).ofPoint = embed := by ext p exact Homogenization.lift_apply_ofPoint .. @[simp] theorem ofVector_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W →ₗ[R] R} - (hrange : embed.range = weight ⁻¹' {1}) : + (hrange : embed.range = comap weight.toAffineMap {1}) : (ofWeightEmbed hinj hrange).ofVector = embed.linear := by ext p exact Homogenization.lift_apply_ofVector .. @@ -236,7 +238,7 @@ theorem ofVector_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) /-- The weight used in the construction becomes the weight in the homogenization. -/ @[simp] theorem weight_ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) - {weight : W →ₗ[R] R} (hrange : embed.range = weight ⁻¹' {1}) : + {weight : W →ₗ[R] R} (hrange : embed.range = comap weight.toAffineMap {1}) : (ofWeightEmbed hinj hrange).weight = weight := by refine (ofWeightEmbed hinj hrange).hom_ext fun x => ?_ rw [weight_ofPoint, ofPoint_ofWeightEmbed, eq_comm] @@ -248,7 +250,7 @@ def ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h IsHomogenization R (comap g.toAffineMap {1}) W := have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h - ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by ext; simp) theorem ofPoint_ofWeightOne {g : W →ₗ[R] R} (h : 1 ∈ g.range) : have : Nonempty (comap g.toAffineMap {1}) := nonempty_subtype.mpr <| g.mem_range.mp h @@ -290,7 +292,7 @@ def ofWeightNeZero : have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h IsHomogenization R (comap g.toAffineMap {1}) W := have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h - ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by simp; rfl) + ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by ext; simp) theorem ofPoint_ofWeightNeZero : have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h From 0678828a65d3b00e306a30784c92528aebc03f5e Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 9 Oct 2026 14:25:48 +0200 Subject: [PATCH 28/39] using range --- .../AffineSpace/AffineSubspace/Range.lean | 4 ++++ .../Homogenization/IsHomogenization.lean | 20 ++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean index 009a85e0..cd20e131 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean @@ -64,6 +64,10 @@ theorem range_id : (id R P₁).range = ⊤ := by ext; simp theorem range_direction_eq_linear_range : f.range.direction = f.linear.range := by rw [range_eq_map_top, map_direction, direction_top, Submodule.map_top] +variable {f} in +theorem range_subset_iff {s : AffineSubspace R P₂} : f.range ≤ s ↔ ∀ y, f y ∈ s := by + simp [AffineSubspace.le_def'] + /-- Restrict the codomain of an affine map `f` to `f.range`. -/ def rangeRestrict : P₁ →ᵃ[R] f.range where toFun p := ⟨f p, p, rfl⟩ diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index f3740f0d..e93098b4 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -138,18 +138,15 @@ theorem ofPoint_ne_ofVector [Nontrivial R] (p : P) (v : V) : ℋ.ofPoint p ≠ theorem ofPoint_ne_zero [Nontrivial R] (p : P) : ℋ.ofPoint p ≠ 0 := by simpa using ℋ.ofPoint_ne_ofVector p 0 -theorem ofPoint_range_eq_preimage_weight_one : Set.range ℋ.ofPoint = ℋ.weight ⁻¹' {1} := by +theorem ofPoint_range_eq_comap_weight_one : ℋ.ofPoint.range = comap ℋ.weight.toAffineMap {1} := by ext; simp [↓weight_eq_one_iff, eq_comm] -theorem ofVector_range_eq_preimage_weight_zero : Set.range ℋ.ofVector = ℋ.weight ⁻¹' {0} := by +theorem ofVector_range_eq_comap_weight_zero : ℋ.ofVector.range = Submodule.comap ℋ.weight ⊥ := by ext; simp [↓weight_eq_zero_iff, eq_comm] /-- Embedding the underlying vector space is exactly the weight-0 hyperplane. -/ theorem ofVector_range_eq_weight_ker : ℋ.ofVector.range = ℋ.weight.ker := by - apply SetLike.ext' - rw [LinearMap.coe_range, ofVector_range_eq_preimage_weight_zero, LinearMap.ker] - ext x - simp + rw [ofVector_range_eq_comap_weight_zero, LinearMap.ker] theorem repr_comp_ofPoint : ℋ.repr ∘ ℋ.ofPoint = Homogenization.ofPoint := by ext a; simp [ofPoint] @@ -174,9 +171,9 @@ variable {U : Type*} [AddCommGroup U] [Module R U] {f : P →ᵃ[R] U} {g : U lemma comp_lift_eq_weight (h : ∀ p, g (f p) = 1) : g ∘ₗ (ℋ.lift f) = ℋ.weight := ℋ.hom_ext <| by simpa -lemma lift_bijective_injective_range_preimage (hinj : Injective f) - (hrange : Set.range f = g ⁻¹' {1}) : Bijective (ℋ.lift f) := by - have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp hrange.subset +lemma lift_bijective_injective_range_comap (hinj : Injective f) + (hrange : f.range = comap g.toAffineMap {1}) : Bijective (ℋ.lift f) := by + have g_f : ∀ p, g (f p) = 1 := AffineMap.range_subset_iff.mp hrange.le constructor · rw [injective_iff_map_eq_zero] intro a ha @@ -186,7 +183,7 @@ lemma lift_bijective_injective_range_preimage (hinj : Injective f) simp [(map_eq_zero_iff _ (f.linear_injective_iff.mpr hinj)).mp ha] · intro w obtain p₀ := Classical.arbitrary P - obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ Set.range f := by simp [hrange, g_f] + obtain ⟨a, ha⟩ : w - g w • f p₀ + f p₀ ∈ f.range := by simp [hrange, g_f] exact ⟨ℋ.ofVector (a -ᵥ p₀) + g w • ℋ.ofPoint p₀, by simp [ofPoint, ofVector, lift, ha]⟩ end @@ -217,8 +214,7 @@ def ofWeightEmbed {embed : P →ᵃ[R] W} (hinj : Injective embed) {weight : W (hrange : embed.range = comap weight.toAffineMap {1}) : IsHomogenization R P W where repr := by apply (LinearEquiv.ofBijective (Homogenization.lift embed) ?_).symm - have : embed.range = weight ⁻¹' {1} := by ext; simp [hrange] - exact lift_bijective_injective_range_preimage (canonical R P) hinj this + exact lift_bijective_injective_range_comap (canonical R P) hinj hrange /-- The embedding used in the construction becomes the embedding in the homogenization. -/ @[simp] From b7de21f928b397ce9e2583623364939fc6524984 Mon Sep 17 00:00:00 2001 From: ovi Date: Fri, 9 Oct 2026 16:40:02 +0200 Subject: [PATCH 29/39] fix --- .../Convex/ConvexSpace/Set/Homogenization.lean | 10 ++++++---- .../LinearAlgebra/AffineSpace/Homogenization/Set.lean | 7 +++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 9e3debec..1e97a99d 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -169,8 +169,9 @@ variable (ℋ : Affine.IsHomogenization R A W) /-- The homogenization of the full affine space is the positive cone of the weight functional. -/ lemma homogenize_top : homogenize ℋ (⊤ : ConvexSet R A) = ℋ.weight.positive := by + have : ℋ.weight ⁻¹' {1} = AffineSubspace.comap ℋ.weight.toAffineMap {1} := rfl rw [homogenize, LinearMap.positive_eq_hull_preimage_singleton ℋ.weight one_pos, - ← ℋ.ofPoint_range_eq_preimage_weight_one] + this, ← ℋ.ofPoint_range_eq_comap_weight_one] congr! with x simp @@ -215,15 +216,16 @@ theorem homogenize_dehomogenize_of_le_positive {C : PointedCone R W} · simp [hbot, homogenize, dehomogenize] · apply SetLike.ext' unfold homogenize + have (c : R) : ℋ.weight ⁻¹' {c} = AffineSubspace.comap ℋ.weight.toAffineMap {c} := rfl rw [eq_Ici_zero_smul_inter_preimage_of_pos_of_ne_bot hC zero_lt_one hbot, - ofPoint_dehomogenize_eq_inter_ofPoint, ← ℋ.ofPoint_range_eq_preimage_weight_one] + ofPoint_dehomogenize_eq_inter_ofPoint, this, ← ℋ.ofPoint_range_eq_comap_weight_one] apply hull_eq_smul · obtain ⟨y, hyC, hy0⟩ := exists_mem_ne_zero_of_ne_bot hbot let y' := (ℋ.weight y)⁻¹ • y have hy'C : y' ∈ C := C.smul_mem (inv_nonneg.mpr (@hC y hyC hy0).le) hyC - have hy' : y' ∈ Set.range ℋ.ofPoint := by - simpa [y', ℋ.ofPoint_range_eq_preimage_weight_one] + have hy' : y' ∈ ℋ.ofPoint.range := by + simpa [y', ℋ.ofPoint_range_eq_comap_weight_one] using inv_mul_cancel₀ (@hC y hyC hy0).ne.symm exact ⟨y', hy'C, hy'⟩ · exact C.isConvexSet.inter ℋ.ofPoint.isConvexSet_range diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean index 27c25db9..90544aac 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/Set.lean @@ -254,7 +254,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range_le_weight_positive : R≥0 ∙ (Set.range ℋ.ofPoint) ≤ ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_one] + rw [← AffineMap.coe_range, ofPoint_range_eq_comap_weight_one] exact nonneg_smulSet_preimage_one_le_positive _ @[simp] lemma homogenize_univ_le_weight_positive : @@ -267,8 +267,7 @@ lemma homogenize_le_weight_positive (s : Set A) : @[simp] theorem homogenize_dehomogenize_le_weight_positive {S : SubMulAction₀ R≥0 W} : homogenize ℋ (S.dehomogenize ℋ) ≤ S ⊓ ℋ.weight.positive := by - have aux : Set.range ℋ.ofPoint = ℋ.ofPoint.range := rfl - rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, aux] + rw [homogenize, dehomogenize, Set.image_preimage_eq_inter_range, ← AffineMap.coe_range] refine le_trans (smulSet_inter_le _ _) ?_ simp only [smulSet_eq, le_inf_iff, inf_le_left, true_and] exact le_trans inf_le_right (nonneg_smulSet_ofPoint_range_le_weight_positive _) @@ -339,7 +338,7 @@ variable (ℋ : IsHomogenization R A W) lemma nonneg_smulSet_ofPoint_range : R≥0 ∙ (Set.range ℋ.ofPoint) = ℋ.weight.positive := by - rw [ofPoint_range_eq_preimage_weight_one] + rw [← AffineMap.coe_range, ofPoint_range_eq_comap_weight_one] exact nonneg_smulSet_preimage_one_eq_positive _ @[simp] lemma homogenize_univ : homogenize ℋ (Set.univ : Set A) = ℋ.weight.positive := by From 6d4bb654df5a9163ed459b135195293b623d0dec Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 12 Oct 2026 12:25:06 +0200 Subject: [PATCH 30/39] found lemma --- .../AffineSpace/AffineSubspace/Basic.lean | 22 ------------------- .../Homogenization/IsHomogenization.lean | 18 ++++++++++----- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean index 7d34e4ca..d375ecd7 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean @@ -63,26 +63,4 @@ instance : Neg (AffineSubspace R V) where instance : IsConcreteNeg (AffineSubspace R V) V := ⟨fun _ => rfl⟩ -lemma nonempty_comap_of_nonempty_of_surjective {E : AffineSubspace R R} (hE : (E : Set R).Nonempty) - {g : V →ₗ[R] R} (hg : Function.Surjective g) : Nonempty (E.comap g.toAffineMap) := by - obtain ⟨e, he⟩ := hE - obtain ⟨_, rfl⟩ := hg e - exact ⟨_, AffineSubspace.mem_comap.mpr he⟩ - end Module - -section DivisionRing - -open AffineSubspace - -variable {R : Type*} [DivisionRing R] -variable {V : Type*} [AddCommGroup V] [Module R V] - -variable {g : V →ₗ[R] R} - -lemma comap_nonempty_of_ne_zero (h : g ≠ 0) : Nonempty (comap g.toAffineMap {1}) := by - obtain ⟨y, hy⟩ : ∃ y, g y ≠ 0 := DFunLike.ne_iff.mp h - apply nonempty_comap_of_nonempty_of_surjective (Set.singleton_nonempty 1) - exact g.surjective_of_ne_zero h - -end DivisionRing diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index e93098b4..0269d8f3 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -10,6 +10,7 @@ public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range public import Mathlib.LinearAlgebra.AffineSpace.Homogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic +public import Mathlib.RingTheory.SimpleModule.Basic /-! This file defines affine homogenization as any vector space linearly equivalent to `Homogenization`, the canonical homogenization from Mathlib. It also proves every object @@ -274,7 +275,7 @@ section Field namespace IsHomogenization -open Function Submodule AffineSubspace +open Function Submodule AffineSubspace Set variable {R : Type*} [DivisionRing R] variable {V : Type*} [AddCommGroup V] [Module R V] @@ -285,24 +286,29 @@ variable {g : W →ₗ[R] R} (h : g ≠ 0) /-- A module is a homogenization of the weight-one hyperplane of any nonzero linear functional. -/ def ofWeightNeZero : - have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h + have : Nonempty (comap g.toAffineMap {1}) := + Surjective.nonempty (restrictPreimage_surjective {1} (g.surjective_of_ne_zero h)) IsHomogenization R (comap g.toAffineMap {1}) W := - have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h + have : Nonempty (comap g.toAffineMap {1}) := + Surjective.nonempty (restrictPreimage_surjective {1} (g.surjective_of_ne_zero h)) ofWeightEmbed (weight := g) (AffineSubspace.subtype_injective _) (by ext; simp) theorem ofPoint_ofWeightNeZero : - have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h + have : Nonempty (comap g.toAffineMap {1}) := + Surjective.nonempty (restrictPreimage_surjective {1} (g.surjective_of_ne_zero h)) (ofWeightNeZero h).ofPoint = (comap g.toAffineMap {1}).subtype := by simp [ofWeightNeZero] theorem ofVector_ofWeightNeZero : - have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h + have : Nonempty (comap g.toAffineMap {1}) := + Surjective.nonempty (restrictPreimage_surjective {1} (g.surjective_of_ne_zero h)) (ofWeightNeZero h).ofVector = (comap g.toAffineMap {1}).direction.subtype := by simp [ofWeightNeZero] @[simp] theorem weight_ofWeightNeZero : - have : Nonempty (comap g.toAffineMap {1}) := comap_nonempty_of_ne_zero h + have : Nonempty (comap g.toAffineMap {1}) := + Surjective.nonempty (restrictPreimage_surjective {1} (g.surjective_of_ne_zero h)) (ofWeightNeZero h).weight = g := by simp [ofWeightNeZero] From ea0b94c38685298c31fd7e5b5e80c9cf2c0323ab Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 14 Oct 2026 15:43:52 +0200 Subject: [PATCH 31/39] capital letters --- .../Convex/ConvexSpace/Set/Face/Basic.lean | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean index e152e527..630b5297 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean @@ -7,7 +7,7 @@ module public import Mathlib.Geometry.Convex.ConvexSpace.Defs -/-! This file defines faces of convex sets. +/-! This file defines faces oF Convex sets. TODO: align this API with `IsFaceOf` for cones. -/ @@ -41,34 +41,34 @@ theorem openSegment_symm (x y : M) : openSegment R x y = openSegment R y x := by all_goals (rw [convexCombPair_symm] at hz; rw [add_comm] at hmn; use hmn) variable (R) in -/-- A subset `f` of a set `c` is a face of `c` iff it is an extreme subset. -/ -structure IsFaceOf (f c : Set M) : Prop where - le : f ⊆ c - left_mem_of_mem_openSegment : ∀ ⦃x⦄, x ∈ c → ∀ ⦃y⦄, y ∈ c → - ∀ ⦃z⦄, z ∈ f → z ∈ openSegment R x y → x ∈ f +/-- A subset `F` of a set `c` is a face of `c` iff it is an extreme subset. -/ +structure IsFaceOf (F C : Set M) : Prop where + le : F ⊆ C + left_mem_of_mem_openSegment : ∀ ⦃x⦄, x ∈ C → ∀ ⦃y⦄, y ∈ C → + ∀ ⦃z⦄, z ∈ F → z ∈ openSegment R x y → x ∈ F namespace IsFaceOf -variable {c f c₁ c₂ f₁ f₂ : Set M} +variable {C F C₁ C₂ F₁ F₂ : Set M} -theorem empty : IsFaceOf R (∅ : Set M) c where - le := Set.empty_subset c +theorem empty : IsFaceOf R (∅ : Set M) C where + le := Set.empty_subset C left_mem_of_mem_openSegment := by simp /- A set is a face of itself. -/ -theorem refl : IsFaceOf R c c := +theorem refl : IsFaceOf R C C := ⟨subset_rfl, fun _ hx _ _ _ _ _ ↦ hx⟩ /- The face relation is transitive. -/ -theorem trans (h₁ : IsFaceOf R f₂ f₁) (h₂ : IsFaceOf R f₁ c) : IsFaceOf R f₂ c := by +theorem trans (h₁ : IsFaceOf R F₂ F₁) (h₂ : IsFaceOf R F₁ C) : IsFaceOf R F₂ C := by refine ⟨h₁.le.trans h₂.le, ?_⟩ intro x hx y hy z hz hhz - have hz' : z ∈ f₁ := h₁.le hz + have hz' : z ∈ F₁ := h₁.le hz exact h₁.2 (h₂.2 hx hy hz' hhz) (h₂.2 hy hx hz' (by simpa [openSegment_symm] using hhz)) hz hhz -/- For two faces `f₁, f₂` of `c`, `f₁` is a face of `f₂` iff it is a subset of `f₂`. -/ -theorem iff_le_of_isFaceOf (h₁ : IsFaceOf R f₁ c) (h₂ : IsFaceOf R f₂ c) : - IsFaceOf R f₁ f₂ ↔ f₁ ⊆ f₂ := by +/- For two faces `F₁, F₂` of `c`, `F₁` is a face of `F₂` iff it is a subset of `F₂`. -/ +theorem iff_le_of_isFaceOf (h₁ : IsFaceOf R F₁ C) (h₂ : IsFaceOf R F₂ C) : + IsFaceOf R F₁ F₂ ↔ F₁ ⊆ F₂ := by constructor · exact fun h ↦ h.1 · intro hh @@ -78,32 +78,32 @@ theorem iff_le_of_isFaceOf (h₁ : IsFaceOf R f₁ c) (h₂ : IsFaceOf R f₂ c) /- A set is a face of a face iff it is contained in the face and it is a face of the ambient set. -/ -lemma isFaceOf_iff (H : IsFaceOf R f c) : - IsFaceOf R f₁ f ↔ f₁ ⊆ f ∧ IsFaceOf R f₁ c := by +lemma isFaceOf_iff (H : IsFaceOf R F C) : + IsFaceOf R F₁ F ↔ F₁ ⊆ F ∧ IsFaceOf R F₁ C := by refine ⟨fun h ↦ ⟨h.1, trans h H⟩, fun h ↦ ⟨h.1, ?_⟩⟩ intro x hx y hy z hz hhz exact h.2.2 (H.le hx) (H.le hy) hz hhz /- The intersection of two faces of two sets is a face of the intersection of the sets. -/ -theorem inf (h₁ : IsFaceOf R f₁ c₁) (h₂ : IsFaceOf R f₂ c₂) : - IsFaceOf R (f₁ ∩ f₂) (c₁ ∩ c₂) := by +theorem inf (h₁ : IsFaceOf R F₁ C₁) (h₂ : IsFaceOf R F₂ C₂) : + IsFaceOf R (F₁ ∩ F₂) (C₁ ∩ C₂) := by refine ⟨fun x hx ↦ ⟨h₁.le hx.1, h₂.le hx.2⟩, ?_⟩ intro a ha b hb z hz hhz exact ⟨h₁.2 ha.1 hb.1 hz.1 hhz, h₂.2 ha.2 hb.2 hz.2 hhz⟩ /- The intersection of two faces is a face. -/ -theorem inf_left (h₁ : IsFaceOf R f₁ c) (h₂ : IsFaceOf R f₂ c) : IsFaceOf R (f₁ ∩ f₂) c := by +theorem inf_left (h₁ : IsFaceOf R F₁ C) (h₂ : IsFaceOf R F₂ C) : IsFaceOf R (F₁ ∩ F₂) C := by refine ⟨fun x hx ↦ h₁.le hx.1, ?_⟩ intro x hx y hy z hz hhz exact ⟨h₁.2 hx hy hz.1 hhz, h₂.2 hx hy hz.2 hhz⟩ /- A face of two sets is a face of the intersection. -/ -theorem inf_right (h₁ : IsFaceOf R f c₁) (h₂ : IsFaceOf R f c₂) : IsFaceOf R f (c₁ ∩ c₂) := +theorem inf_right (h₁ : IsFaceOf R F C₁) (h₂ : IsFaceOf R F C₂) : IsFaceOf R F (C₁ ∩ C₂) := ⟨Set.subset_inter h₁.1 h₂.1, fun _ hx _ hy _ hz hhz ↦ h₁.2 hx.1 hy.1 hz hhz⟩ /-- The intersection of a set `c` with any family of faces of `c` is a face of `c`. -/ -theorem sInf {c : Set M} {Fs : Set (Set M)} (h : ∀ f ∈ Fs, IsFaceOf R f c) : - IsFaceOf R (c ∩ ⋂₀ Fs) c where +theorem sInf {c : Set M} {Fs : Set (Set M)} (h : ∀ F ∈ Fs, IsFaceOf R F C) : + IsFaceOf R (C ∩ ⋂₀ Fs) C where le _ sm := sm.1 left_mem_of_mem_openSegment := by intro x hx y hy z hz hxyz @@ -113,11 +113,11 @@ theorem sInf {c : Set M} {Fs : Set (Set M)} (h : ∀ f ∈ Fs, IsFaceOf R f c) : section map variable [ConvexSpace R M₁] [ConvexSpace R M₂] -variable {c₁ f₁ : Set M₁} {c₂ f₂ : Set M₂} +variable {C₁ F₁ : Set M₁} {C₂ F₂ : Set M₂} /- The image of a face under an injective affine map is a face of the image. -/ theorem map {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) - (hF : IsFaceOf R f₁ c₁) : IsFaceOf R (φ '' f₁) (φ '' c₁) := by + (hF : IsFaceOf R F₁ C₁) : IsFaceOf R (φ '' F₁) (φ '' C₁) := by refine ⟨fun x ⟨y, hy, hyx⟩ ↦ ⟨y, hF.le hy, hyx⟩, ?_⟩ intro x hx y hy z hz hhz rcases hx with ⟨m, hmC, rfl⟩ @@ -134,8 +134,8 @@ theorem map {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) exact Set.mem_image_of_mem _ (hF.2 hmC hnC hlF hl) /- The preimage of a face is a face of the preimage. -/ -theorem comap_face {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hF : IsFaceOf R f₂ c₂) : - IsFaceOf R (φ ⁻¹' f₂) (φ ⁻¹' c₂) := by +theorem comap_face {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hF : IsFaceOf R F₂ C₂) : + IsFaceOf R (φ ⁻¹' F₂) (φ ⁻¹' C₂) := by refine ⟨Set.preimage_mono hF.1, ?_⟩ intro x hx y hy z hz hhz have hhz' : φ z ∈ openSegment R (φ x) (φ y) := by @@ -150,7 +150,7 @@ theorem comap_face {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hF : IsFaceOf /- `F` is a face of `C` iff the image of `F` is a face of the image of `C` under an injective affine map -/ theorem isFaceOf_map_iff {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) : - IsFaceOf R (φ '' f₁) (φ '' c₁) ↔ IsFaceOf R f₁ c₁ := by + IsFaceOf R (φ '' F₁) (φ '' C₁) ↔ IsFaceOf R F₁ C₁ := by refine ⟨fun h ↦ ?_, map hφ hinj⟩ have h' := comap_face hφ h rwa [Set.preimage_image_eq _ hinj, Set.preimage_image_eq _ hinj] at h' From 188833ba110eb1eb6e063306cc68043d9f77fbcc Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 15 Oct 2026 18:21:02 +0200 Subject: [PATCH 32/39] getting segment frm mathlib pr --- Polyhedral.lean | 1 + .../Mathlib/Geometry/Convex/Segment.lean | 260 ++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 Polyhedral/Mathlib/Geometry/Convex/Segment.lean diff --git a/Polyhedral.lean b/Polyhedral.lean index 1b028e43..733c6a48 100644 --- a/Polyhedral.lean +++ b/Polyhedral.lean @@ -64,6 +64,7 @@ public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.WithTop public import Polyhedral.Mathlib.Geometry.Convex.Fun.Defs public import Polyhedral.Mathlib.Geometry.Convex.Fun.Dual +public import Polyhedral.Mathlib.Geometry.Convex.Segment public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Closure public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Nonneg diff --git a/Polyhedral/Mathlib/Geometry/Convex/Segment.lean b/Polyhedral/Mathlib/Geometry/Convex/Segment.lean new file mode 100644 index 00000000..bcfeeda9 --- /dev/null +++ b/Polyhedral/Mathlib/Geometry/Convex/Segment.lean @@ -0,0 +1,260 @@ +/- +Copyright (c) 2026 Olivia Röhrig. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Olivia Röhrig +-/ + +module + +public import Mathlib.Data.Set.Insert +public import Mathlib.Geometry.Convex.ConvexSpace.Prod + +/-! +# Segments in convex spaces + +In an R-convex space, we define the following objects: +* `Icc R x y`: Closed segment joining `x` and `y`. +* `Ioo R x y`: Open segment joining `x` and `y`. +* `Ico R x y`: Right-open segment joining `x` and `y`. +-/ + +-- this file is PR #44799 + +namespace Convexity + +open Convexity Function + +@[expose] public section Semiring + +variable (R) {X} [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] [ConvexSpace R X] {s : Set X} + {x y z : X} + +/-- Segments in a convex space. Denoted as `Icc R x y` within the `Convex` namespace. -/ +def Icc (x y : X) : Set X := + { z : X | ∃ (a b : R) (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1), + convexCombPair a b ha hb hab x y = z } + +/-- Open segments in a convex space. Note that `Ioo R x x = {x}` instead of being `∅` when +the base semiring has some element between `0` and `1`. -/ +def Ioo (x y : X) : Set X := + { z : X | ∃ (a b : R) (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1), + convexCombPair a b ha.le hb.le hab x y = z } + +/-- Left-open segments in a convex space. Denoted as `Ico R x y` within the `Convex` namespace. -/ +def Ico (x y : X) : Set X := + { z : X | ∃ (a b : R) (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1), + convexCombPair a b ha.le hb hab x y = z } + +/- [x,y] = [y,x] -/ +theorem Icc_symm (x y : X) : Icc R x y = Icc R y x := by + ext z + constructor + all_goals (intro h; rcases h with ⟨m, n, hm , hn , hmn , hz⟩; use n, m, hn, hm) + all_goals (rw [convexCombPair_symm] at hz; rw [add_comm] at hmn; use hmn) + +/- (x,y) = (y,x) -/ +theorem Ioo_symm (x y : X) : Ioo R x y = Ioo R y x := by + ext z + constructor + all_goals (intro h; rcases h with ⟨m, n, hm , hn , hmn , hz⟩; use n, m, hn, hm) + all_goals (rw [convexCombPair_symm] at hz; rw [add_comm] at hmn; use hmn) + +theorem Ioo_subset_Ico (x y : X) : Ioo R x y ⊆ Ico R x y := + fun _ ⟨a, b, ha, hb, hab, hz⟩ ↦ ⟨a, b, ha, hb.le, hab, hz⟩ + +theorem Ico_subset_Icc (x y : X) : Ico R x y ⊆ Icc R x y := + fun _ ⟨a, b, ha, hb, hab, hz⟩ ↦ ⟨a, b, ha.le, hb, hab, hz⟩ + +theorem Ioo_subset_Icc (x y : X) : Ioo R x y ⊆ Icc R x y := + le_trans (Ioo_subset_Ico R x y) (Ico_subset_Icc R x y) + +section + +variable {R} + +theorem convexCombPair_mem_Icc {a b : R} (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1) : + convexCombPair a b ha hb hab x y ∈ Icc R x y := by + use a, b, ha, hb, hab + +theorem convexCombPair_mem_Ioo {a b : R} (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1) : + convexCombPair a b ha.le hb.le hab x y ∈ Ioo R x y := by + use a, b, ha, hb, hab + +theorem convexCombPair_mem_Ico {a b : R} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1) : + convexCombPair a b ha.le hb hab x y ∈ Ico R x y := by + use a, b, ha, hb, hab + +theorem forall_mem_Icc_iff (p : X → Prop) : (∀ z ∈ Icc R x y, p z) ↔ + ∀ {a b : R} (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1), + p (convexCombPair a b ha hb hab x y) where + mp := fun h _ _ _ _ _ ↦ h _ <| convexCombPair_mem_Icc .. + mpr := fun h _ hz => by rcases hz with ⟨_, _, _, _, _, rfl⟩; apply h + +theorem forall_mem_Ioo_iff (p : X → Prop) : (∀ z ∈ Ioo R x y, p z) ↔ + ∀ {a b : R} (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1), + p (convexCombPair a b ha.le hb.le hab x y) where + mp := fun h _ _ ha hb _ ↦ h _ <| convexCombPair_mem_Ioo ha hb .. + mpr := fun h _ hz => by rcases hz with ⟨_, _, ha, hb, _, rfl⟩; apply h ha hb + +theorem forall_mem_Ico_iff (p : X → Prop) : (∀ z ∈ Ico R x y, p z) ↔ + ∀ {a b : R} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1), + p (convexCombPair a b ha.le hb hab x y) where + mp := fun h _ _ ha hb _ ↦ h _ <| convexCombPair_mem_Ico ha .. + mpr := fun h _ hz => by rcases hz with ⟨_, _, ha, hb, _, rfl⟩; apply h ha hb + +theorem Icc_subset_iff : Icc R x y ⊆ s ↔ ∀ {a b : R} (ha : 0 ≤ a) (hb : 0 ≤ b) (hab : a + b = 1), + convexCombPair a b ha hb hab x y ∈ s := + forall_mem_Icc_iff .. + +theorem Ioo_subset_iff : + Ioo R x y ⊆ s ↔ ∀ {a b : R} (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1), + convexCombPair a b ha.le hb.le hab x y ∈ s := + forall_mem_Ioo_iff .. + +theorem Ico_subset_iff : + Ico R x y ⊆ s ↔ ∀ {a b : R} (ha : 0 < a) (hb : 0 ≤ b) (hab : a + b = 1), + convexCombPair a b ha.le hb hab x y ∈ s := + forall_mem_Ico_iff .. + +end + +theorem left_mem_Icc (x y : X) : x ∈ Icc R x y := + ⟨1, 0, zero_le_one, le_refl 0, add_zero 1, by rw [convexCombPair_one]⟩ + +theorem right_mem_Icc (x y : X) : y ∈ Icc R x y := + Icc_symm R y x ▸ left_mem_Icc R y x + +theorem left_mem_Ico (x y : X) : x ∈ Ico R x y := + ⟨1, 0, zero_lt_one, le_refl 0, add_zero 1, convexCombPair_one⟩ + +@[simp] +theorem Icc_same (x : X) : Icc R x x = {x} := + Set.ext fun z ↦ + ⟨fun ⟨a, b, _, _, hab, hz⟩ ↦ by + simpa [(add_smul ..).symm, Set.mem_singleton_iff, hab, one_smul, eq_comm] using hz, + fun h ↦ Set.mem_singleton_iff.1 h ▸ left_mem_Icc R z z⟩ + +@[simp] +theorem Ico_same (x : X) : Ico R x x = {x} := by + apply Set.Subset.antisymm + · rw [← Icc_same R x]; exact Ico_subset_Icc R x x + · simp [left_mem_Ico] + +theorem Ioo_insert_left (x y : X) : insert x (Ioo R x y) = Ico R x y := by + simp only [subset_antisymm_iff, Set.insert_subset_iff, left_mem_Ico, Ioo_subset_Ico, and_self, + true_and] + rintro z ⟨a, b, ha, hb', hab, rfl⟩ + by_cases hb : 0 < b + · exact Set.mem_insert_of_mem x (convexCombPair_mem_Ioo ha hb hab) + · rw [← eq_of_le_of_not_lt hb' hb] at hab + simp [← eq_of_le_of_not_lt hb' hb, add_zero a ▸ hab] + +theorem Ico_insert (x y : X) : insert y (Ico R x y) = Icc R x y := by + simp only [subset_antisymm_iff, Set.insert_subset_iff, right_mem_Icc, Ico_subset_Icc, true_and] + rintro z ⟨a, b, ha, hb, hab, rfl⟩ + refine ha.eq_or_lt.imp ?_ (fun hal ↦ convexCombPair_mem_Ico hal hb hab) + rintro rfl + simp [zero_add b ▸ hab] + +theorem Ioo_insert (x y : X) : insert x (insert y (Ioo R x y)) = Icc R x y := by + rw [Ioo_symm, Ioo_insert_left, Ico_insert, Icc_symm] + +namespace IsAffineMap + +variable {R} {Y} [ConvexSpace R Y] {f : X → Y} + +@[simp] +theorem image_Icc (hf : IsAffineMap R f) (a b : X) : + f '' Icc R a b = Icc R (f a) (f b) := + Set.ext fun _ ↦ by simp [Icc, IsAffineMap.map_convexCombPair hf] + +theorem mem_Icc_image (hf : IsAffineMap R f) {a b c : X} + (h : c ∈ Icc R a b) : f c ∈ Icc R (f a) (f b) := by + rw [← image_Icc hf, Set.mem_image] + exact ⟨c, ⟨h, rfl⟩⟩ + +@[simp] +theorem image_Ioo (hf : IsAffineMap R f) (a b : X) : + f '' Ioo R a b = Ioo R (f a) (f b) := + Set.ext fun _ ↦ by simp [Ioo, IsAffineMap.map_convexCombPair hf] + +theorem mem_Ioo_image (hf : IsAffineMap R f) {a b c : X} + (h : c ∈ Ioo R a b) : f c ∈ Ioo R (f a) (f b) := by + rw [← image_Ioo hf, Set.mem_image] + exact ⟨c, ⟨h, rfl⟩⟩ + +@[simp] +theorem image_Ico (hf : IsAffineMap R f) (a b : X) : f '' Ico R a b = Ico R (f a) (f b) := + Set.ext fun _ ↦ by simp [Ico, IsAffineMap.map_convexCombPair hf] + +theorem mem_Ico_image (hf : IsAffineMap R f) {a b c : X} (h : c ∈ Ico R a b) : + f c ∈ Ico R (f a) (f b) := by + rw [← image_Ico hf, Set.mem_image] + exact ⟨c, ⟨h, rfl⟩⟩ + +end IsAffineMap + +namespace Prod + +variable {Y} [ConvexSpace R Y] + +theorem Icc_subset (x y : X × Y) : Icc R x y ⊆ Icc R x.1 y.1 ×ˢ Icc R x.2 y.2 := by + rintro z ⟨a, b, ha, hb, hab, hz⟩ + exact ⟨⟨a, b, ha, hb, hab, by subst hz; simp⟩, a, b, ha, hb, hab, by subst hz; simp⟩ + +theorem Ioo_subset (x y : X × Y) : + Ioo R x y ⊆ Ioo R x.1 y.1 ×ˢ Ioo R x.2 y.2 := by + rintro z ⟨a, b, ha, hb, hab, hz⟩ + exact ⟨⟨a, b, ha, hb, hab, by subst hz; simp⟩, a, b, ha, hb, hab, by subst hz; simp⟩ + +theorem Ico_subset (x y : X × Y) : + Ico R x y ⊆ Ico R x.1 y.1 ×ˢ Ico R x.2 y.2 := by + rintro z ⟨a, b, ha, hb, hab, hz⟩ + exact ⟨⟨a, b, ha, hb, hab, by subst hz; simp⟩, a, b, ha, hb, hab, by subst hz; simp⟩ + +theorem image_mk_Icc_left (x₁ x₂ : X) (y : Y) : + (fun x ↦ (x, y)) '' Icc R x₁ x₂ = Icc R (x₁, y) (x₂, y) := + (IsAffineMap.prodMk IsAffineMap.id (IsAffineMap.const y)).image_Icc .. + +theorem image_mk_Icc_right (x : X) (y₁ y₂ : Y) : + (fun y ↦ (x, y)) '' Icc R y₁ y₂ = Icc R (x, y₁) (x, y₂) := + (IsAffineMap.prodMk (IsAffineMap.const x) IsAffineMap.id).image_Icc .. + +theorem image_mk_Ioo_left (x₁ x₂ : X) (y : Y) : + (fun x ↦ (x, y)) '' Ioo R x₁ x₂ = Ioo R (x₁, y) (x₂, y) := + (IsAffineMap.prodMk IsAffineMap.id (IsAffineMap.const y)).image_Ioo .. + +theorem image_mk_Ioo_right (x : X) (y₁ y₂ : Y) : + (fun y ↦ (x, y)) '' Ioo R y₁ y₂ = Ioo R (x, y₁) (x, y₂) := + (IsAffineMap.prodMk (IsAffineMap.const x) IsAffineMap.id).image_Ioo .. + +theorem image_mk_Ico_left (x₁ x₂ : X) (y : Y) : + (fun x ↦ (x, y)) '' Ico R x₁ x₂ = Ico R (x₁, y) (x₂, y) := + (IsAffineMap.prodMk IsAffineMap.id (IsAffineMap.const y)).image_Ico .. + +theorem image_mk_Ico_right (x : X) (y₁ y₂ : Y) : + (fun y ↦ (x, y)) '' Ico R y₁ y₂ = Ico R (x, y₁) (x, y₂) := + (IsAffineMap.prodMk (IsAffineMap.const x) IsAffineMap.id).image_Ico .. + +end Prod + +end Semiring + +section DenselyOrderedRing + +variable (R) {X} [Ring R] [PartialOrder R] [IsStrictOrderedRing R] [ConvexSpace R X] + [DenselyOrdered R] + +@[simp] +theorem Ioo_same (x : X) : Ioo R x x = {x} := + Set.ext fun z ↦ + ⟨fun ⟨a, b, _, _, hab, hz⟩ ↦ by + simpa only [convexCombPair_same, Set.mem_singleton_iff, eq_comm] using hz, + fun h : z = x ↦ by + obtain ⟨a, ha₀, ha₁⟩ := DenselyOrdered.dense (0 : R) 1 zero_lt_one + refine ⟨a, 1 - a, ha₀, sub_pos_of_lt ha₁, add_sub_cancel .., ?_⟩ + rw [convexCombPair_same, h]⟩ + +end DenselyOrderedRing + +end Convexity From ec71660673931f781960551fc0572948bea8a298 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 15 Oct 2026 18:27:45 +0200 Subject: [PATCH 33/39] redefining IsFaceOf to only allow convex faces --- .../Convex/ConvexSpace/Polytope/Face.lean | 13 +- .../Convex/ConvexSpace/Set/Face/Basic.lean | 299 +++++++++++------- .../ConvexSpace/Set/Face/Homogenization.lean | 38 +-- .../Convex/ConvexSpace/Set/Face/Lattice.lean | 40 +-- 4 files changed, 219 insertions(+), 171 deletions(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean index 8c5bbeb0..cc5dcc02 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/Face.lean @@ -21,6 +21,8 @@ variable {R V A : Type*} open Convexity IsConvexSet Affine +namespace Convexity + section Field variable [Field R] [LinearOrder R] [IsStrictOrderedRing R] @@ -31,18 +33,17 @@ variable {C F : Set A} include V in /-- Faces of polytopes are polytopes. -/ -theorem IsPolytope.face_isPolytope - (hC : IsPolytope R C) (hF : IsFaceOf R F C) (hcF : IsConvexSet R F) : +theorem IsPolytope.face_isPolytope (hC : IsPolytope R C) (hF : IsFaceOf R F C) : IsPolytope R (F : Set A) := by let : ConvexSpace R (Homogenization R A) := ConvexSpace.ofModule - have homF := (IsHomogenization.canonical R A).homogenize_isFaceOf hcF hC.isConvexSet hF + have homF := (IsHomogenization.canonical R A).homogenize_isFaceOf hC.isConvexSet hF have := PointedCone.IsFaceOf.fg (IsPolytope.homogenize_fg _ hC) homF convert FG.dehomogenize_isPolytope this (fun _ a b ↦ weight_pos_of_mem_homogenize a b) - rw [dehomogenize_homogenize _ hcF] + rw [dehomogenize_homogenize _ hF.isConvexSet] include V in instance {P : Polytope R A} : CoeOut (Face P.isPolytope.isConvexSet) (Polytope R A) where - coe F := ⟨_, IsPolytope.face_isPolytope P.isPolytope F.isFaceOf F.isConvexSet⟩ + coe F := ⟨_, IsPolytope.face_isPolytope P.isPolytope F.isFaceOf⟩ include V in /-- The face lattice of a polytope as a graded order with grading given by the dimensions of @@ -60,3 +61,5 @@ private noncomputable instance Polytope.faceHomogenizationGradeOrder (P : Polyto exact fun x y ↦ (apply_covBy_apply_iff _).mpr end Field + +end Convexity diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean index 630b5297..85d1a258 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean @@ -1,162 +1,217 @@ /- -Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Copyright (c) 2025 Olivia Röhrig. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig, Mara Gruß, Valentina Taylor Cerra, Martin Winter +Authors: Olivia Röhrig -/ module -public import Mathlib.Geometry.Convex.ConvexSpace.Defs +public import Mathlib.Analysis.Convex.Extreme +public import Polyhedral.Mathlib.Geometry.Convex.Segment +public import Mathlib.Geometry.Convex.Set -/-! This file defines faces oF Convex sets. +/-! +# Faces of sets + +This file defines what it means for a set in a convex space to be a face of another set and +establishes basic properties of this relation. + +## Main declarations + +* `IsFaceOf F C`: States that the set `F` is a face of the set `C`. -TODO: align this API with `IsFaceOf` for cones. -/ +open Function Convexity + @[expose] public section namespace Convexity -open Function - -variable {R M M₁ M₂ : Type*} +variable {R M N : Type*} section Semiring -variable [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] -variable [ConvexSpace R M] +variable [Semiring R] [PartialOrder R] [IsStrictOrderedRing R] [ConvexSpace R M] [ConvexSpace R N] -/- NOTE: this is a copy of mathlib convexity API adapted to `ConvexSpace`. -/ variable (R) in -/-- Open segment in a convex space. Note that `openSegment 𝕜 x x = {x}` instead of being `∅` when -the base semiring has some element between `0` and `1`. -/ -def openSegment (x y : M) : Set M := - { z : M | ∃ (a b : R) (a0 : 0 < a) (b0 : 0 < b) (ab : a + b = 1), - convexCombPair a b a0.le b0.le ab x y = z } - -/- (x,y) = (y,x) -/ -theorem openSegment_symm (x y : M) : openSegment R x y = openSegment R y x := by - ext z - constructor - all_goals (intro h; rcases h with ⟨m, n, hm , hn , hmn , hz⟩; use n, m, hn, hm) - all_goals (rw [convexCombPair_symm] at hz; rw [add_comm] at hmn; use hmn) - -variable (R) in -/-- A subset `F` of a set `c` is a face of `c` iff it is an extreme subset. -/ +/-- A subset `F` of a set `F` is a face of `C` iff it is an extreme convex subset. -/ +@[mk_iff] structure IsFaceOf (F C : Set M) : Prop where + isConvexSet : IsConvexSet R F le : F ⊆ C - left_mem_of_mem_openSegment : ∀ ⦃x⦄, x ∈ C → ∀ ⦃y⦄, y ∈ C → - ∀ ⦃z⦄, z ∈ F → z ∈ openSegment R x y → x ∈ F - -namespace IsFaceOf - -variable {C F C₁ C₂ F₁ F₂ : Set M} + left_mem_of_mem_Ioo {x y z : M} : x ∈ C → y ∈ C → + z ∈ F → z ∈ Ioo R x y → x ∈ F -theorem empty : IsFaceOf R (∅ : Set M) C where - le := Set.empty_subset C - left_mem_of_mem_openSegment := by simp +variable {C C₁ C₂ F F₁ F₂ : Set M} -/- A set is a face of itself. -/ -theorem refl : IsFaceOf R C C := - ⟨subset_rfl, fun _ hx _ _ _ _ _ ↦ hx⟩ +namespace IsFaceOf -/- The face relation is transitive. -/ -theorem trans (h₁ : IsFaceOf R F₂ F₁) (h₂ : IsFaceOf R F₁ C) : IsFaceOf R F₂ C := by - refine ⟨h₁.le.trans h₂.le, ?_⟩ - intro x hx y hy z hz hhz - have hz' : z ∈ F₁ := h₁.le hz - exact h₁.2 (h₂.2 hx hy hz' hhz) (h₂.2 hy hx hz' (by simpa [openSegment_symm] using hhz)) hz hhz - -/- For two faces `F₁, F₂` of `c`, `F₁` is a face of `F₂` iff it is a subset of `F₂`. -/ -theorem iff_le_of_isFaceOf (h₁ : IsFaceOf R F₁ C) (h₂ : IsFaceOf R F₂ C) : - IsFaceOf R F₁ F₂ ↔ F₁ ⊆ F₂ := by - constructor - · exact fun h ↦ h.1 - · intro hh - refine ⟨hh, ?_⟩ - intro x hx y hy z hz hhz - exact h₁.2 (h₂.le hx) (h₂.le hy) hz hhz - -/- A set is a face of a face iff it is contained in the face and it is a face -of the ambient set. -/ -lemma isFaceOf_iff (H : IsFaceOf R F C) : - IsFaceOf R F₁ F ↔ F₁ ⊆ F ∧ IsFaceOf R F₁ C := by - refine ⟨fun h ↦ ⟨h.1, trans h H⟩, fun h ↦ ⟨h.1, ?_⟩⟩ - intro x hx y hy z hz hhz - exact h.2.2 (H.le hx) (H.le hy) hz hhz - -/- The intersection of two faces of two sets is a face of the intersection of the sets. -/ -theorem inf (h₁ : IsFaceOf R F₁ C₁) (h₂ : IsFaceOf R F₂ C₂) : - IsFaceOf R (F₁ ∩ F₂) (C₁ ∩ C₂) := by - refine ⟨fun x hx ↦ ⟨h₁.le hx.1, h₂.le hx.2⟩, ?_⟩ - intro a ha b hb z hz hhz - exact ⟨h₁.2 ha.1 hb.1 hz.1 hhz, h₂.2 ha.2 hb.2 hz.2 hhz⟩ - -/- The intersection of two faces is a face. -/ -theorem inf_left (h₁ : IsFaceOf R F₁ C) (h₂ : IsFaceOf R F₂ C) : IsFaceOf R (F₁ ∩ F₂) C := by - refine ⟨fun x hx ↦ h₁.le hx.1, ?_⟩ - intro x hx y hy z hz hhz - exact ⟨h₁.2 hx hy hz.1 hhz, h₂.2 hx hy hz.2 hhz⟩ - -/- A face of two sets is a face of the intersection. -/ +/-- A convex set `C` is a face of itself. -/ +@[refl, simp] +protected theorem refl {C : Set M} (h : IsConvexSet R C) : IsFaceOf R C C := + ⟨h, fun _ a ↦ a, fun hx _ _ _ ↦ hx⟩ + +protected theorem rfl {C : Set M} {h : IsConvexSet R C} : IsFaceOf R C C := .refl h + +/-- A face of a set is a face of another if and only if they are contained in each other. -/ +theorem isFaceOf_iff_le (h₁ : IsFaceOf R F₁ C) (h₂ : IsFaceOf R F₂ C) : + IsFaceOf R F₁ F₂ ↔ F₁ ⊆ F₂ := + ⟨IsFaceOf.le, fun h ↦ ⟨h₁.isConvexSet, h, fun hx hy hz hs↦ h₁.3 (h₂.le hx) (h₂.le hy) hz hs⟩⟩ + +/-- The empty set is a face of every set. -/ +protected theorem empty {C : Set M} : IsFaceOf R ∅ C := + ⟨IsConvexSet.empty, Set.empty_subset C, fun _ _ h _ ↦ h⟩ + +/-- The intersection of two faces of two sets is a face of the intersection of the sets. -/ +protected theorem inf (h₁ : IsFaceOf R F₁ C₁) (h₂ : IsFaceOf R F₂ C₂) : + IsFaceOf R (F₁ ∩ F₂) (C₁ ∩ C₂) where + isConvexSet := IsConvexSet.inter h₁.isConvexSet h₂.isConvexSet + le := le_inf_iff.mpr ⟨Set.inter_subset_left.trans h₁.le, Set.inter_subset_right.trans h₂.le⟩ + left_mem_of_mem_Ioo := by + simp only [Set.mem_inter_iff, and_imp] + refine fun xC₁ xC₂ yC₁ yC₂ zF₁ zF₂ hz ↦ ⟨?_, ?_⟩ + · exact h₁.left_mem_of_mem_Ioo xC₁ yC₁ zF₁ hz + · exact h₂.left_mem_of_mem_Ioo xC₂ yC₂ zF₂ hz + +/-- The intersection of two faces of a set is a face of the set. -/ +theorem inf_left (h₁ : IsFaceOf R F₁ C) (h₂ : IsFaceOf R F₂ C) : IsFaceOf R (F₁ ∩ F₂) C := + inf_idem C ▸ IsFaceOf.inf h₁ h₂ + +/-- If a set is a face of two sets simultaneously, then it's also a face of their intersection. -/ theorem inf_right (h₁ : IsFaceOf R F C₁) (h₂ : IsFaceOf R F C₂) : IsFaceOf R F (C₁ ∩ C₂) := - ⟨Set.subset_inter h₁.1 h₂.1, fun _ hx _ hy _ hz hhz ↦ h₁.2 hx.1 hy.1 hz hhz⟩ + inf_idem F ▸ IsFaceOf.inf h₁ h₂ -/-- The intersection of a set `c` with any family of faces of `c` is a face of `c`. -/ -theorem sInf {c : Set M} {Fs : Set (Set M)} (h : ∀ F ∈ Fs, IsFaceOf R F C) : - IsFaceOf R (C ∩ ⋂₀ Fs) C where +protected theorem sInf (hc : IsConvexSet R C) {F : Set (Set M)} (h : ∀ f ∈ F, IsFaceOf R f C) : + IsFaceOf R (C ∩ sInf F) C where + isConvexSet := IsConvexSet.inter hc <| IsConvexSet.sInter (fun f hf ↦ (h f hf).isConvexSet) le _ sm := sm.1 - left_mem_of_mem_openSegment := by - intro x hx y hy z hz hxyz - refine ⟨hx, fun F hF => ?_⟩ - exact (h F hF).left_mem_of_mem_openSegment hx hy (hz.2 F hF) hxyz + left_mem_of_mem_Ioo := by + simp only [Set.sInf_eq_sInter, Set.mem_inter_iff, Set.mem_sInter, and_imp] + intro _ _ _ xc yc zc zf zs + simpa [xc] using fun f hf ↦ (h f hf).left_mem_of_mem_Ioo xc yc (zf f hf) zs + +protected theorem sInf' {F : Set (Set M)} (hne : F.Nonempty) (h : ∀ f ∈ F, IsFaceOf R f C) : + IsFaceOf R (sInf F) C where + isConvexSet := IsConvexSet.sInter (fun f hf ↦ (h f hf).isConvexSet) + le := by + obtain ⟨f, hf⟩ := hne + exact fun z hz ↦ (h f hf).le (Set.mem_sInter.mp hz f hf) + left_mem_of_mem_Ioo := by + intro x y z hx hy hz hseg + rw [Set.sInf_eq_sInter, Set.mem_sInter] at hz ⊢ + exact fun f hf ↦ (h f hf).left_mem_of_mem_Ioo hx hy (hz f hf) hseg + +/-- The face of a face of a set is also a face of the set. -/ +@[trans] +protected theorem trans (h₁ : IsFaceOf R F₂ F₁) (h₂ : IsFaceOf R F₁ C) : IsFaceOf R F₂ C := by + refine ⟨h₁.isConvexSet, h₁.le.trans h₂.le, ?_⟩ + intro x y z hx hy hz hhz + have hz' : z ∈ F₁ := h₁.le hz + exact h₁.3 (h₂.3 hx hy hz' hhz) + (h₂.3 hy hx hz' (by simpa [Ioo_symm, Ioo_symm] using hhz)) hz hhz -section map +section Map -variable [ConvexSpace R M₁] [ConvexSpace R M₂] -variable {C₁ F₁ : Set M₁} {C₂ F₂ : Set M₂} +variable {C₁ F₁ : Set M} {C₂ F₂ : Set N} /- The image of a face under an injective affine map is a face of the image. -/ -theorem map {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) - (hF : IsFaceOf R F₁ C₁) : IsFaceOf R (φ '' F₁) (φ '' C₁) := by - refine ⟨fun x ⟨y, hy, hyx⟩ ↦ ⟨y, hF.le hy, hyx⟩, ?_⟩ - intro x hx y hy z hz hhz - rcases hx with ⟨m, hmC, rfl⟩ - rcases hy with ⟨n, hnC, rfl⟩ - rcases hz with ⟨l, hlF, rfl⟩ - have hl : l ∈ openSegment R m n := by - rcases hhz with ⟨a, b, ha, hb, hab, hcomb⟩ - have h : φ (convexCombPair a b ha.le hb.le hab m n) = - convexCombPair a b ha.le hb.le hab (φ m) (φ n) := - hφ.map_convexCombPair ha.le hb.le hab m n - have hh : φ (convexCombPair a b ha.le hb.le hab m n) = φ l := by - simpa [h] using hcomb - exact ⟨a, b, ha, hb, hab, hinj hh⟩ - exact Set.mem_image_of_mem _ (hF.2 hmC hnC hlF hl) +theorem map {φ : M → N} (hφ : IsAffineMap R φ) (hinj : Injective φ) + (hF : IsFaceOf R F₁ C₁) : IsFaceOf R (φ '' F₁) (φ '' C₁) where + isConvexSet := IsConvexSet.image hφ hF.isConvexSet + le := Set.image_mono hF.le + left_mem_of_mem_Ioo := by + rintro _ _ a ⟨x, hmC, rfl⟩ ⟨y, hnC, rfl⟩ ⟨z, hlF, rfl⟩ ⟨_, _, ha, hb, hab, hcomb⟩ + refine Set.mem_image_of_mem _ (hF.3 hmC hnC hlF ⟨_, _, ha, hb, hab, hinj ?_⟩) + simpa [hφ.map_convexCombPair] using hcomb /- The preimage of a face is a face of the preimage. -/ -theorem comap_face {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hF : IsFaceOf R F₂ C₂) : - IsFaceOf R (φ ⁻¹' F₂) (φ ⁻¹' C₂) := by - refine ⟨Set.preimage_mono hF.1, ?_⟩ - intro x hx y hy z hz hhz - have hhz' : φ z ∈ openSegment R (φ x) (φ y) := by - rcases hhz with ⟨a, b, ha, hb, hab, hcomb⟩ - have hff : φ (convexCombPair a b ha.le hb.le hab x y) = - convexCombPair a b ha.le hb.le hab (φ x) (φ y) := - hφ.map_convexCombPair ha.le hb.le hab x y - rw [hcomb] at hff - exact ⟨a, b, ha, hb, hab, hff.symm⟩ - exact hF.2 hx hy hz hhz' +theorem preimage {φ : M → N} (hφ : IsAffineMap R φ) (hF : IsFaceOf R F₂ C₂) : + IsFaceOf R (φ ⁻¹' F₂) (φ ⁻¹' C₂) where + isConvexSet := IsConvexSet.preimage hφ hF.isConvexSet + le := Set.preimage_mono hF.le + left_mem_of_mem_Ioo := by + rintro x y z hx hy hz ⟨a, b, ha, hb, hab, hcomb⟩ + refine hF.3 hx hy hz ⟨a, b, ha, hb, hab, ?_⟩ + exact hcomb ▸ (hφ.map_convexCombPair ha.le hb.le hab x y).symm + +theorem of_map_injective {φ : M → N} (hφ : IsAffineMap R φ) (hinj : Injective φ) + (hF : IsFaceOf R (φ '' F₁) (φ '' C₁)) : IsFaceOf R F₁ C₁ := by + have h' := IsFaceOf.preimage hφ hF + rwa [Set.preimage_image_eq _ hinj, Set.preimage_image_eq _ hinj] at h' + +theorem of_preimage_surjective {φ : M → N} (hφ : IsAffineMap R φ) (hsurj : Function.Surjective φ) + (hc : IsFaceOf R (φ ⁻¹' F₂) (φ ⁻¹' C₂)) : IsFaceOf R F₂ C₂ := by + have hcv := IsConvexSet.image hφ hc.isConvexSet + rw [Set.image_preimage_eq _ hsurj] at hcv + refine ⟨hcv, fun x xF ↦ ?_, fun {x y z} xC yC zF h ↦ ?_⟩ + · rw [← (hsurj x).choose_spec] at xF ⊢ + exact Set.mem_preimage.mp (hc.le xF) + · rw [← (hsurj x).choose_spec] at h ⊢ xC + rw [← (hsurj y).choose_spec] at h yC + rw [← hφ.image_Ioo] at h + obtain ⟨a, b, rfl⟩ := h + exact hc.left_mem_of_mem_Ioo xC yC zF b + +end Map + +end IsFaceOf /- `F` is a face of `C` iff the image of `F` is a face of the image of `C` under an injective affine map -/ -theorem isFaceOf_map_iff {φ : M₁ → M₂} (hφ : IsAffineMap R φ) (hinj : Injective φ) : - IsFaceOf R (φ '' F₁) (φ '' C₁) ↔ IsFaceOf R F₁ C₁ := by - refine ⟨fun h ↦ ?_, map hφ hinj⟩ - have h' := comap_face hφ h - rwa [Set.preimage_image_eq _ hinj, Set.preimage_image_eq _ hinj] at h' +theorem isFaceOf_map_iff {φ : M → N} (hφ : IsAffineMap R φ) (hinj : Injective φ) : + IsFaceOf R (φ '' F₁) (φ '' C₁) ↔ IsFaceOf R F₁ C₁ := + ⟨IsFaceOf.of_map_injective hφ hinj, IsFaceOf.map hφ hinj⟩ +variable {C₂ F₂ : Set N} in +/-- The preimage of a set `F` under a surjective affine map is a face of the +preimage of another set `F` if and only if `F` is a face of `C`. -/ +theorem isFaceOf_preimage_iff {φ : M → N} (hφ : IsAffineMap R φ) (hsurj : Function.Surjective φ) : + IsFaceOf R (φ ⁻¹' F₂) (φ ⁻¹' C₂) ↔ IsFaceOf R F₂ C₂ := + ⟨IsFaceOf.of_preimage_surjective hφ hsurj, IsFaceOf.preimage hφ⟩ + +namespace IsFaceOf -end map +section Prod + +/-- The product of two faces of two sets is a face of the product of the sets. -/ +protected theorem prod {C₁ F₁ : Set M} {C₂ F₂ : Set N} + (hF₁ : IsFaceOf R F₁ C₁) (hF₂ : IsFaceOf R F₂ C₂) : IsFaceOf R (F₁ ×ˢ F₂) (C₁ ×ˢ C₂) where + isConvexSet := IsConvexSet.prod hF₁.isConvexSet hF₂.isConvexSet + le := fun x hx ↦ by simpa [Set.mem_prod] using ⟨hF₁.le hx.1, hF₂.le hx.2⟩ + left_mem_of_mem_Ioo := by + simp only [Set.mem_prod, and_imp, Prod.forall] + intro _ _ _ _ _ _ xC₁ xC₂ yC₁ yC₂ ha hb hs + have := Prod.Ioo_subset R _ _ hs + exact ⟨hF₁.3 xC₁ yC₁ ha this.1, hF₂.3 xC₂ yC₂ hb this.2⟩ + +/-- The projection of a face of a product set onto the first component is a face of the +projection of the product set onto the first component. -/ +protected theorem fst {C₁ : Set M} {C₂ : Set N} {F : Set (M × N)} + (hF : IsFaceOf R F (C₁ ×ˢ C₂)) : IsFaceOf R (Prod.fst '' F) C₁ where + isConvexSet := IsConvexSet.image Prod.isAffineMap_fst hF.isConvexSet + le := by + intro x hx + simp only [Set.mem_image, Prod.exists, exists_and_right, exists_eq_right] at hx + exact (Set.mem_prod.mp <| hF.le hx.choose_spec).1 + left_mem_of_mem_Ioo := by + simp only [Set.mem_image, Prod.exists, exists_and_right, exists_eq_right, forall_exists_index] + intro x y a hx hy ha z h + refine ⟨ha, hF.left_mem_of_mem_Ioo (x := (x, ha)) (y := (y, ha)) (z := (a, ha)) ?_ ?_ z ?_⟩ + · exact Set.mem_prod.mp ⟨hx, (hF.le z).2⟩ + · exact Set.mem_prod.mp ⟨hy, (hF.le z).2⟩ + · rw [← Prod.image_mk_Ioo_left R x y ha] + simpa + +/-- The projection of a face of a product set onto the second component is a face of the +projection of the product set onto the second component. -/ +protected theorem snd {C₁ : Set M} {C₂ : Set N} {F : Set (M × N)} + (hF : IsFaceOf R F (C₁ ×ˢ C₂)) : IsFaceOf R (Prod.snd '' F) C₂ := by + have := hF.map (φ := Prod.swap) ((Prod.isAffineMap_snd).prodMk (Prod.isAffineMap_fst)) + Prod.swap_injective + convert IsFaceOf.fst (by simpa) + simp [Set.image_image] + +end Prod end IsFaceOf diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean index b57e1b72..e5de1bd5 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Homogenization.lean @@ -33,10 +33,10 @@ variable (ℋ : Affine.IsHomogenization R A W) variable {ℋ} in /-- If the homogenization of a point `q` is a positive combination of the homogenization of two other points, then `q` lies in the open segment between them. -/ -theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} +theorem pos_combo_Ioo {r₁ r₂ t : R} {p₁ p₂ q : A} (h₁ : 0 < r₁) (h₂ : 0 < r₂) (hₜ : 0 < t) (h : r₁ • ℋ.ofPoint p₁ + r₂ • ℋ.ofPoint p₂ = t • ℋ.ofPoint q) : - q ∈ Convexity.openSegment R p₁ p₂ := by + q ∈ Convexity.Ioo R p₁ p₂ := by have : r₁ + r₂ = t := by simpa [ℋ.weight_ofPoint, map_add, map_smul] using congr_arg ℋ.weight h have : t⁻¹ • r₁ + t⁻¹ • r₂ = 1 := by simp_rw [← smul_add, smul_eq_mul, this, mul_comm, Field.mul_inv_cancel _ hₜ.ne.symm] @@ -48,21 +48,21 @@ theorem pos_combo_openSegment {r₁ r₂ t : R} {p₁ p₂ q : A} /-- If `F` is a face of `P`, then the homogenization of `F` is a face of the homogenization of `P`. -/ -theorem homogenize_isFaceOf {F P : Set A} (hF : IsConvexSet R F) (hP : IsConvexSet R P) - (he : IsFaceOf R F P) : (homogenize ℋ F).IsFaceOf (homogenize ℋ P) where - le := (homogenizeOrderHom ℋ).monotone' he.le +theorem homogenize_isFaceOf {F P : Set A} (hP : IsConvexSet R P) + (hF : IsFaceOf R F P) : (homogenize ℋ F).IsFaceOf (homogenize ℋ P) where + le := (homogenizeOrderHom ℋ).monotone' hF.le mem_of_smul_add_mem := by intro v w a hv hw ha hvw have hhom := homogenize_salient ℋ P by_cases hnf : (F : Set A).Nonempty - · have cF := hF.image ℋ.ofPoint.isAffineMap + · have cF := hF.isConvexSet.image ℋ.ofPoint.isAffineMap apply (Set.ext_iff.mp (PointedCone.hull_eq_smul (hnf.image _) cF) _).mpr by_cases hv0 : v = 0 · exact ⟨0, le_rfl, mem_smul_set.mpr (by simpa [hv0] using nonempty_def.mp hnf)⟩ · by_cases hw0 : w = 0 · subst hw0 - obtain ⟨r, hr, r', ⟨w, hw, _⟩, hra⟩ := - smul_pos_of_mem_homogenize hF hvw (by simpa using smul_ne_zero ha.ne.symm hv0) + obtain ⟨r, hr, r', ⟨w, hw, _⟩, hra⟩ := smul_pos_of_mem_homogenize hF.isConvexSet hvw + (by simpa using smul_ne_zero ha.ne.symm hv0) simp only [add_zero] at ⊢ hra use a⁻¹ • r, (smul_pos (inv_pos.mpr ha) hr).le, r' constructor @@ -75,11 +75,12 @@ theorem homogenize_isFaceOf {F P : Set A} (hF : IsConvexSet R F) (hP : IsConvexS intro hc exact (smul_ne_zero rw0.ne.symm (ℋ.ofPoint_ne_zero q')) <| hhom _ hw _ (PointedCone.smul_mem _ ha.le hv) (by simpa [add_comm] using hc) - obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := smul_pos_of_mem_homogenize hF hvw this - have := he.left_mem_of_mem_openSegment pp qq qqp ?_ + obtain ⟨_, rvw0, _, ⟨_, qqp, rfl⟩, pdp⟩ := + smul_pos_of_mem_homogenize hF.isConvexSet hvw this + have := hF.left_mem_of_mem_Ioo pp qq qqp ?_ · refine ⟨rv, rv0.le, smul_mem_smul_set <| mem_image_of_mem ℋ.ofPoint this⟩ rw [← smul_assoc _ rv] at pdp - exact pos_combo_openSegment (smul_pos ha rv0) rw0 rvw0 pdp.symm + exact pos_combo_Ioo (smul_pos ha rv0) rw0 rvw0 pdp.symm · have := not_nonempty_iff_eq_empty.mp hnf simp_all only [homogenize, image_empty, span_empty, mem_bot] by_contra hxx @@ -94,9 +95,10 @@ theorem homogenize_isFaceOf {F P : Set A} (hF : IsConvexSet R F) (hP : IsConvexS of `C`. -/ theorem dehomogenize_isFaceOf {F C : PointedCone R W} (hf : F.IsFaceOf C) : IsFaceOf R (dehomogenize ℋ F) (dehomogenize ℋ C) where + isConvexSet := dehomogenize_isConvexSet ℋ F le := preimage_mono (fun _ x ↦ hf.le x) - left_mem_of_mem_openSegment := by - rintro x hx y hy z hz ⟨a, b, ha, hb, hab, hzo⟩ + left_mem_of_mem_Ioo := by + rintro x y z hx hy hz ⟨a, b, ha, hb, hab, hzo⟩ refine hf.mem_of_smul_add_mem hx (C.smul_mem hb.le hy) ha ?_ rwa [← convexCombPair_eq_sum _ _ ha.le hb.le hab, ← ℋ.ofPoint.isAffineMap.map_convexCombPair, hzo] @@ -109,17 +111,17 @@ of convex sets. -/ def _root_.Convexity.face_homogenizeIso {P : Set A} (hP : IsConvexSet R P) : Face hP ≃o PointedCone.Face (homogenize ℋ P) where - toFun F := ⟨_, ℋ.homogenize_isFaceOf F.isConvexSet hP F.isFaceOf⟩ - invFun F := ⟨dehomogenize ℋ F.toSubmodule, dehomogenize_isConvexSet ℋ F.toSubmodule, + toFun F := ⟨_, ℋ.homogenize_isFaceOf hP F.isFaceOf⟩ + invFun F := ⟨dehomogenize ℋ F.toSubmodule, by simpa [dehomogenize_homogenize ℋ hP] using dehomogenize_isFaceOf ℋ F.isFaceOf⟩ map_rel_iff' := by intro a b refine ⟨fun h x xm ↦ ?_, fun h _ xm ↦ span_mono (image_mono h) xm⟩ - refine (ofPoint_mem_homogenize_iff_mem _ x b.isConvexSet).mp (h ?_) - exact (ofPoint_mem_homogenize_iff_mem _ x a.isConvexSet).mpr xm + refine (ofPoint_mem_homogenize_iff_mem _ x b.isFaceOf.isConvexSet).mp (h ?_) + exact (ofPoint_mem_homogenize_iff_mem _ x a.isFaceOf.isConvexSet).mpr xm left_inv F := by simp only [Face.carrier_eq_coe, Face.ext_iff] - exact dehomogenize_homogenize ℋ F.isConvexSet + exact dehomogenize_homogenize ℋ F.isFaceOf.isConvexSet right_inv F := by have := homogenize_dehomogenize_of_le_positive (fun _ h n ↦ weight_pos_of_mem_homogenize (F.isFaceOf.le h) n) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean index 6f59938f..c25e278f 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean @@ -33,7 +33,6 @@ namespace IsConvexSet @[ext] structure Face {p : Set M} (P : IsConvexSet R p) where carrier : Set M - isConvexSet : IsConvexSet R carrier isFaceOf : IsFaceOf R carrier p attribute [coe] Face.carrier @@ -53,14 +52,14 @@ instance : CoeOut (Face P) (Set M) := ⟨carrier⟩ @[simp] theorem mem_coe {F : Face P} (x : M) : x ∈ F.carrier ↔ x ∈ F := .rfl -@[simp] theorem mem_mk {s c h x} : x ∈ (⟨s, c, h⟩ : Face P) ↔ x ∈ s := .rfl +@[simp] theorem mem_mk {s h x} : x ∈ (⟨s, h⟩ : Face P) ↔ x ∈ s := .rfl -@[simp] theorem mk_eq {s c h} : (⟨s, c, h⟩ : Face P) = s := by ext; simp +@[simp] theorem mk_eq {s h} : (⟨s, h⟩ : Face P) = s := by ext; simp instance : PartialOrder (Face P) := .ofSetLike .. instance : OrderBot (Face P) where - bot := ⟨_, IsConvexSet.empty, IsFaceOf.empty⟩ + bot := ⟨_, IsFaceOf.empty⟩ bot_le _ _ := by simp lemma nonempty_of_ne_bot {F : Face P} (h : F ≠ ⊥) : (F : Set M).Nonempty := by @@ -71,32 +70,21 @@ lemma nonempty_of_ne_bot {F : Face P} (h : F ≠ ⊥) : (F : Set M).Nonempty := simp [heq, Bot.bot] instance : OrderTop (Face P) where - top := ⟨_, P, IsFaceOf.refl⟩ + top := ⟨_, IsFaceOf.refl P⟩ le_top F := F.isFaceOf.le instance : Inhabited (Face P) := ⟨⊤⟩ -theorem toConvexSet_le {F : Face P} : F.carrier ≤ p := F.isFaceOf.le - -@[simp] -theorem toConvexSet_le_toConvexSet {F₁ F₂ : Face P} : - F₁.carrier ≤ F₂.carrier ↔ F₁ ≤ F₂ := .rfl - -@[simp] theorem toConvexSet_bot : ((⊥ : Face P) : Set M) = ∅ := rfl - -@[simp] theorem toConvexSet_top : ((⊤ : Face P) : Set M) = p := rfl - /-! ### Infimum, supremum and lattice -/ /-- The infimum of two faces `F₁`, `F₂` of `P` is the intersection of `F₁` and `F₂`. -/ instance : Min (Face P) where - min F₁ F₂ := ⟨_, F₁.isConvexSet.inter F₂.isConvexSet, F₁.isFaceOf.inf_left F₂.isFaceOf⟩ + min F₁ F₂ := ⟨_, F₁.isFaceOf.inf_left F₂.isFaceOf⟩ instance : InfSet (Face P) where sInf S := - { carrier := p ⊓ sInf {s.1 | s ∈ S} - isConvexSet := P.inter (IsConvexSet.sInter fun s ⟨s, hs, sh⟩ ↦ sh ▸ s.isConvexSet) - isFaceOf := IsFaceOf.sInf (by rintro _ ⟨s, hs, rfl⟩; exact s.isFaceOf) } + { carrier := p ∩ sInf {s.1 | s ∈ S} + isFaceOf := IsFaceOf.sInf P (fun _ hf ↦ hf.choose_spec.2 ▸ hf.choose.isFaceOf) } instance : SemilatticeInf (Face P) where inf := min @@ -108,17 +96,17 @@ instance : CompleteSemilatticeInf (Face P) where __ := instSemilatticeInf isGLB_sInf S := by constructor <;> intro f fS - · rw [← toConvexSet_le_toConvexSet] - refine inf_le_of_right_le ?_ - simp only [carrier_eq_coe, Set.sInf_eq_sInter] - exact fun _ xs ↦ xs f (by simpa) + · rintro _ ⟨_, hz⟩ + simp only [carrier_eq_coe, Set.sInf_eq_sInter, Set.mem_sInter, Set.mem_ofPred_eq, + forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, SetLike.mem_coe] at hz + exact hz _ fS · simp only [sInf, carrier_eq_coe, Set.mem_ofPred_eq, forall_exists_index, and_imp, - forall_apply_eq_imp_iff₂, SetLike.mem_coe, Set.inf_eq_inter] + forall_apply_eq_imp_iff₂, SetLike.mem_coe] simpa [LE.le] using fun x a ↦ ⟨f.isFaceOf.le a, fun i hi ↦ (mem_coe x).mp (fS hi a)⟩ instance : CompleteLattice (Face P) where - top := ⟨_, P, .refl⟩ - le_top _ := toConvexSet_le + top := ⟨_, .refl P⟩ + le_top f := f.isFaceOf.le __ := completeLatticeOfCompleteSemilatticeInf _ end IsConvexSet.Face From 51ed18940acbdd6f9d8247c2066f6611f7454a08 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 15 Oct 2026 18:35:39 +0200 Subject: [PATCH 34/39] keeping the ConvexSet coe --- .../Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean index 19b879aa..35709c33 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/Cone/Pointed/Convexity.lean @@ -7,6 +7,7 @@ module public import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Basic public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Hull +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Lattice import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Module @@ -36,6 +37,11 @@ lemma isConvexSet (P : PointedCone R M) : IsConvexSet R (P : Set M) := by refine P.finsuppSum_mem _ _ (fun i r ↦ r • i) (fun c hc ↦ ?_) exact P.smul_mem (w.weights_nonneg c) <| hw (Finsupp.mem_support_iff.mpr hc) +@[coe] +def toConvexSet (P : PointedCone R M) : ConvexSet R M := ⟨_, P.isConvexSet⟩ + +instance : Coe (PointedCone R M) (ConvexSet R M) := ⟨toConvexSet⟩ + @[simp] theorem hull_convexHull (t : Set M) : hull R (Convexity.convexHull R t) = hull R t := by apply le_antisymm From e9d2025df2099e8a24c09ba8d4e49c1b88dfb11e Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 20 Oct 2026 17:11:24 +0200 Subject: [PATCH 35/39] remove bogus import --- .../Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean index d375ecd7..720b29ba 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Basic.lean @@ -7,7 +7,6 @@ module public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic public import Polyhedral.Mathlib.Algebra.Group.Pointwise.SetLike.Basic -import Mathlib.RingTheory.SimpleModule.Basic /-! This file adds features for affine spaces. From 1ab0db9071a226d55e45769e4717fc8809fbc255 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 20 Oct 2026 17:16:12 +0200 Subject: [PATCH 36/39] keeping empty --- .../Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean index c25e278f..a08a5f34 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Lattice.lean @@ -59,7 +59,7 @@ instance : CoeOut (Face P) (Set M) := ⟨carrier⟩ instance : PartialOrder (Face P) := .ofSetLike .. instance : OrderBot (Face P) where - bot := ⟨_, IsFaceOf.empty⟩ + bot := ⟨∅, IsFaceOf.empty⟩ bot_le _ _ := by simp lemma nonempty_of_ne_bot {F : Face P} (h : F ≠ ⊥) : (F : Set M).Nonempty := by From 1e10f806e74664a5cf6beff5a793ab8c186107c6 Mon Sep 17 00:00:00 2001 From: ovi Date: Tue, 20 Oct 2026 18:12:58 +0200 Subject: [PATCH 37/39] wip --- .../ConvexSpace/Polytope/KreinMilman.lean | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean new file mode 100644 index 00000000..aa1a7bc7 --- /dev/null +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean @@ -0,0 +1,106 @@ +/- +Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Martin Winter, Olivia Röhrig +-/ + +import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Finite.Face.Basic +import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Module +import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Basic +import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Homogenization + +/-! In this file we prove the Krein-Milman theorem for polytopes: every polytope is the convex +hull of its vertices, that is, of the finite set of points whose singletons are faces. + +The proof is independent of the Krein-Milman theorem for FG cones +(`PointedCone.FG.krein_milman`); the cone version is instead derived from the present theorem +by slicing a salient cone at weight one. The key step here shows that a generator outside the +convex hull of the remaining generators spans a singleton face; this is obtained from the +cone-side lemma `PointedCone.span_singleton_isFaceOf_sup_singleton_of_not_mem` via +homogenization. -/ + +variable {R V A : Type*} + +open Convexity Affine Affine.IsHomogenization PointedCone + +section Field + +variable [Field R] [LinearOrder R] [IsStrictOrderedRing R] +variable [AddCommGroup V] [Module R V] +variable [AddTorsor V A] + +variable {P : Set A} + +variable {W} [AddCommGroup W] [Module R W] (ℋ : Affine.IsHomogenization R A W) in +/-- The dehomogenization of the ray spanned by an embedded point is the singleton of that +point. -/ +@[simp] lemma dehomogenize_hull_singleton_ofPoint (p : A) : + Convexity.dehomogenize ℋ (R ∙₊ ℋ.ofPoint p) = {p} := by + ext q + constructor + · intro hq + have hq' : ℋ.ofPoint q ∈ R ∙₊ ℋ.ofPoint p := hq + simp only [Submodule.mem_span_singleton, Subtype.exists, Nonneg.mk_smul, exists_prop] at hq' + obtain ⟨c, -, hc⟩ := hq' + have hw := congrArg ℋ.weight hc + simp only [map_smul, ℋ.weight_ofPoint, smul_eq_mul, mul_one] at hw + rw [hw, one_smul] at hc + exact ℋ.ofPoint_injective hc ▸ rfl + · rintro rfl + simp [Convexity.dehomogenize] + +variable [ConvexSpace R A] [IsAffineConvexSpace R V A] + +/-- If a point `x` does not lie in the convex hull of a set `s`, then the singleton of `x` is +a face of the convex hull of `insert x s`. -/ +lemma IsFaceOf.singleton_convexHull_insert {s : Set A} {x : A} {v : V} (hx : x ∉ convexHull R s) : + IsFaceOf R ({x} : Set A) (convexHull R (insert x s)) := by + let : ConvexSpace R (Homogenization R A) := .ofModule + let ℋ := IsHomogenization.canonical R A + have hhom : homogenize (IsHomogenization.canonical R A) (convexHull R (insert x s)) = + PointedCone.hull R (ℋ.ofPoint '' s) ⊔ (R ∙₊ ℋ.ofPoint x) := by + rw [← hull_image_ofPoint_eq_homogenize_convexHull, Set.image_insert_eq, hull_insert, sup_comm] + have hnot : ℋ.ofPoint x ∉ PointedCone.hull R (ℋ.ofPoint '' s) := by + rw [hull_image_ofPoint_eq_homogenize_convexHull (ℋ := ℋ)] + exact fun h => hx ((ofPoint_mem_homogenize_iff_mem _ x IsConvexSet.convexHull).mp h) + have hsal : (PointedCone.hull R (ℋ.ofPoint '' s) ⊔ (R ∙₊ ℋ.ofPoint x)).Salient := + hhom ▸ homogenize_salient _ _ + have hface := span_singleton_isFaceOf_sup_singleton_of_not_mem hnot hsal + rw [← hhom] at hface + have h := dehomogenize_isFaceOf ℋ hface + rwa [dehomogenize_homogenize, dehomogenize_hull_singleton_ofPoint ℋ x] at h + exact IsConvexSet.convexHull + +/-- Krein-Milman theorem for polytopes: every polytope is the convex hull of its vertices, +that is, of the finite set of points whose singletons are faces. -/ +theorem IsPolytope.krein_milman (hP : IsPolytope R P) : + ∃ s : Finset A, Convexity.convexHull R (s : Set A) = P ∧ ∀ x ∈ s, IsFaceOf R {x} P := by + classical + suffices h : ∀ t : Finset A, ∀ P : Set A, Convexity.convexHull R (t : Set A) = P → + ∃ s : Finset A, Convexity.convexHull R (s : Set A) = P ∧ ∀ x ∈ s, IsFaceOf R {x} P by + obtain ⟨t, ht⟩ := hP + exact h t P ht.symm + intro t + induction t using Finset.strongInduction with + | _ t ih => + intro P hP + by_cases hex : ∃ x ∈ t, x ∈ Convexity.convexHull R ((t.erase x : Finset A) : Set A) + · -- a redundant generator can be dropped and the induction hypothesis applies + obtain ⟨x, hxt, hx⟩ := hex + refine ih (t.erase x) (Finset.erase_ssubset hxt) P ?_ + rw [← hP] + -- ext + refine subset_antisymm + (convexHull_mono (Finset.coe_subset.mpr (Finset.erase_subset x t))) ?_ + refine (IsConvexSet.convexHull_subset_iff IsConvexSet.convexHull).mpr ?_ + intro y hy + rcases eq_or_ne y x with rfl | hne + · exact hx + · exact subset_convexHull_self (Finset.mem_coe.mpr (Finset.mem_erase.mpr ⟨hne, hy⟩)) + · -- otherwise every generator is a vertex + push Not at hex + refine ⟨t, hP, fun x hxt => ?_⟩ + have h := IsFaceOf.singleton_convexHull_insert (R := R) (hex x hxt) + rwa [← Finset.coe_insert, Finset.insert_erase hxt, hP] at h + +end Field From a1835c204777e92cd750eb6667657c0514184e25 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 21 Oct 2026 11:04:18 +0200 Subject: [PATCH 38/39] version+mathlib bump --- Polyhedral.lean | 1 - .../Geometry/Convex/ConvexSpace/Order.lean | 2 +- .../AffineSpace/AffineSubspace/Range.lean | 94 ------------------- .../Homogenization/IsHomogenization.lean | 4 +- lake-manifest.json | 20 ++-- lean-toolchain | 2 +- 6 files changed, 14 insertions(+), 109 deletions(-) delete mode 100644 Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean diff --git a/Polyhedral.lean b/Polyhedral.lean index 242f3273..0374c004 100644 --- a/Polyhedral.lean +++ b/Polyhedral.lean @@ -68,7 +68,6 @@ public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Closure public import Polyhedral.Mathlib.GroupTheory.GroupAction.SubMulActionWithZero.Nonneg public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Defs public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.IsHomogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.Homogenization.Set diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Order.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Order.lean index a92cc733..e68bc405 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Order.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Order.lean @@ -115,7 +115,7 @@ lemma upperMass_eq_one_iff : w.upperMass x = 1 ↔ ∀ y, w.weights y ≠ 0 → refine ⟨fun h1 y hy ↦ ?_, fun hall ↦ ?_⟩ · rw [h1] at h have hz := add_left_cancel (h.trans (add_zero 1).symm) - by_contra! hxy + by_contra hxy exact hy <| (Finset.sum_eq_zero_iff_of_nonneg fun _ _ ↦ w.weights_nonneg _).1 hz y <| by simp [hy, hxy] · rwa [Finset.sum_eq_zero fun y ↦ by simp +contextual [hall], add_zero] at h diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean deleted file mode 100644 index cd20e131..00000000 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace/Range.lean +++ /dev/null @@ -1,94 +0,0 @@ -/- -Copyright (c) 2026 Olivia Röhrig. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Olivia Röhrig --/ -module - -public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic - -/-! -# Range of affine maps - -The range of an affine map `f : P₁ →ᵃ[R] P₂` is an affine subspace of `P₂`. - -# Implementation note - -Follows `LinearMap.range`. - --/ - -@[expose] public section - -open Affine Module AffineMap AffineSubspace - -section - -variable {R V₁ V₂ P₁ P₂ : Type*} - -namespace AffineMap - -variable [Ring R] -variable [AddCommGroup V₁] [Module R V₁] -variable [AddCommGroup V₂] [Module R V₂] -variable [AffineSpace V₁ P₁] [AffineSpace V₂ P₂] - -variable (f : P₁ →ᵃ[R] P₂) - -/-- The range of an affine map is an affine subspace. -/ -def range : AffineSubspace R P₂ where - carrier := Set.range f - smul_vsub_vadd_mem' := by - simp only [Set.mem_range, forall_exists_index] - intro c _ _ _ x₁ h₁ x₂ h₂ x₃ h₃ - exact ⟨c • (x₁ -ᵥ x₂) +ᵥ x₃, by simp [map_vadd, ← h₁, ← h₂, ← h₃]⟩ - -/-- The range of an affine map is nonempty. -/ -instance instNonemptyRange : Nonempty (range f) := - Set.instNonemptyRange f - -@[simp, norm_cast] -theorem coe_range : f.range = Set.range f := rfl - -@[simp] -theorem mem_range (x : P₂) : x ∈ f.range ↔ ∃ (y : P₁), f y = x := - Iff.rfl - -theorem range_eq_map_top : f.range = .map f ⊤ := by ext; simp - -theorem mem_range_self (x : P₁) : f x ∈ f.range := by simp - -@[simp] -theorem range_id : (id R P₁).range = ⊤ := by ext; simp - -theorem range_direction_eq_linear_range : f.range.direction = f.linear.range := by - rw [range_eq_map_top, map_direction, direction_top, Submodule.map_top] - -variable {f} in -theorem range_subset_iff {s : AffineSubspace R P₂} : f.range ≤ s ↔ ∀ y, f y ∈ s := by - simp [AffineSubspace.le_def'] - -/-- Restrict the codomain of an affine map `f` to `f.range`. -/ -def rangeRestrict : P₁ →ᵃ[R] f.range where - toFun p := ⟨f p, p, rfl⟩ - linear := f.linear.codRestrict f.range.direction - (f.range_direction_eq_linear_range ▸ f.linear.mem_range_self) - map_vadd' _ _ := by ext; simp [map_vadd] - -theorem surjective_rangeRestrict : Function.Surjective ⇑f.rangeRestrict := - fun ⟨_, y, rfl⟩ => ⟨y, rfl⟩ - -@[simp] -theorem range_rangeRestrict : f.rangeRestrict.range = ⊤ := by - ext ⟨_, x, rfl⟩ - simpa [AffineSubspace.mem_top, iff_true] using ⟨x, rfl⟩ - -@[simp] -theorem injective_rangeRestrict_iff : - Function.Injective (rangeRestrict f) ↔ Function.Injective f := by - convert (Function.Injective.of_comp_iff Subtype.val_injective f.rangeRestrict).symm - ext; simp [rangeRestrict] - -end AffineMap - -end diff --git a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean index 0269d8f3..b6530a8e 100644 --- a/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean +++ b/Polyhedral/Mathlib/LinearAlgebra/AffineSpace/Homogenization/IsHomogenization.lean @@ -6,7 +6,7 @@ Authors: Olivia Röhrig, Martin Winter module public import Mathlib.LinearAlgebra.AffineSpace.AffineMap -public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range +public import Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Range public import Mathlib.LinearAlgebra.AffineSpace.Homogenization public import Polyhedral.Mathlib.LinearAlgebra.AffineSpace.AffineSubspace.Basic @@ -174,7 +174,7 @@ lemma comp_lift_eq_weight (h : ∀ p, g (f p) = 1) : g ∘ₗ (ℋ.lift f) = ℋ lemma lift_bijective_injective_range_comap (hinj : Injective f) (hrange : f.range = comap g.toAffineMap {1}) : Bijective (ℋ.lift f) := by - have g_f : ∀ p, g (f p) = 1 := AffineMap.range_subset_iff.mp hrange.le + have g_f : ∀ p, g (f p) = 1 := Set.range_subset_iff.mp hrange.le constructor · rw [injective_iff_map_eq_zero] intro a ha diff --git a/lake-manifest.json b/lake-manifest.json index 4810c658..3e505232 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,7 +5,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "cfc55fc58714a59dc06e6e79edc6d1d95140d3c2", + "rev": "eb6d361fd932140a10cc8d9f4be0db7f73b9bedf", "name": "mathlib", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -35,7 +35,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "dfa4f38190d07c37e315953e08b90fe2d95b3c24", + "rev": "c2d7840c65673533e15b499f25beecdc6227f7d8", "name": "plausible", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -45,7 +45,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "d6b4c7be5be75ec4917c873ac50c756dc1436372", + "rev": "9d39f9bb0c30aa2f6200808805ff16e6ce950890", "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -55,7 +55,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "a41f0e9a4dea23188ea9cc1c41ac9f8bbafe0b93", + "rev": "19a8e822bfeace1ae4e090045aad81e0c930e6cf", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "df72b022e558978a1c50264cfc4d7fec86fa8e04", + "rev": "ff78fbc75a9bffb4ef08f8c290e268d120cd27d7", "name": "proofwidgets", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -75,7 +75,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "4a174c490d8707121c4a9290800489f105d85e07", + "rev": "29c64c56cc38211d39b306db2df11701e3d3de11", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -85,7 +85,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "dce0ad79c486cb1fb504af04f953c3466b0c6db8", + "rev": "6d26f8bb4b2bb78f929ad160feac508866821316", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -95,7 +95,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "66e469188fe07963e5cf666c7d4433f45b8131c5", + "rev": "8e746d768c73b716c7d4bc07bd8e73f2a75bdb60", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -115,10 +115,10 @@ "type": "git", "subDir": null, "scope": "leanprover", - "rev": "c24fe6078c630e89b489bffe59b3e20ac30d12c8", + "rev": "34d2efffcb6dc8d5f3537cf6a7f88bfaa999ec49", "name": "Cli", "manifestFile": "lake-manifest.json", - "inputRev": "v4.35.0", + "inputRev": "v4.36.0-rc1", "inherited": true, "configFile": "lakefile.toml"}, {"url": "https://github.com/fgdorais/lean4-unicode-basic", diff --git a/lean-toolchain b/lean-toolchain index a6aff065..d0cf8c52 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.35.0 +leanprover/lean4:v4.36.0-rc1 \ No newline at end of file From f96537e429ba66026f6a8a8fdfd497ac89b7e991 Mon Sep 17 00:00:00 2001 From: ovi Date: Wed, 21 Oct 2026 11:31:23 +0200 Subject: [PATCH 39/39] moving moritz/louis proof from workshop repo --- Polyhedral.lean | 1 + .../ConvexSpace/Polytope/KreinMilman.lean | 30 +++---------------- .../Convex/ConvexSpace/Set/Face/Basic.lean | 23 -------------- .../ConvexSpace/Set/Homogenization.lean | 17 +++++++++++ 4 files changed, 22 insertions(+), 49 deletions(-) diff --git a/Polyhedral.lean b/Polyhedral.lean index 3015c0e1..27628350 100644 --- a/Polyhedral.lean +++ b/Polyhedral.lean @@ -53,6 +53,7 @@ public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polyhedron.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Basic public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Face public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Homogenization +public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.KreinMilman public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Lattice public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Polytope.Pointwise public import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Set.Face.Basic diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean index aa1a7bc7..32135c29 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Polytope/KreinMilman.lean @@ -1,8 +1,3 @@ -/- -Copyright (c) 2026 Olivia Röhrig, Martin Winter. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Martin Winter, Olivia Röhrig --/ import Polyhedral.Mathlib.Geometry.Convex.Cone.Pointed.Finite.Face.Basic import Polyhedral.Mathlib.Geometry.Convex.ConvexSpace.Module @@ -31,29 +26,12 @@ variable [AddTorsor V A] variable {P : Set A} -variable {W} [AddCommGroup W] [Module R W] (ℋ : Affine.IsHomogenization R A W) in -/-- The dehomogenization of the ray spanned by an embedded point is the singleton of that -point. -/ -@[simp] lemma dehomogenize_hull_singleton_ofPoint (p : A) : - Convexity.dehomogenize ℋ (R ∙₊ ℋ.ofPoint p) = {p} := by - ext q - constructor - · intro hq - have hq' : ℋ.ofPoint q ∈ R ∙₊ ℋ.ofPoint p := hq - simp only [Submodule.mem_span_singleton, Subtype.exists, Nonneg.mk_smul, exists_prop] at hq' - obtain ⟨c, -, hc⟩ := hq' - have hw := congrArg ℋ.weight hc - simp only [map_smul, ℋ.weight_ofPoint, smul_eq_mul, mul_one] at hw - rw [hw, one_smul] at hc - exact ℋ.ofPoint_injective hc ▸ rfl - · rintro rfl - simp [Convexity.dehomogenize] - variable [ConvexSpace R A] [IsAffineConvexSpace R V A] +include V in /-- If a point `x` does not lie in the convex hull of a set `s`, then the singleton of `x` is a face of the convex hull of `insert x s`. -/ -lemma IsFaceOf.singleton_convexHull_insert {s : Set A} {x : A} {v : V} (hx : x ∉ convexHull R s) : +lemma IsFaceOf.singleton_convexHull_insert {s : Set A} {x : A} (hx : x ∉ convexHull R s) : IsFaceOf R ({x} : Set A) (convexHull R (insert x s)) := by let : ConvexSpace R (Homogenization R A) := .ofModule let ℋ := IsHomogenization.canonical R A @@ -61,7 +39,7 @@ lemma IsFaceOf.singleton_convexHull_insert {s : Set A} {x : A} {v : V} (hx : x PointedCone.hull R (ℋ.ofPoint '' s) ⊔ (R ∙₊ ℋ.ofPoint x) := by rw [← hull_image_ofPoint_eq_homogenize_convexHull, Set.image_insert_eq, hull_insert, sup_comm] have hnot : ℋ.ofPoint x ∉ PointedCone.hull R (ℋ.ofPoint '' s) := by - rw [hull_image_ofPoint_eq_homogenize_convexHull (ℋ := ℋ)] + rw [hull_image_ofPoint_eq_homogenize_convexHull] exact fun h => hx ((ofPoint_mem_homogenize_iff_mem _ x IsConvexSet.convexHull).mp h) have hsal : (PointedCone.hull R (ℋ.ofPoint '' s) ⊔ (R ∙₊ ℋ.ofPoint x)).Salient := hhom ▸ homogenize_salient _ _ @@ -71,6 +49,7 @@ lemma IsFaceOf.singleton_convexHull_insert {s : Set A} {x : A} {v : V} (hx : x rwa [dehomogenize_homogenize, dehomogenize_hull_singleton_ofPoint ℋ x] at h exact IsConvexSet.convexHull +include V in /-- Krein-Milman theorem for polytopes: every polytope is the convex hull of its vertices, that is, of the finite set of points whose singletons are faces. -/ theorem IsPolytope.krein_milman (hP : IsPolytope R P) : @@ -89,7 +68,6 @@ theorem IsPolytope.krein_milman (hP : IsPolytope R P) : obtain ⟨x, hxt, hx⟩ := hex refine ih (t.erase x) (Finset.erase_ssubset hxt) P ?_ rw [← hP] - -- ext refine subset_antisymm (convexHull_mono (Finset.coe_subset.mpr (Finset.erase_subset x t))) ?_ refine (IsConvexSet.convexHull_subset_iff IsConvexSet.convexHull).mpr ?_ diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean index a2f919c5..85d1a258 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Face/Basic.lean @@ -134,7 +134,6 @@ theorem preimage {φ : M → N} (hφ : IsAffineMap R φ) (hF : IsFaceOf R F₂ C refine hF.3 hx hy hz ⟨a, b, ha, hb, hab, ?_⟩ exact hcomb ▸ (hφ.map_convexCombPair ha.le hb.le hab x y).symm -<<<<<<< HEAD theorem of_map_injective {φ : M → N} (hφ : IsAffineMap R φ) (hinj : Injective φ) (hF : IsFaceOf R (φ '' F₁) (φ '' C₁)) : IsFaceOf R F₁ C₁ := by have h' := IsFaceOf.preimage hφ hF @@ -154,28 +153,6 @@ theorem of_preimage_surjective {φ : M → N} (hφ : IsAffineMap R φ) (hsurj : exact hc.left_mem_of_mem_Ioo xC yC zF b end Map -======= -/- `F` is a face of `C` iff the image of `F` is a face of the image of `C` under an injective affine -map -/ -theorem isFaceOf_map_iff {f : M₁ → M₂} {F C : ConvexSet R M₁} (hhf : IsAffineMap R f) - (hf : Injective f) : (F.map hhf).IsFaceOf (C.map hhf) ↔ F.IsFaceOf C := by - constructor - · intro h - have hh := comap_face hhf h - have h (A : ConvexSet R M₁) : (A.map hhf).comap hhf = A := by - ext z - constructor - · intro hz - rcases hz with ⟨y, hy, hzy⟩ - rw [hf hzy] at hy - use hy - · intro hz - exact ⟨z, hz, rfl⟩ - rw [h F, h C] at hh - exact hh - · intro h - apply map hhf hf h ->>>>>>> version-bump end IsFaceOf diff --git a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean index 021493f8..da1d061c 100644 --- a/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean +++ b/Polyhedral/Mathlib/Geometry/Convex/ConvexSpace/Set/Homogenization.lean @@ -145,6 +145,23 @@ lemma ofPoint_dehomogenize_eq_inter_ofPoint (C : PointedCone R W) : use y simpa +/-- The dehomogenization of the ray spanned by an embedded point is the singleton of that +point. -/ +@[simp] +lemma dehomogenize_hull_singleton_ofPoint (p : A) : dehomogenize ℋ (R ∙₊ ℋ.ofPoint p) = {p} := by + ext q + constructor + · intro hq + simp only [dehomogenize, mem_preimage, SetLike.mem_coe, mem_span_singleton, Subtype.exists, + Nonneg.mk_smul] at hq + obtain ⟨a, -, ha⟩ := hq + have hw := congrArg ℋ.weight ha + simp only [map_smul, ℋ.weight_ofPoint, smul_eq_mul, mul_one] at hw + rw [hw, one_smul] at ha + exact ℋ.ofPoint_injective ha ▸ rfl + · rintro rfl + simp [Convexity.dehomogenize] + section variable [ConvexSpace R A] [ConvexSpace R W] [IsModuleConvexSpace R W] [IsAffineConvexSpace R V A]