Skip to content

Commit 34a0b42

Browse files
HugLycanfpvandoorn
authored andcommitted
feat(Tactic/Positivity): make positivity work for types that are not partial orders (leanprover-community#35394)
Make positivity work for types that are not partial orders Most PositivityExt haven't been updated for non partial order cases yet. They will be updated in the later PR. `Strictness` now depends on `Option Q(PartialOrder $α)` instead of `Q(PartialOrder $α)`, and the constructors `Strictness.positive`/`Strictness.nonnegative` now have their `Q(PartialOrder $α)` typeclass arguments. Co-authored-by: Floris van Doorn <fpvdoorn@gmail.com>
1 parent dce3794 commit 34a0b42

54 files changed

Lines changed: 612 additions & 354 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Mathlib/Algebra/Order/AbsoluteValue/Basic.lean

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,8 @@ open Lean Meta Mathlib Meta Positivity Qq in
416416
For performance reasons, we only attempt to apply this when `abv` is a variable.
417417
If it is an explicit function, e.g. `|_|` or `‖_‖`, another extension should apply. -/
418418
@[positivity _]
419-
meta def Mathlib.Meta.Positivity.evalAbv : PositivityExt where eval {_ _α} _zα _pα e := do
419+
meta def Mathlib.Meta.Positivity.evalAbv : PositivityExt where eval {_ _α} _zα pα? e := do
420+
let some _ := pα? | pure .none
420421
let (.app f a) ← whnfR e | throwError "not abv ·"
421422
if !f.getAppFn.isFVar then
422423
throwError "abv: function is not a variable"

Mathlib/Algebra/Order/Algebra.lean

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,12 @@ open Lean Meta Qq Function
9595

9696
/-- Extension for `algebraMap`. -/
9797
@[positivity algebraMap _ _ _]
98-
meta def evalAlgebraMap : PositivityExt where eval {u β} _zβ _pβ e := do
98+
meta def evalAlgebraMap : PositivityExt where eval {u β} _zβ pβ? e := do
9999
let ~q(@algebraMap $α _ $instα $instβ $instαβ $a) := e | throwError "not `algebraMap`"
100-
let pα ← synthInstanceQ q(PartialOrder $α)
100+
let pα ← try? <| synthInstanceQ q(PartialOrder $α)
101101
match ← core q(inferInstance) pα a with
102102
| .positive pa =>
103+
let some _ := pβ? | pure .none
103104
let _instαSemiring ← synthInstanceQ q(Semiring $α)
104105
let _instαPartialOrder ← synthInstanceQ q(PartialOrder $α)
105106
try
@@ -117,6 +118,7 @@ meta def evalAlgebraMap : PositivityExt where eval {u β} _zβ _pβ e := do
117118
assertInstancesCommute
118119
return .nonnegative q(algebraMap_nonneg $β <| le_of_lt $pa)
119120
| .nonnegative pa =>
121+
let some _ := pβ? | pure .none
120122
let _instαSemiring ← synthInstanceQ q(CommSemiring $α)
121123
let _instαPartialOrder ← synthInstanceQ q(PartialOrder $α)
122124
let _instβSemiring ← synthInstanceQ q(Semiring $β)

Mathlib/Algebra/Order/BigOperators/Expect.lean

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ open scoped BigOperators
220220
attribute [local instance] monadLiftOptionMetaM in
221221
/-- Positivity extension for `Finset.expect`. -/
222222
@[positivity Finset.expect _ _]
223-
meta def evalFinsetExpect : PositivityExt where eval {u α} zα pα e := do
223+
meta def evalFinsetExpect : PositivityExt where eval {u α} zα pα? e := do
224+
let some pα := pα? | pure .none
224225
match e with
225226
| ~q(@Finset.expect $ι _ $instα $instmod $s $f) =>
226227
let i : Q($ι) ← mkFreshExprMVarQ q($ι) .syntheticOpaque

Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,10 @@ example (s : Finset ℕ) (f : ℕ → ℤ) (hf : ∀ n, 0 ≤ f n) : 0 ≤ s.pro
225225
because `compareHyp` can't look for assumptions behind binders.
226226
-/
227227
@[positivity Finset.prod _ _]
228-
meta def evalFinsetProd : PositivityExt where eval {u α} zα pα e := do
228+
meta def evalFinsetProd : PositivityExt where eval {u α} zα pα? e := do
229229
match e with
230230
| ~q(@Finset.prod $ι _ $instα $s $f) =>
231+
let some pα := pα? | pure .none
231232
let i : Q($ι) ← mkFreshExprMVarQ q($ι) .syntheticOpaque
232233
have body : Q($α) := Expr.betaRev f #[i]
233234
let rbody ← core zα pα body

Mathlib/Algebra/Order/Field/Basic.lean

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -733,15 +733,23 @@ lemma zpow_zero_pos {α : Type*} [Semifield α] [PartialOrder α] [IsStrictOrder
733733

734734
/-- The `positivity` extension which identifies expressions of the form `a / b`,
735735
such that `positivity` successfully recognises both `a` and `b`. -/
736-
@[positivity _ / _] meta def evalDiv : PositivityExt where eval {u α} zα pα e := do
736+
@[positivity _ / _] meta def evalDiv : PositivityExt where eval {u α} zα pα? e := do
737737
let .app (.app (f : Q($α → $α → $α)) (a : Q($α))) (b : Q($α)) ← withReducible (whnf e)
738738
| throwError "not /"
739739
let _e_eq : $e =Q $f $a $b := ⟨⟩
740+
trace[Tactic.positivity.zeroness] "evalDiv: {a} divided by {b}"
741+
let _a ← synthInstanceQ q(Semifield $α)
742+
let ⟨_f_eq⟩ ← withDefault <| withNewMCtxDepth <| assertDefEqQ q($f) q(HDiv.hDiv)
743+
let some pα := pα? |
744+
match ← core zα pα? a, ← core zα pα? b with
745+
| .nonzero pa, .nonzero pb =>
746+
let _a ← synthInstanceQ q(GroupWithZero $α)
747+
assumeInstancesCommute
748+
pure (.nonzero q(div_ne_zero $pa $pb))
749+
| _, _ => pure .none
740750
let _a ← synthInstanceQ q(GroupWithZero $α)
741-
let _a ← synthInstanceQ q(PartialOrder $α)
742751
let _a ← synthInstanceQ q(PosMulReflectLT $α)
743752
assumeInstancesCommute
744-
let ⟨_f_eq⟩ ← withDefault <| withNewMCtxDepth <| assertDefEqQ q($f) q(HDiv.hDiv)
745753
let ra ← core zα pα a; let rb ← core zα pα b
746754
match ra, rb with
747755
| .positive pa, .positive pb => pure (.positive q(div_pos $pa $pb))
@@ -756,25 +764,38 @@ such that `positivity` successfully recognises both `a` and `b`. -/
756764
/-- The `positivity` extension which identifies expressions of the form `a⁻¹`,
757765
such that `positivity` successfully recognises `a`. -/
758766
@[positivity _⁻¹]
759-
meta def evalInv : PositivityExt where eval {u α} zα pα e := do
767+
meta def evalInv : PositivityExt where eval {u α} zα pα? e := do
760768
let .app (f : Q($α → $α)) (a : Q($α)) ← withReducible (whnf e) | throwError "not ⁻¹"
761769
let _e_eq : $e =Q $f $a := ⟨⟩
770+
let _a ← synthInstanceQ q(Semifield $α)
771+
let ⟨_f_eq⟩ ← withDefault <| withNewMCtxDepth <| assertDefEqQ q($f) q(Inv.inv)
772+
let some _ := pα? |
773+
match ← core zα pα? a with
774+
| .nonzero pa =>
775+
let _a ← synthInstanceQ q(GroupWithZero $α)
776+
assumeInstancesCommute
777+
pure (.nonzero q(inv_ne_zero $pa))
778+
| _ => pure .none
762779
let _a ← synthInstanceQ q(GroupWithZero $α)
763780
let _a ← synthInstanceQ q(PartialOrder $α)
764781
let _a ← synthInstanceQ q(PosMulReflectLT $α)
765782
assumeInstancesCommute
766-
let ⟨_f_eq⟩ ← withDefault <| withNewMCtxDepth <| assertDefEqQ q($f) q(Inv.inv)
767-
let ra ← core zα pα a
783+
let ra ← core zα pα? a
768784
match ra with
769-
| .positive pa => pure (.positive q(inv_pos_of_pos $pa))
770-
| .nonnegative pa => pure (.nonnegative q(inv_nonneg_of_nonneg $pa))
785+
| .positive pa =>
786+
assumeInstancesCommute
787+
pure (.positive q(inv_pos_of_pos $pa))
788+
| .nonnegative pa =>
789+
assumeInstancesCommute
790+
pure (.nonnegative q(inv_nonneg_of_nonneg $pa))
771791
| .nonzero pa => pure (.nonzero q(inv_ne_zero $pa))
772792
| .none => pure .none
773793

774794
/-- The `positivity` extension which identifies expressions of the form `a ^ (0:ℤ)`. -/
775795
@[positivity _ ^ (0 : ℤ), Pow.pow _ (0 : ℤ)]
776-
meta def evalPowZeroInt : PositivityExt where eval {u α} _zα _pα e := do
796+
meta def evalPowZeroInt : PositivityExt where eval {u α} _zα pα? e := do
777797
let .app (.app _ (a : Q($α))) _ ← withReducible (whnf e) | throwError "not ^"
798+
let some _ := pα? | pure .none
778799
let _a ← synthInstanceQ q(Semifield $α)
779800
let _a ← synthInstanceQ q(LinearOrder $α)
780801
let _a ← synthInstanceQ q(IsStrictOrderedRing $α)

Mathlib/Algebra/Order/Field/Power.lean

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,16 @@ open Lean Meta Qq
123123
/-- The `positivity` extension which identifies expressions of the form `a ^ (b : ℤ)`,
124124
such that `positivity` successfully recognises both `a` and `b`. -/
125125
@[positivity _ ^ (_ : ℤ), Pow.pow _ (_ : ℤ)]
126-
meta def evalZPow : PositivityExt where eval {u α} zα pα e := do
126+
meta def evalZPow : PositivityExt where eval {u α} zα pα? e := do
127127
let .app (.app _ (a : Q($α))) (b : Q(ℤ)) ← withReducible (whnf e) | throwError "not ^"
128+
let some pα := pα? |
129+
match ← core zα pα? a with
130+
| .nonzero pa =>
131+
let _a ← synthInstanceQ q(GroupWithZero $α)
132+
assumeInstancesCommute
133+
haveI' : $e =Q $a ^ $b := ⟨⟩
134+
pure (.nonzero q(zpow_ne_zero $b $pa))
135+
| _ => pure .none
128136
let result ← catchNone do
129137
let _a ← synthInstanceQ q(Field $α)
130138
let _a ← synthInstanceQ q(LinearOrder $α)
@@ -151,11 +159,11 @@ meta def evalZPow : PositivityExt where eval {u α} zα pα e := do
151159
let ra ← core zα pα a
152160
let ofNonneg (pa : Q(0 ≤ $a))
153161
(_oα : Q(Semifield $α)) (_oα : Q(LinearOrder $α)) (_oα : Q(IsStrictOrderedRing $α)) :
154-
MetaM (Strictness zα pα e) := do
162+
MetaM (Strictness zα e pα) := do
155163
haveI' : $e =Q $a ^ $b := ⟨⟩
156164
assumeInstancesCommute
157165
pure (.nonnegative q(zpow_nonneg $pa $b))
158-
let ofNonzero (pa : Q($a ≠ 0)) (_oα : Q(GroupWithZero $α)) : MetaM (Strictness zα pα e) := do
166+
let ofNonzero (pa : Q($a ≠ 0)) (_oα : Q(GroupWithZero $α)) : MetaM (Strictness zα e pα) := do
159167
haveI' : $e =Q $a ^ $b := ⟨⟩
160168
let _a ← synthInstanceQ q(GroupWithZero $α)
161169
assumeInstancesCommute

Mathlib/Algebra/Order/Floor/Extended.lean

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,11 @@ alias ⟨_, natCeil_pos⟩ := ENat.ceil_pos
256256

257257
/-- Extension for the `positivity` tactic: `ENat.ceil` is positive if its input is. -/
258258
@[positivity ⌈_⌉ₑ]
259-
meta def evalENatCeil : PositivityExt where eval {u α} _zα _pα e := do
259+
meta def evalENatCeil : PositivityExt where eval {u α} _zα pα? e := do
260260
match u, α, e with
261261
| 0, ~q(ℕ∞), ~q(ENat.ceil $r) =>
262-
assertInstancesCommute
263-
match ← core q(inferInstance) q(inferInstance) r with
262+
let some _ := pα? | pure .none
263+
match ← core q(inferInstance) (some q(inferInstance)) r with
264264
| .positive pr =>
265265
assertInstancesCommute
266266
pure (.positive q(natCeil_pos $pr))

Mathlib/Algebra/Order/Floor/Ring.lean

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ theorem int_floor_nonneg_of_pos [Ring α] [LinearOrder α] [FloorRing α] {a :
5050

5151
/-- Extension for the `positivity` tactic: `Int.floor` is nonnegative if its input is. -/
5252
@[positivity ⌊_⌋]
53-
meta def evalIntFloor : PositivityExt where eval {u α} _zα _pα e := do
53+
meta def evalIntFloor : PositivityExt where eval {u α} _zα pα? e := do
5454
match u, α, e with
5555
| 0, ~q(ℤ), ~q(@Int.floor $α' $ir $io $j $a) =>
56-
match ← core q(inferInstance) q(inferInstance) a with
56+
let some _ := pα? | pure .none
57+
match ← core q(inferInstance) (some q(inferInstance)) a with
5758
| .positive pa =>
5859
assertInstancesCommute
5960
pure (.nonnegative q(int_floor_nonneg_of_pos (α := $α') $pa))
@@ -69,13 +70,14 @@ theorem nat_ceil_pos [Semiring α] [LinearOrder α] [FloorSemiring α] {a : α}
6970

7071
/-- Extension for the `positivity` tactic: `Nat.ceil` is positive if its input is. -/
7172
@[positivity ⌈_⌉₊]
72-
meta def evalNatCeil : PositivityExt where eval {u α} _zα _pα e := do
73+
meta def evalNatCeil : PositivityExt where eval {u α} _zα pα? e := do
7374
match u, α, e with
7475
| 0, ~q(ℕ), ~q(@Nat.ceil $α' $ir $io $j $a) =>
76+
let some _ := pα? | pure .none
7577
let _i ← synthInstanceQ q(LinearOrder $α')
7678
let _i ← synthInstanceQ q(IsStrictOrderedRing $α')
7779
assertInstancesCommute
78-
match ← core q(inferInstance) q(inferInstance) a with
80+
match ← core q(inferInstance) (some q(inferInstance)) a with
7981
| .positive pa =>
8082
assertInstancesCommute
8183
pure (.positive q(nat_ceil_pos (α := $α') $pa))
@@ -87,10 +89,11 @@ theorem int_ceil_pos [Ring α] [LinearOrder α] [FloorRing α] {a : α} : 0 < a
8789

8890
/-- Extension for the `positivity` tactic: `Int.ceil` is positive/nonnegative if its input is. -/
8991
@[positivity ⌈_⌉]
90-
meta def evalIntCeil : PositivityExt where eval {u α} _zα _pα e := do
92+
meta def evalIntCeil : PositivityExt where eval {u α} _zα pα? e := do
9193
match u, α, e with
9294
| 0, ~q(ℤ), ~q(@Int.ceil $α' $ir $io $j $a) =>
93-
match ← core q(inferInstance) q(inferInstance) a with
95+
let some _ := pα? | pure .none
96+
match ← core q(inferInstance) (some q(inferInstance)) a with
9497
| .positive pa =>
9598
assertInstancesCommute
9699
pure (.positive q(int_ceil_pos (α := $α') $pa))

Mathlib/Algebra/Order/Interval/Basic.lean

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,18 +660,20 @@ open Lean Meta Qq
660660
/-- Extension for the `positivity` tactic: The length of an interval is always nonnegative. -/
661661
@[positivity NonemptyInterval.length _]
662662
meta def evalNonemptyIntervalLength : PositivityExt where
663-
eval {u α} _ _ e := do
663+
eval {u α} _ pα? e := do
664664
let ~q(@NonemptyInterval.length _ $ig $ipo $a) := e |
665665
throwError "not NonemptyInterval.length"
666+
let some _ := pα? | pure .none
666667
let _i ← synthInstanceQ q(IsOrderedAddMonoid $α)
667668
assertInstancesCommute
668669
return .nonnegative q(NonemptyInterval.length_nonneg $a)
669670

670671
/-- Extension for the `positivity` tactic: The length of an interval is always nonnegative. -/
671672
@[positivity Interval.length _]
672673
meta def evalIntervalLength : PositivityExt where
673-
eval {u α} _ _ e := do
674+
eval {u α} _ pα? e := do
674675
let ~q(@Interval.length _ $ig $ipo $a) := e | throwError "not Interval.length"
676+
let some _ := pα? | pure .none
675677
let _i ← synthInstanceQ q(IsOrderedAddMonoid $α)
676678
assumeInstancesCommute
677679
return .nonnegative q(Interval.length_nonneg $a)

Mathlib/Algebra/Order/Module/Field.lean

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ end Module.IsTorsionFree
103103

104104
/-- Positivity extension for scalar multiplication. -/
105105
@[positivity HSMul.hSMul _ _]
106-
meta def evalSMul : PositivityExt where eval {_u α} zα pα (e : Q($α)) := do
106+
meta def evalSMul : PositivityExt where eval {_u α} zα pα? (e : Q($α)) := do
107+
let some pα := pα? | pure .none
107108
let .app (.app (.app (.app (.app (.app
108109
(.const ``HSMul.hSMul [u1, _, _]) (β : Q(Type u1))) _) _) _)
109110
(a : Q($β))) (b : Q($α)) ← whnfR e | throwError "failed to match hSMul"

0 commit comments

Comments
 (0)