|
| 1 | +/- |
| 2 | +Copyright (c) 2024 Yaël Dillies. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Yaël Dillies |
| 5 | +-/ |
| 6 | +import Mathlib.Algebra.Group.Pointwise.Set.Card |
| 7 | +import Mathlib.Analysis.Convex.Between |
| 8 | +import Mathlib.Analysis.Convex.Combination |
| 9 | +import Mathlib.Topology.Algebra.Affine |
| 10 | +import Mathlib.Topology.MetricSpace.Pseudo.Lemmas |
| 11 | +import Mathlib.Topology.Order.Monotone |
| 12 | + |
| 13 | +/-! |
| 14 | +# Points in sight |
| 15 | +
|
| 16 | +This file defines the relation of visibility with respect to a set, and lower bounds how many |
| 17 | +elements of a set a point sees in terms of the dimension of that set. |
| 18 | +
|
| 19 | +## TODO |
| 20 | +
|
| 21 | +The art gallery problem can be stated using the visibility predicate: A set `A` (the art gallery) is |
| 22 | +guarded by a finite set `G` (the guards) iff `∀ a ∈ A, ∃ g ∈ G, IsVisible ℝ sᶜ a g`. |
| 23 | +-/ |
| 24 | + |
| 25 | +open AffineMap Filter Finset Set |
| 26 | +open scoped Cardinal Pointwise Topology |
| 27 | + |
| 28 | +variable {𝕜 V P : Type*} |
| 29 | + |
| 30 | +section AddTorsor |
| 31 | +variable [LinearOrderedField 𝕜] [AddCommGroup V] [Module 𝕜 V] [AddTorsor V P] |
| 32 | + {s t : Set P} {x y z : P} |
| 33 | + |
| 34 | +variable (𝕜) in |
| 35 | +/-- Two points are visible to each other through a set if no point of that set lies strictly |
| 36 | +between them. |
| 37 | +
|
| 38 | +By convention, a point `x` sees itself through any set `s`, even when `x ∈ s`. -/ |
| 39 | +def IsVisible (s : Set P) (x y : P) : Prop := ∀ ⦃z⦄, z ∈ s → ¬ Sbtw 𝕜 x z y |
| 40 | + |
| 41 | +@[simp, refl] lemma IsVisible.rfl : IsVisible 𝕜 s x x := by simp [IsVisible] |
| 42 | + |
| 43 | +lemma isVisible_comm : IsVisible 𝕜 s x y ↔ IsVisible 𝕜 s y x := by simp [IsVisible, sbtw_comm] |
| 44 | + |
| 45 | +@[symm] alias ⟨IsVisible.symm, _⟩ := isVisible_comm |
| 46 | + |
| 47 | +lemma IsVisible.mono (hst : s ⊆ t) (ht : IsVisible 𝕜 t x y) : IsVisible 𝕜 s x y := |
| 48 | + fun _z hz ↦ ht <| hst hz |
| 49 | + |
| 50 | +lemma isVisible_iff_lineMap (hxy : x ≠ y) : |
| 51 | + IsVisible 𝕜 s x y ↔ ∀ δ ∈ Set.Ioo (0 : 𝕜) 1, lineMap x y δ ∉ s := by |
| 52 | + simp [IsVisible, sbtw_iff_mem_image_Ioo_and_ne, hxy] |
| 53 | + aesop |
| 54 | + |
| 55 | +end AddTorsor |
| 56 | + |
| 57 | +section Module |
| 58 | +variable [LinearOrderedField 𝕜] [AddCommGroup V] [Module 𝕜 V] {s : Set V} {x y z : V} |
| 59 | + |
| 60 | +/-- If a point `x` sees a convex combination of points of a set `s` through `convexHull ℝ s ∌ x`, |
| 61 | +then it sees all terms of that combination. |
| 62 | +
|
| 63 | +Note that the converse does not hold. -/ |
| 64 | +lemma IsVisible.of_convexHull_of_pos {ι : Type*} {t : Finset ι} {a : ι → V} {w : ι → 𝕜} |
| 65 | + (hw₀ : ∀ i ∈ t, 0 ≤ w i) (hw₁ : ∑ i ∈ t, w i = 1) (ha : ∀ i ∈ t, a i ∈ s) |
| 66 | + (hx : x ∉ convexHull 𝕜 s) (hw : IsVisible 𝕜 (convexHull 𝕜 s) x (∑ i ∈ t, w i • a i)) {i : ι} |
| 67 | + (hi : i ∈ t) (hwi : 0 < w i) : IsVisible 𝕜 (convexHull 𝕜 s) x (a i) := by |
| 68 | + classical |
| 69 | + obtain hwi | hwi : w i = 1 ∨ w i < 1 := eq_or_lt_of_le <| (single_le_sum hw₀ hi).trans_eq hw₁ |
| 70 | + · convert hw |
| 71 | + rw [← one_smul 𝕜 (a i), ← hwi, eq_comm] |
| 72 | + rw [← hwi, ← sub_eq_zero, ← sum_erase_eq_sub hi, |
| 73 | + sum_eq_zero_iff_of_nonneg fun j hj ↦ hw₀ _ <| erase_subset _ _ hj] at hw₁ |
| 74 | + refine sum_eq_single _ (fun j hj hji ↦ ?_) (by simp [hi]) |
| 75 | + rw [hw₁ _ <| mem_erase.2 ⟨hji, hj⟩, zero_smul] |
| 76 | + rintro _ hε ⟨⟨ε, ⟨hε₀, hε₁⟩, rfl⟩, h⟩ |
| 77 | + replace hε₀ : 0 < ε := hε₀.lt_of_ne <| by rintro rfl; simp at h |
| 78 | + replace hε₁ : ε < 1 := hε₁.lt_of_ne <| by rintro rfl; simp at h |
| 79 | + have : 0 < 1 - ε := by linarith |
| 80 | + have hwi : 0 < 1 - w i := by linarith |
| 81 | + refine hw (z := lineMap x (∑ j ∈ t, w j • a j) ((w i)⁻¹ / ((1 - ε) / ε + (w i)⁻¹))) |
| 82 | + ?_ <| sbtw_lineMap_iff.2 ⟨(ne_of_mem_of_not_mem ((convex_convexHull ..).sum_mem hw₀ hw₁ |
| 83 | + fun i hi ↦ subset_convexHull _ _ <| ha _ hi) hx).symm, by positivity, |
| 84 | + (div_lt_one <| by positivity).2 ?_⟩ |
| 85 | + · have : Wbtw 𝕜 |
| 86 | + (lineMap x (a i) ε) |
| 87 | + (lineMap x (∑ j ∈ t, w j • a j) ((w i)⁻¹ / ((1 - ε) / ε + (w i)⁻¹))) |
| 88 | + (∑ j ∈ t.erase i, (w j / (1 - w i)) • a j) := by |
| 89 | + refine ⟨((1 - w i) / w i) / ((1 - ε) / ε + (1 - w i) / w i + 1), ⟨by positivity, ?_⟩, ?_⟩ |
| 90 | + · refine (div_le_one <| by positivity).2 ?_ |
| 91 | + calc |
| 92 | + (1 - w i) / w i = 0 + (1 - w i) / w i + 0 := by simp |
| 93 | + _ ≤ (1 - ε) / ε + (1 - w i) / w i + 1 := by gcongr <;> positivity |
| 94 | + have : |
| 95 | + w i • a i + (1 - w i) • ∑ j ∈ t.erase i, (w j / (1 - w i)) • a j = ∑ j ∈ t, w j • a j := by |
| 96 | + rw [smul_sum] |
| 97 | + simp_rw [smul_smul, mul_div_cancel₀ _ hwi.ne'] |
| 98 | + exact add_sum_erase _ (fun i ↦ w i • a i) hi |
| 99 | + simp_rw [lineMap_apply_module, ← this, smul_add, smul_smul] |
| 100 | + match_scalars <;> field_simp <;> ring |
| 101 | + refine (convex_convexHull _ _).mem_of_wbtw this hε <| (convex_convexHull _ _).sum_mem ?_ ?_ ?_ |
| 102 | + · intros j hj |
| 103 | + have := hw₀ j <| erase_subset _ _ hj |
| 104 | + positivity |
| 105 | + · rw [← sum_div, sum_erase_eq_sub hi, hw₁, div_self hwi.ne'] |
| 106 | + · exact fun j hj ↦ subset_convexHull _ _ <| ha _ <| erase_subset _ _ hj |
| 107 | + · exact lt_add_of_pos_left _ <| by positivity |
| 108 | + |
| 109 | +variable [TopologicalSpace 𝕜] [OrderTopology 𝕜] [TopologicalSpace V] [TopologicalAddGroup V] |
| 110 | + [ContinuousSMul 𝕜 V] |
| 111 | + |
| 112 | +/-- One cannot see any point in the interior of a set. -/ |
| 113 | +lemma IsVisible.eq_of_mem_interior (hsxy : IsVisible 𝕜 s x y) (hy : y ∈ interior s) : |
| 114 | + x = y := by |
| 115 | + by_contra! hxy |
| 116 | + suffices h : ∀ᶠ (_δ : 𝕜) in 𝓝[>] 0, False by obtain ⟨_, ⟨⟩⟩ := h.exists |
| 117 | + have hmem : ∀ᶠ (δ : 𝕜) in 𝓝[>] 0, lineMap y x δ ∈ s := |
| 118 | + lineMap_continuous.continuousWithinAt.eventually_mem |
| 119 | + (by simpa using mem_interior_iff_mem_nhds.1 hy) |
| 120 | + filter_upwards [hmem, Ioo_mem_nhdsWithin_Ioi' zero_lt_one] with δ hmem hsbt |
| 121 | + using hsxy.symm hmem (by aesop) |
| 122 | + |
| 123 | +/-- One cannot see any point of an open set. -/ |
| 124 | +lemma IsOpen.eq_of_isVisible_of_left_mem (hs : IsOpen s) (hsxy : IsVisible 𝕜 s x y) (hy : y ∈ s) : |
| 125 | + x = y := |
| 126 | + hsxy.eq_of_mem_interior (by simpa [hs.interior_eq]) |
| 127 | + |
| 128 | +end Module |
| 129 | + |
| 130 | +section Real |
| 131 | +variable [AddCommGroup V] [Module ℝ V] {s : Set V} {x y z : V} |
| 132 | + |
| 133 | +/-- All points of the convex hull of a set `s` visible from a point `x ∉ convexHull ℝ s` lie in the |
| 134 | +convex hull of such points that actually lie in `s`. |
| 135 | +
|
| 136 | +Note that the converse does not hold. -/ |
| 137 | +lemma IsVisible.mem_convexHull_isVisible (hx : x ∉ convexHull ℝ s) (hy : y ∈ convexHull ℝ s) |
| 138 | + (hxy : IsVisible ℝ (convexHull ℝ s) x y) : |
| 139 | + y ∈ convexHull ℝ {z ∈ s | IsVisible ℝ (convexHull ℝ s) x z} := by |
| 140 | + classical |
| 141 | + obtain ⟨ι, _, w, a, hw₀, hw₁, ha, rfl⟩ := mem_convexHull_iff_exists_fintype.1 hy |
| 142 | + rw [← Fintype.sum_subset (s := {i | w i ≠ 0}) |
| 143 | + fun i hi ↦ mem_filter.2 ⟨mem_univ _, left_ne_zero_of_smul hi⟩] |
| 144 | + exact (convex_convexHull ..).sum_mem (fun i _ ↦ hw₀ _) (by rwa [sum_filter_ne_zero]) |
| 145 | + fun i hi ↦ subset_convexHull _ _ ⟨ha _, IsVisible.of_convexHull_of_pos (fun _ _ ↦ hw₀ _) hw₁ |
| 146 | + (by simpa) hx hxy (mem_univ _) <| (hw₀ _).lt_of_ne' (mem_filter.1 hi).2⟩ |
| 147 | + |
| 148 | +variable [TopologicalSpace V] [TopologicalAddGroup V] [ContinuousSMul ℝ V] |
| 149 | + |
| 150 | +/-- If `s` is a closed set, then any point `x` sees some point of `s` in any direction where there |
| 151 | +is something to see. -/ |
| 152 | +lemma IsClosed.exists_wbtw_isVisible (hs : IsClosed s) (hy : y ∈ s) (x : V) : |
| 153 | + ∃ z ∈ s, Wbtw ℝ x z y ∧ IsVisible ℝ s x z := by |
| 154 | + let t : Set ℝ := Ici 0 ∩ lineMap x y ⁻¹' s |
| 155 | + have ht₁ : 1 ∈ t := by simpa [t] |
| 156 | + have ht : BddBelow t := bddBelow_Ici.inter_of_left |
| 157 | + let δ : ℝ := sInf t |
| 158 | + have hδ₁ : δ ≤ 1 := csInf_le ht ht₁ |
| 159 | + obtain ⟨hδ₀, hδ⟩ : 0 ≤ δ ∧ lineMap x y δ ∈ s := |
| 160 | + (isClosed_Ici.inter <| hs.preimage lineMap_continuous).csInf_mem ⟨1, ht₁⟩ ht |
| 161 | + refine ⟨lineMap x y δ, hδ, wbtw_lineMap_iff.2 <| .inr ⟨hδ₀, hδ₁⟩, ?_⟩ |
| 162 | + rintro _ hε ⟨⟨ε, ⟨hε₀, hε₁⟩, rfl⟩, -, h⟩ |
| 163 | + replace hδ₀ : 0 < δ := hδ₀.lt_of_ne' <| by rintro hδ₀; simp [hδ₀] at h |
| 164 | + replace hε₁ : ε < 1 := hε₁.lt_of_ne <| by rintro rfl; simp at h |
| 165 | + rw [lineMap_lineMap_right] at hε |
| 166 | + exact (csInf_le ht ⟨mul_nonneg hε₀ hδ₀.le, hε⟩).not_lt <| mul_lt_of_lt_one_left hδ₀ hε₁ |
| 167 | + |
| 168 | +-- TODO: Once we have cone hulls, the RHS can be strengthened to |
| 169 | +-- `coneHull ℝ x {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y}` |
| 170 | +/-- A set whose convex hull is closed lies in the cone based at a point `x` generated by its points |
| 171 | +visible from `x` through its convex hull. -/ |
| 172 | +lemma IsClosed.convexHull_subset_affineSpan_isVisible (hs : IsClosed (convexHull ℝ s)) |
| 173 | + (hx : x ∉ convexHull ℝ s) : |
| 174 | + convexHull ℝ s ⊆ affineSpan ℝ ({x} ∪ {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y}) := by |
| 175 | + rintro y hy |
| 176 | + obtain ⟨z, hz, hxzy, hxz⟩ := hs.exists_wbtw_isVisible hy x |
| 177 | + -- TODO: `calc` doesn't work with `∈` :( |
| 178 | + exact AffineSubspace.right_mem_of_wbtw hxzy (subset_affineSpan _ _ <| subset_union_left rfl) |
| 179 | + (affineSpan_mono _ subset_union_right <| convexHull_subset_affineSpan _ <| |
| 180 | + hxz.mem_convexHull_isVisible hx hz) (ne_of_mem_of_not_mem hz hx).symm |
| 181 | + |
| 182 | +open Submodule in |
| 183 | +/-- If `s` is a closed set of dimension `d` and `x` is a point outside of its convex hull, |
| 184 | +then `x` sees at least `d` points of the convex hull of `s` that actually lie in `s`. -/ |
| 185 | +lemma rank_le_card_isVisible (hs : IsClosed (convexHull ℝ s)) (hx : x ∉ convexHull ℝ s) : |
| 186 | + Module.rank ℝ (span ℝ (-x +ᵥ s)) ≤ #{y ∈ s | IsVisible ℝ (convexHull ℝ s) x y} := by |
| 187 | + calc |
| 188 | + Module.rank ℝ (span ℝ (-x +ᵥ s)) ≤ |
| 189 | + Module.rank ℝ (span ℝ |
| 190 | + (-x +ᵥ affineSpan ℝ ({x} ∪ {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y}) : Set V)) := by |
| 191 | + push_cast |
| 192 | + refine Submodule.rank_mono ?_ |
| 193 | + gcongr |
| 194 | + exact (subset_convexHull ..).trans <| hs.convexHull_subset_affineSpan_isVisible hx |
| 195 | + _ = Module.rank ℝ (span ℝ (-x +ᵥ {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y})) := by |
| 196 | + suffices h : |
| 197 | + -x +ᵥ (affineSpan ℝ ({x} ∪ {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y}) : Set V) = |
| 198 | + span ℝ (-x +ᵥ {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y}) by |
| 199 | + rw [AffineSubspace.coe_pointwise_vadd, h, span_span] |
| 200 | + simp [← AffineSubspace.coe_pointwise_vadd, AffineSubspace.pointwise_vadd_span, |
| 201 | + vadd_set_insert, -coe_affineSpan, affineSpan_insert_zero] |
| 202 | + _ ≤ #(-x +ᵥ {y ∈ s | IsVisible ℝ (convexHull ℝ s) x y}) := rank_span_le _ |
| 203 | + _ = #{y ∈ s | IsVisible ℝ (convexHull ℝ s) x y} := by simp |
| 204 | + |
| 205 | +end Real |
0 commit comments