Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit b360751

Browse files
committed
feat(analysis/calculus/bump_function_findim): construct good bump functions on finite-dimensional spaces (#18095)
On any finite-dimensional real vector space, we construct a smooth family of smooth functions indexed by `R > 1` which are equal to `1` on the ball `B 0 1`, and with support exactly `B 0 R`. This is the main ingredient to construct nice bump functions.
1 parent 938fead commit b360751

File tree

2 files changed

+398
-0
lines changed

2 files changed

+398
-0
lines changed

src/analysis/calculus/bump_function_findim.lean

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import analysis.calculus.specific_functions
77
import analysis.calculus.series
88
import analysis.convolution
99
import data.set.pointwise.support
10+
import measure_theory.measure.haar_lebesgue
1011

1112
/-!
1213
# Bump functions in finite-dimensional vector spaces
@@ -194,3 +195,376 @@ begin
194195
end
195196

196197
end
198+
199+
section
200+
201+
namespace exists_cont_diff_bump_base
202+
203+
/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces.
204+
It is the characteristic function of the closed unit ball. -/
205+
def φ : E → ℝ := (closed_ball (0 : E) 1).indicator (λ y, (1 : ℝ))
206+
207+
variables [normed_space ℝ E] [finite_dimensional ℝ E]
208+
209+
section helper_definitions
210+
211+
variable (E)
212+
lemma u_exists : ∃ u : E → ℝ, cont_diff ℝ ⊤ u ∧
213+
(∀ x, u x ∈ Icc (0 : ℝ) 1) ∧ (support u = ball 0 1) ∧ (∀ x, u (-x) = u x) :=
214+
begin
215+
have A : is_open (ball (0 : E) 1), from is_open_ball,
216+
obtain ⟨f, f_support, f_smooth, f_range⟩ :
217+
∃ (f : E → ℝ), f.support = ball (0 : E) 1 ∧ cont_diff ℝ ⊤ f ∧ set.range f ⊆ set.Icc 0 1,
218+
from A.exists_smooth_support_eq,
219+
have B : ∀ x, f x ∈ Icc (0 : ℝ) 1 := λ x, f_range (mem_range_self x),
220+
refine ⟨λ x, (f x + f (-x)) / 2, _, _, _, _⟩,
221+
{ exact (f_smooth.add (f_smooth.comp cont_diff_neg)).div_const },
222+
{ assume x,
223+
split,
224+
{ linarith [(B x).1, (B (-x)).1] },
225+
{ linarith [(B x).2, (B (-x)).2] } },
226+
{ refine support_eq_iff.2 ⟨λ x hx, _, λ x hx, _⟩,
227+
{ apply ne_of_gt,
228+
have : 0 < f x,
229+
{ apply lt_of_le_of_ne (B x).1 (ne.symm _),
230+
rwa ← f_support at hx },
231+
linarith [(B (-x)).1] },
232+
{ have I1 : x ∉ support f, by rwa f_support,
233+
have I2 : -x ∉ support f,
234+
{ rw f_support,
235+
simp only at hx,
236+
simpa using hx },
237+
simp only [mem_support, not_not] at I1 I2,
238+
simp only [I1, I2, add_zero, zero_div] } },
239+
{ assume x, simp only [add_comm, neg_neg] }
240+
end
241+
242+
variable {E}
243+
244+
/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces,
245+
which is smooth, symmetric, and with support equal to the unit ball. -/
246+
def u (x : E) : ℝ := classical.some (u_exists E) x
247+
248+
variable (E)
249+
lemma u_smooth : cont_diff ℝ ⊤ (u : E → ℝ) := (classical.some_spec (u_exists E)).1
250+
251+
lemma u_continuous : continuous (u : E → ℝ) := (u_smooth E).continuous
252+
253+
lemma u_support : support (u : E → ℝ) = ball 0 1 := (classical.some_spec (u_exists E)).2.2.1
254+
255+
lemma u_compact_support : has_compact_support (u : E → ℝ) :=
256+
begin
257+
rw [has_compact_support_def, u_support, closure_ball (0 : E) one_ne_zero],
258+
exact is_compact_closed_ball _ _,
259+
end
260+
variable {E}
261+
262+
lemma u_nonneg (x : E) : 0 ≤ u x := ((classical.some_spec (u_exists E)).2.1 x).1
263+
264+
lemma u_le_one (x : E) : u x ≤ 1 := ((classical.some_spec (u_exists E)).2.1 x).2
265+
266+
lemma u_neg (x : E) : u (-x) = u x := (classical.some_spec (u_exists E)).2.2.2 x
267+
268+
variables [measurable_space E] [borel_space E]
269+
270+
local notation ` := measure_theory.measure.add_haar
271+
272+
variable (E)
273+
lemma u_int_pos : 0 < ∫ (x : E), u x ∂μ :=
274+
begin
275+
refine (integral_pos_iff_support_of_nonneg u_nonneg _).mpr _,
276+
{ exact (u_continuous E).integrable_of_has_compact_support (u_compact_support E) },
277+
{ rw u_support, exact measure_ball_pos _ _ zero_lt_one }
278+
end
279+
variable {E}
280+
281+
/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces,
282+
which is smooth, symmetric, with support equal to the ball of radius `D` and integral `1`. -/
283+
def W (D : ℝ) (x : E) : ℝ := ((∫ (x : E), u x ∂μ) * |D|^(finrank ℝ E))⁻¹ • u (D⁻¹ • x)
284+
285+
lemma W_def (D : ℝ) :
286+
(W D : E → ℝ) = λ x, ((∫ (x : E), u x ∂μ) * |D|^(finrank ℝ E))⁻¹ • u (D⁻¹ • x) :=
287+
by { ext1 x, refl }
288+
289+
lemma W_nonneg (D : ℝ) (x : E) : 0 ≤ W D x :=
290+
begin
291+
apply mul_nonneg _ (u_nonneg _),
292+
apply inv_nonneg.2,
293+
apply mul_nonneg (u_int_pos E).le,
294+
apply pow_nonneg (abs_nonneg D)
295+
end
296+
297+
lemma W_mul_φ_nonneg (D : ℝ) (x y : E) : 0 ≤ W D y * φ (x - y) :=
298+
mul_nonneg (W_nonneg D y) (indicator_nonneg (by simp only [zero_le_one, implies_true_iff]) _)
299+
300+
variable (E)
301+
302+
lemma W_integral {D : ℝ} (Dpos : 0 < D) : ∫ (x : E), W D x ∂μ = 1 :=
303+
begin
304+
simp_rw [W, integral_smul],
305+
rw [integral_comp_inv_smul_of_nonneg μ (u : E → ℝ) Dpos.le,
306+
abs_of_nonneg Dpos.le, mul_comm],
307+
field_simp [Dpos.ne', (u_int_pos E).ne'],
308+
end
309+
310+
lemma W_support {D : ℝ} (Dpos : 0 < D) : support (W D : E → ℝ) = ball 0 D :=
311+
begin
312+
have B : D • ball (0 : E) 1 = ball 0 D,
313+
by rw [smul_unit_ball Dpos.ne', real.norm_of_nonneg Dpos.le],
314+
have C : D ^ finrank ℝ E ≠ 0, from pow_ne_zero _ Dpos.ne',
315+
simp only [W_def, algebra.id.smul_eq_mul, support_mul, support_inv, univ_inter,
316+
support_comp_inv_smul₀ Dpos.ne', u_support, B, support_const (u_int_pos E).ne',
317+
support_const C, abs_of_nonneg Dpos.le],
318+
end
319+
320+
lemma W_compact_support {D : ℝ} (Dpos : 0 < D) : has_compact_support (W D : E → ℝ) :=
321+
begin
322+
rw [has_compact_support_def, W_support E Dpos, closure_ball (0 : E) Dpos.ne'],
323+
exact is_compact_closed_ball _ _,
324+
end
325+
variable {E}
326+
327+
/-- An auxiliary function to construct partitions of unity on finite-dimensional real vector spaces.
328+
It is the convolution between a smooth function of integral `1` supported in the ball of radius `D`,
329+
with the indicator function of the closed unit ball. Therefore, it is smooth, equal to `1` on the
330+
ball of radius `1 - D`, with support equal to the ball of radius `1 + D`. -/
331+
def Y (D : ℝ) : E → ℝ := W D ⋆[lsmul ℝ ℝ, μ] φ
332+
333+
lemma Y_neg (D : ℝ) (x : E) : Y D (-x) = Y D x :=
334+
begin
335+
apply convolution_neg_of_neg_eq,
336+
{ apply eventually_of_forall (λ x, _),
337+
simp only [W_def, u_neg, smul_neg, algebra.id.smul_eq_mul, mul_eq_mul_left_iff,
338+
eq_self_iff_true, true_or], },
339+
{ apply eventually_of_forall (λ x, _),
340+
simp only [φ, indicator, mem_closed_ball_zero_iff, norm_neg] },
341+
end
342+
343+
lemma Y_eq_one_of_mem_closed_ball {D : ℝ} {x : E} (Dpos : 0 < D)
344+
(hx : x ∈ closed_ball (0 : E) (1 - D)) : Y D x = 1 :=
345+
begin
346+
change (W D ⋆[lsmul ℝ ℝ, μ] φ) x = 1,
347+
have B : ∀ (y : E), y ∈ ball x D → φ y = 1,
348+
{ have C : ball x D ⊆ ball 0 1,
349+
{ apply ball_subset_ball',
350+
simp only [mem_closed_ball] at hx,
351+
linarith only [hx] },
352+
assume y hy,
353+
simp only [φ, indicator, mem_closed_ball, ite_eq_left_iff, not_le, zero_ne_one],
354+
assume h'y,
355+
linarith only [mem_ball.1 (C hy), h'y] },
356+
have Bx : φ x = 1, from B _ (mem_ball_self Dpos),
357+
have B' : ∀ y, y ∈ ball x D → φ y = φ x, by { rw Bx, exact B },
358+
rw convolution_eq_right' _ (le_of_eq (W_support E Dpos)) B',
359+
simp only [lsmul_apply, algebra.id.smul_eq_mul, integral_mul_right, W_integral E Dpos, Bx,
360+
one_mul],
361+
end
362+
363+
lemma Y_eq_zero_of_not_mem_ball {D : ℝ} {x : E} (Dpos : 0 < D)
364+
(hx : x ∉ ball (0 : E) (1 + D)) : Y D x = 0 :=
365+
begin
366+
change (W D ⋆[lsmul ℝ ℝ, μ] φ) x = 0,
367+
have B : ∀ y, y ∈ ball x D → φ y = 0,
368+
{ assume y hy,
369+
simp only [φ, indicator, mem_closed_ball_zero_iff, ite_eq_right_iff, one_ne_zero],
370+
assume h'y,
371+
have C : ball y D ⊆ ball 0 (1+D),
372+
{ apply ball_subset_ball',
373+
rw ← dist_zero_right at h'y,
374+
linarith only [h'y] },
375+
exact hx (C (mem_ball_comm.1 hy)) },
376+
have Bx : φ x = 0, from B _ (mem_ball_self Dpos),
377+
have B' : ∀ y, y ∈ ball x D → φ y = φ x, by { rw Bx, exact B },
378+
rw convolution_eq_right' _ (le_of_eq (W_support E Dpos)) B',
379+
simp only [lsmul_apply, algebra.id.smul_eq_mul, Bx, mul_zero, integral_const]
380+
end
381+
382+
lemma Y_nonneg (D : ℝ) (x : E) : 0 ≤ Y D x :=
383+
integral_nonneg (W_mul_φ_nonneg D x)
384+
385+
lemma Y_le_one {D : ℝ} (x : E) (Dpos : 0 < D) : Y D x ≤ 1 :=
386+
begin
387+
have A : (W D ⋆[lsmul ℝ ℝ, μ] φ) x ≤ (W D ⋆[lsmul ℝ ℝ, μ] 1) x,
388+
{ apply convolution_mono_right_of_nonneg _ (W_nonneg D)
389+
(indicator_le_self' (λ x hx, zero_le_one)) (λ x, zero_le_one),
390+
refine (has_compact_support.convolution_exists_left _ (W_compact_support E Dpos) _
391+
(locally_integrable_const (1 : ℝ)) x).integrable,
392+
exact continuous_const.mul ((u_continuous E).comp (continuous_id.const_smul _)) },
393+
have B : (W D ⋆[lsmul ℝ ℝ, μ] (λ y, (1 : ℝ))) x = 1,
394+
by simp only [convolution, continuous_linear_map.map_smul, mul_inv_rev, coe_smul', mul_one,
395+
lsmul_apply, algebra.id.smul_eq_mul, integral_mul_left, W_integral E Dpos, pi.smul_apply],
396+
exact A.trans (le_of_eq B)
397+
end
398+
399+
lemma Y_pos_of_mem_ball {D : ℝ} {x : E} (Dpos : 0 < D) (D_lt_one : D < 1)
400+
(hx : x ∈ ball (0 : E) (1 + D)) : 0 < Y D x :=
401+
begin
402+
simp only [mem_ball_zero_iff] at hx,
403+
refine (integral_pos_iff_support_of_nonneg (W_mul_φ_nonneg D x) _).2 _,
404+
{ have F_comp : has_compact_support (W D),
405+
from W_compact_support E Dpos,
406+
have B : locally_integrable (φ : E → ℝ) μ,
407+
from (locally_integrable_const _).indicator measurable_set_closed_ball,
408+
have C : continuous (W D : E → ℝ),
409+
from continuous_const.mul ((u_continuous E).comp (continuous_id.const_smul _)),
410+
exact (has_compact_support.convolution_exists_left (lsmul ℝ ℝ : ℝ →L[ℝ] ℝ →L[ℝ] ℝ)
411+
F_comp C B x).integrable },
412+
{ set z := (D / (1 + D)) • x with hz,
413+
have B : 0 < 1 + D, by linarith,
414+
have C : ball z (D * (1 + D- ‖x‖) / (1 + D)) ⊆ support (λ (y : E), W D y * φ (x - y)),
415+
{ assume y hy,
416+
simp only [support_mul, W_support E Dpos],
417+
simp only [φ, mem_inter_iff, mem_support, ne.def, indicator_apply_eq_zero,
418+
mem_closed_ball_zero_iff, one_ne_zero, not_forall, not_false_iff, exists_prop, and_true],
419+
split,
420+
{ apply ball_subset_ball' _ hy,
421+
simp only [z, norm_smul, abs_of_nonneg Dpos.le, abs_of_nonneg B.le, dist_zero_right,
422+
real.norm_eq_abs, abs_div],
423+
simp only [div_le_iff B] with field_simps,
424+
ring_nf },
425+
{ have ID : ‖D / (1 + D) - 1‖ = 1 / (1 + D),
426+
{ rw real.norm_of_nonpos,
427+
{ simp only [B.ne', ne.def, not_false_iff, mul_one, neg_sub, add_tsub_cancel_right]
428+
with field_simps},
429+
{ simp only [B.ne', ne.def, not_false_iff, mul_one] with field_simps,
430+
apply div_nonpos_of_nonpos_of_nonneg _ B.le,
431+
linarith only, } },
432+
rw ← mem_closed_ball_iff_norm',
433+
apply closed_ball_subset_closed_ball' _ (ball_subset_closed_ball hy),
434+
rw [← one_smul ℝ x, dist_eq_norm, hz, ← sub_smul, one_smul, norm_smul, ID],
435+
simp only [-one_div, -mul_eq_zero, B.ne', div_le_iff B] with field_simps,
436+
simp only [mem_ball_zero_iff] at hx,
437+
nlinarith only [hx, D_lt_one] } },
438+
apply lt_of_lt_of_le _ (measure_mono C),
439+
apply measure_ball_pos,
440+
exact div_pos (mul_pos Dpos (by linarith only [hx])) B }
441+
end
442+
443+
variable (E)
444+
445+
lemma Y_smooth : cont_diff_on ℝ ⊤ (uncurry Y) ((Ioo (0 : ℝ) 1) ×ˢ (univ : set E)) :=
446+
begin
447+
have hs : is_open (Ioo (0 : ℝ) (1 : ℝ)), from is_open_Ioo,
448+
have hk : is_compact (closed_ball (0 : E) 1), from proper_space.is_compact_closed_ball _ _,
449+
refine cont_diff_on_convolution_left_with_param (lsmul ℝ ℝ) hs hk _ _ _,
450+
{ rintros p x hp hx,
451+
simp only [W, mul_inv_rev, algebra.id.smul_eq_mul, mul_eq_zero, inv_eq_zero],
452+
right,
453+
contrapose! hx,
454+
have : p⁻¹ • x ∈ support u, from mem_support.2 hx,
455+
simp only [u_support, norm_smul, mem_ball_zero_iff, real.norm_eq_abs, abs_inv,
456+
abs_of_nonneg hp.1.le, ← div_eq_inv_mul, div_lt_one hp.1] at this,
457+
rw mem_closed_ball_zero_iff,
458+
exact this.le.trans hp.2.le },
459+
{ exact (locally_integrable_const _).indicator measurable_set_closed_ball },
460+
{ apply cont_diff_on.mul,
461+
{ refine (cont_diff_on_const.mul _).inv
462+
(λ x hx, ne_of_gt (mul_pos (u_int_pos E) (pow_pos (abs_pos_of_pos hx.1.1) _))),
463+
apply cont_diff_on.pow,
464+
simp_rw [← real.norm_eq_abs],
465+
apply @cont_diff_on.norm ℝ,
466+
{ exact cont_diff_on_fst },
467+
{ assume x hx, exact ne_of_gt hx.1.1 } },
468+
{ apply (u_smooth E).comp_cont_diff_on,
469+
exact cont_diff_on.smul (cont_diff_on_fst.inv (λ x hx, ne_of_gt hx.1.1)) cont_diff_on_snd } },
470+
end
471+
472+
lemma Y_support {D : ℝ} (Dpos : 0 < D) (D_lt_one : D < 1) :
473+
support (Y D : E → ℝ) = ball (0 : E) (1 + D) :=
474+
support_eq_iff.2 ⟨λ x hx, (Y_pos_of_mem_ball Dpos D_lt_one hx).ne',
475+
λ x hx, Y_eq_zero_of_not_mem_ball Dpos hx⟩
476+
477+
variable {E}
478+
479+
end helper_definitions
480+
481+
/-- The base function from which one will construct a family of bump functions. One could
482+
add more properties if they are useful and satisfied in the examples of inner product spaces
483+
and finite dimensional vector spaces, notably derivative norm control in terms of `R - 1`.
484+
TODO: move to the right file and use this to refactor bump functions in general. -/
485+
@[nolint has_nonempty_instance]
486+
structure _root_.cont_diff_bump_base (E : Type*) [normed_add_comm_group E] [normed_space ℝ E] :=
487+
(to_fun : ℝ → E → ℝ)
488+
(mem_Icc : ∀ (R : ℝ) (x : E), to_fun R x ∈ Icc (0 : ℝ) 1)
489+
(symmetric : ∀ (R : ℝ) (x : E), to_fun R (-x) = to_fun R x)
490+
(smooth : cont_diff_on ℝ ⊤ (uncurry to_fun) ((Ioi (1 : ℝ)) ×ˢ (univ : set E)))
491+
(eq_one : ∀ (R : ℝ) (hR : 1 < R) (x : E) (hx : ‖x‖ ≤ 1), to_fun R x = 1)
492+
(support : ∀ (R : ℝ) (hR : 1 < R), support (to_fun R) = metric.ball (0 : E) R)
493+
494+
/-- A class registering that a real vector space admits bump functions. This will be instantiated
495+
first for inner product spaces, and then for finite-dimensional normed spaces.
496+
We use a specific class instead of `nonempty (cont_diff_bump_base E)` for performance reasons. -/
497+
class _root_.has_cont_diff_bump (E : Type*) [normed_add_comm_group E] [normed_space ℝ E] : Prop :=
498+
(out : nonempty (cont_diff_bump_base E))
499+
500+
@[priority 100]
501+
instance {E : Type*} [normed_add_comm_group E] [normed_space ℝ E] [finite_dimensional ℝ E] :
502+
has_cont_diff_bump E :=
503+
begin
504+
refine ⟨⟨_⟩⟩,
505+
borelize E,
506+
have IR : ∀ (R : ℝ), 1 < R → 0 < (R - 1) / (R + 1),
507+
{ assume R hR, apply div_pos; linarith },
508+
exact
509+
{ to_fun := λ R x, if 1 < R then Y ((R - 1) / (R + 1)) (((R + 1) / 2)⁻¹ • x) else 0,
510+
mem_Icc := λ R x, begin
511+
split_ifs,
512+
{ refine ⟨Y_nonneg _ _, Y_le_one _ (IR R h)⟩ },
513+
{ simp only [pi.zero_apply, left_mem_Icc, zero_le_one] }
514+
end,
515+
symmetric := λ R x, begin
516+
split_ifs,
517+
{ simp only [Y_neg, smul_neg] },
518+
{ refl },
519+
end,
520+
smooth := begin
521+
suffices : cont_diff_on ℝ ⊤
522+
((uncurry Y) ∘ (λ (p : ℝ × E), ((p.1 - 1) / (p.1 + 1), ((p.1 + 1)/2)⁻¹ • p.2)))
523+
(Ioi 1 ×ˢ univ),
524+
{ apply this.congr,
525+
rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
526+
simp only [hR, uncurry_apply_pair, if_true, comp_app], },
527+
apply (Y_smooth E).comp,
528+
{ apply cont_diff_on.prod,
529+
{ refine (cont_diff_on_fst.sub cont_diff_on_const).div
530+
(cont_diff_on_fst.add cont_diff_on_const) _,
531+
rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
532+
apply ne_of_gt,
533+
dsimp only,
534+
linarith, },
535+
{ apply cont_diff_on.smul _ cont_diff_on_snd,
536+
refine (cont_diff_on_fst.add cont_diff_on_const).div_const.inv _,
537+
rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
538+
apply ne_of_gt,
539+
dsimp only,
540+
linarith } },
541+
{ rintros ⟨R, x⟩ ⟨(hR : 1 < R), hx⟩,
542+
have A : 0 < (R - 1) / (R + 1), by { apply div_pos; linarith },
543+
have B : (R - 1) / (R + 1) < 1, by { apply (div_lt_one _ ).2; linarith },
544+
simp only [mem_preimage, prod_mk_mem_set_prod_eq, mem_Ioo, mem_univ, and_true, A, B] }
545+
end,
546+
eq_one := λ R hR x hx, begin
547+
have A : 0 < R + 1, by linarith,
548+
simp only [hR, if_true],
549+
apply Y_eq_one_of_mem_closed_ball (IR R hR),
550+
simp only [norm_smul, inv_div, mem_closed_ball_zero_iff, real.norm_eq_abs, abs_div,
551+
abs_two, abs_of_nonneg A.le],
552+
calc 2 / (R + 1) * ‖x‖ ≤ 2 / (R + 1) * 1 :
553+
mul_le_mul_of_nonneg_left hx (div_nonneg zero_le_two A.le)
554+
... = 1 - (R - 1) / (R + 1) : by { field_simp [A.ne'], ring }
555+
end,
556+
support := λ R hR, begin
557+
have A : 0 < (R + 1) / 2, by linarith,
558+
have A' : 0 < R + 1, by linarith,
559+
have C : (R - 1) / (R + 1) < 1, by { apply (div_lt_one _ ).2; linarith },
560+
simp only [hR, if_true, support_comp_inv_smul₀ A.ne', Y_support _ (IR R hR) C,
561+
smul_ball A.ne', real.norm_of_nonneg A.le, smul_zero],
562+
congr' 1,
563+
field_simp [A'.ne'],
564+
ring,
565+
end },
566+
end
567+
568+
end exists_cont_diff_bump_base
569+
570+
end

0 commit comments

Comments
 (0)