Skip to content

Commit b145b11

Browse files
ericrbgYaelDillies
andcommitted
feat: norm positivity extension proves strict positivity (#10276)
Closes #5265. Co-authored-by: Yaël Dillies <yael.dillies@gmail.com>
1 parent a0a62fe commit b145b11

File tree

8 files changed

+72
-47
lines changed

8 files changed

+72
-47
lines changed

Mathlib/Analysis/InnerProductSpace/Basic.lean

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,8 +645,6 @@ zero. See also `EuclideanGeometry.dist_inversion_inversion` for inversions aroun
645645
point. -/
646646
theorem dist_div_norm_sq_smul {x y : F} (hx : x ≠ 0) (hy : y ≠ 0) (R : ℝ) :
647647
dist ((R / ‖x‖) ^ 2 • x) ((R / ‖y‖) ^ 2 • y) = R ^ 2 / (‖x‖ * ‖y‖) * dist x y :=
648-
have hx' : ‖x‖ ≠ 0 := norm_ne_zero_iff.2 hx
649-
have hy' : ‖y‖ ≠ 0 := norm_ne_zero_iff.2 hy
650648
calc
651649
dist ((R / ‖x‖) ^ 2 • x) ((R / ‖y‖) ^ 2 • y) =
652650
√(‖(R / ‖x‖) ^ 2 • x - (R / ‖y‖) ^ 2 • y‖ ^ 2) := by

Mathlib/Analysis/InnerProductSpace/Rayleigh.lean

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ theorem rayleigh_smul (x : E) {c : 𝕜} (hc : c ≠ 0) :
5757
rayleighQuotient T (c • x) = rayleighQuotient T x := by
5858
by_cases hx : x = 0
5959
· simp [hx]
60-
have : ‖c‖ ≠ 0 := by simp [hc]
61-
have : ‖x‖ ≠ 0 := by simp [hx]
6260
field_simp [norm_smul, T.reApplyInnerSelf_smul]
6361
ring
6462

@@ -149,7 +147,6 @@ theorem eq_smul_self_of_isLocalExtrOn_real (hT : IsSelfAdjoint T) {x₀ : F}
149147
apply smul_right_injective F hb
150148
simp [c, eq_neg_of_add_eq_zero_left h₂, ← mul_smul, this]
151149
convert hc
152-
have : ‖x₀‖ ≠ 0 := by simp [hx₀]
153150
have := congr_arg (fun x => ⟪x, x₀⟫_ℝ) hc
154151
field_simp [inner_smul_left, real_inner_self_eq_norm_mul_norm, sq] at this ⊢
155152
exact this

Mathlib/Analysis/Normed/Group/Basic.lean

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -428,33 +428,6 @@ attribute [bound] norm_nonneg
428428
@[to_additive (attr := simp) abs_norm]
429429
theorem abs_norm' (z : E) : |‖z‖| = ‖z‖ := abs_of_nonneg <| norm_nonneg' _
430430

431-
namespace Mathlib.Meta.Positivity
432-
433-
open Lean Meta Qq Function
434-
435-
/-- Extension for the `positivity` tactic: multiplicative norms are nonnegative, via
436-
`norm_nonneg'`. -/
437-
@[positivity Norm.norm _]
438-
def evalMulNorm : PositivityExt where eval {u α} _zα _pα e := do
439-
match u, α, e with
440-
| 0, ~q(ℝ), ~q(@Norm.norm $β $instDist $a) =>
441-
let _inst ← synthInstanceQ q(SeminormedGroup $β)
442-
assertInstancesCommute
443-
pure (.nonnegative q(norm_nonneg' $a))
444-
| _, _, _ => throwError "not ‖ · ‖"
445-
446-
/-- Extension for the `positivity` tactic: additive norms are nonnegative, via `norm_nonneg`. -/
447-
@[positivity Norm.norm _]
448-
def evalAddNorm : PositivityExt where eval {u α} _zα _pα e := do
449-
match u, α, e with
450-
| 0, ~q(ℝ), ~q(@Norm.norm $β $instDist $a) =>
451-
let _inst ← synthInstanceQ q(SeminormedAddGroup $β)
452-
assertInstancesCommute
453-
pure (.nonnegative q(norm_nonneg $a))
454-
| _, _, _ => throwError "not ‖ · ‖"
455-
456-
end Mathlib.Meta.Positivity
457-
458431
@[to_additive (attr := simp) norm_zero]
459432
theorem norm_one' : ‖(1 : E)‖ = 0 := by rw [← dist_one_right, dist_self]
460433

@@ -1436,6 +1409,58 @@ alias ⟨_, HasCompactSupport.norm⟩ := hasCompactSupport_norm_iff
14361409

14371410
end NormedAddGroup
14381411

1412+
/-! ### `positivity` extensions -/
1413+
1414+
namespace Mathlib.Meta.Positivity
1415+
1416+
open Lean Meta Qq Function
1417+
1418+
/-- Extension for the `positivity` tactic: multiplicative norms are always nonnegative, and positive
1419+
on non-one inputs. -/
1420+
@[positivity ‖_‖]
1421+
def evalMulNorm : PositivityExt where eval {u α} _ _ e := do
1422+
match u, α, e with
1423+
| 0, ~q(ℝ), ~q(@Norm.norm $E $_n $a) =>
1424+
let _seminormedGroup_E ← synthInstanceQ q(SeminormedGroup $E)
1425+
assertInstancesCommute
1426+
-- Check whether we are in a normed group and whether the context contains a `a ≠ 1` assumption
1427+
let o : Option (Q(NormedGroup $E) × Q($a ≠ 1)) := ← do
1428+
let .some normedGroup_E ← trySynthInstanceQ q(NormedGroup $E) | return none
1429+
let some pa ← findLocalDeclWithTypeQ? q($a ≠ 1) | return none
1430+
return some (normedGroup_E, pa)
1431+
match o with
1432+
-- If so, return a proof of `0 < ‖a‖`
1433+
| some (_normedGroup_E, pa) =>
1434+
assertInstancesCommute
1435+
return .positive q(norm_pos_iff'.2 $pa)
1436+
-- Else, return a proof of `0 ≤ ‖a‖`
1437+
| none => return .nonnegative q(norm_nonneg' $a)
1438+
| _, _, _ => throwError "not `‖·‖`"
1439+
1440+
/-- Extension for the `positivity` tactic: additive norms are always nonnegative, and positive
1441+
on non-zero inputs. -/
1442+
@[positivity ‖_‖]
1443+
def evalAddNorm : PositivityExt where eval {u α} _ _ e := do
1444+
match u, α, e with
1445+
| 0, ~q(ℝ), ~q(@Norm.norm $E $_n $a) =>
1446+
let _seminormedAddGroup_E ← synthInstanceQ q(SeminormedAddGroup $E)
1447+
assertInstancesCommute
1448+
-- Check whether we are in a normed group and whether the context contains a `a ≠ 0` assumption
1449+
let o : Option (Q(NormedAddGroup $E) × Q($a ≠ 0)) := ← do
1450+
let .some normedAddGroup_E ← trySynthInstanceQ q(NormedAddGroup $E) | return none
1451+
let some pa ← findLocalDeclWithTypeQ? q($a ≠ 0) | return none
1452+
return some (normedAddGroup_E, pa)
1453+
match o with
1454+
-- If so, return a proof of `0 < ‖a‖`
1455+
| some (_normedAddGroup_E, pa) =>
1456+
assertInstancesCommute
1457+
return .positive q(norm_pos_iff.2 $pa)
1458+
-- Else, return a proof of `0 ≤ ‖a‖`
1459+
| none => return .nonnegative q(norm_nonneg $a)
1460+
| _, _, _ => throwError "not `‖·‖`"
1461+
1462+
end Mathlib.Meta.Positivity
1463+
14391464
/-! ### Subgroups of normed groups -/
14401465

14411466

Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,7 @@ Note this looks for `ε ≤ 1` in the context. -/
165165
def evalTriangleRemovalBound : PositivityExt where eval {u α} _zα _pα e := do
166166
match u, α, e with
167167
| 0, ~q(ℝ), ~q(triangleRemovalBound $ε) =>
168-
let some fvarId ← findLocalDeclWithType? q($ε ≤ 1)
169-
| throwError "`ε ≤ 1` is not available in the local context"
170-
let hε₁ : Q($ε ≤ 1) := .fvar fvarId
168+
let some hε₁ ← findLocalDeclWithTypeQ? q($ε ≤ 1) | failure
171169
let .positive hε ← core q(inferInstance) q(inferInstance) ε | failure
172170
assertInstancesCommute
173171
pure (.positive q(triangleRemovalBound_pos $hε $hε₁))

Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,7 @@ theorem oangle_add {x y z : V} (hx : x ≠ 0) (hy : y ≠ 0) (hz : z ≠ 0) :
442442
simp_rw [oangle]
443443
rw [← Complex.arg_mul_coe_angle, o.kahler_mul y x z]
444444
· congr 1
445-
convert Complex.arg_real_mul _ (_ : 0 < ‖y‖ ^ 2) using 2
446-
· norm_cast
447-
· have : 0 < ‖y‖ := by simpa using hy
448-
positivity
445+
exact mod_cast Complex.arg_real_mul _ (by positivity : 0 < ‖y‖ ^ 2)
449446
· exact o.kahler_ne_zero hx hy
450447
· exact o.kahler_ne_zero hy hz
451448

@@ -541,8 +538,6 @@ theorem inner_eq_norm_mul_norm_mul_cos_oangle (x y : V) :
541538
⟪x, y⟫ = ‖x‖ * ‖y‖ * Real.Angle.cos (o.oangle x y) := by
542539
by_cases hx : x = 0; · simp [hx]
543540
by_cases hy : y = 0; · simp [hy]
544-
have : ‖x‖ ≠ 0 := by simpa using hx
545-
have : ‖y‖ ≠ 0 := by simpa using hy
546541
rw [oangle, Real.Angle.cos_coe, Complex.cos_arg, o.abs_kahler]
547542
· simp only [kahler_apply_apply, real_smul, add_re, ofReal_re, mul_re, I_re, ofReal_im]
548543
-- TODO(https://github.com/leanprover-community/mathlib4/issues/15486): used to be `field_simp`; replaced by `simp only ...` to speed up

Mathlib/Tactic/ReduceModChar.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,9 @@ match Expr.getAppFnArgs t with
192192
let .some instRing ← trySynthInstanceQ q(Ring $t) | return .failure
193193

194194
let n ← mkFreshExprMVarQ q(ℕ)
195-
let .some instCharP ← findLocalDeclWithType? q(CharP $t $n) | return .failure
195+
let .some instCharP ← findLocalDeclWithTypeQ? q(CharP $t $n) | return .failure
196196

197-
return .intLike (← instantiateMVarsQ n) instRing (.fvar instCharP)
197+
return .intLike (← instantiateMVarsQ n) instRing instCharP
198198

199199
/-- Given an expression `e`, determine whether it is a numeric expression in characteristic `n`,
200200
and if so, reduce `e` modulo `n`.

Mathlib/Util/Qq.lean

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/-
22
Copyright (c) 2023 Kim Morrison. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
4-
Authors: Kim Morrison, Alex J. Best
4+
Authors: Kim Morrison, Alex J. Best, Yaël Dillies
55
-/
66
import Mathlib.Init
77
import Qq
@@ -28,4 +28,11 @@ def inferTypeQ' (e : Expr) : MetaM ((u : Level) × (α : Q(Type $u)) × Q($α))
2828

2929
theorem QuotedDefEq.rfl {u : Level} {α : Q(Sort u)} {a : Q($α)} : @QuotedDefEq u α a a := ⟨⟩
3030

31+
/-- Return a local declaration whose type is definitionally equal to `sort`.
32+
33+
This is a Qq version of `Lean.Meta.findLocalDeclWithType?` -/
34+
def findLocalDeclWithTypeQ? {u : Level} (sort : Q(Sort u)) : MetaM (Option Q($sort)) := do
35+
let some fvarId ← findLocalDeclWithType? q($sort) | return none
36+
return some <| .fvar fvarId
37+
3138
end Qq

MathlibTest/positivity.lean

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ set_option autoImplicit true
1414

1515
open Finset Function Nat NNReal ENNReal
1616

17-
variable {ι α β : Type _}
17+
variable {ι α β E : Type*}
1818

1919
/- ## Numeric goals -/
2020

@@ -307,8 +307,13 @@ example : 0 ≤ Real.log 1 := by positivity
307307
example : 0 ≤ Real.log 0 := by positivity
308308
example : 0 ≤ Real.log (-1) := by positivity
309309

310-
example {V : Type _} [NormedCommGroup V] (x : V) : 0 ≤ ‖x‖ := by positivity
311-
example {V : Type _} [NormedAddCommGroup V] (x : V) : 0 ≤ ‖x‖ := by positivity
310+
example [SeminormedGroup E] {a : E} (_ha : a ≠ 1) : 0 ≤ ‖a‖ := by positivity
311+
example [NormedGroup E] {a : E} : 0 ≤ ‖a‖ := by positivity
312+
example [NormedGroup E] {a : E} (ha : a ≠ 1) : 0 < ‖a‖ := by positivity
313+
314+
example [SeminormedAddGroup E] {a : E} (_ha : a ≠ 0) : 0 ≤ ‖a‖ := by positivity
315+
example [NormedAddGroup E] {a : E} : 0 ≤ ‖a‖ := by positivity
316+
example [NormedAddGroup E] {a : E} (ha : a ≠ 0) : 0 < ‖a‖ := by positivity
312317

313318
example [MetricSpace α] (x y : α) : 0 ≤ dist x y := by positivity
314319
example [MetricSpace α] {s : Set α} : 0 ≤ Metric.diam s := by positivity

0 commit comments

Comments
 (0)