@@ -25,7 +25,29 @@ public meta section
2525open Lean
2626open Lean.Meta Qq Lean.Elab Term
2727
28- /-- Attribute for identifying `positivity` extensions. -/
28+ /-- A definition of type `PositivityExt` tagged `@[positivity t]` extends the `positivity` tactic.
29+ The term (with underscores) `t` indicates which expressions this extension accepts.
30+ An extension will be given an expression `e : α`, together with hypotheses
31+ `[Zero α] [PartialOrder α]` and attempts to prove `e > 0`, `e ≥ 0`, or `e ≠ 0`.
32+
33+ When `Positivity.core` calls this extension on an expression `e`, it does not guarantee that `e`
34+ matches `t` perfectly: validate the form of the expression (using e.g.
35+ `match_expr (← withReducible (whnf e))`) before building a proof. See also the
36+ `let .app ... ← withReducible (whnf e) | throwError ...` lines in the example below.
37+
38+ An extension can call `Mathlib.Meta.Positivity.core` to recursively solve subgoals.
39+
40+ Example:
41+ ```lean
42+ @[positivity ite _ _ _] def evalIte : PositivityExt where eval {u α} zα pα e := do
43+ let .app (.app (.app (.app f (p : Q(Prop))) (_ : Q(Decidable $p))) (a : Q($α))) (b : Q($α))
44+ ← withReducible (whnf e) | throwError "not ite"
45+ haveI' : $e =Q ite $p $a $b := ⟨⟩
46+ guard <| ← withDefault <| withNewMCtxDepth <| isDefEq f q(ite (α := $α))
47+ let ra ← core zα pα a; let rb ← core zα pα b
48+ ...
49+ ```
50+ -/
2951syntax (name := positivity) "positivity " term,+ : attr
3052
3153lemma ne_of_ne_of_eq' {α : Sort *} {a c b : α} (hab : (a : α) ≠ c) (hbc : a = b) : b ≠ c := hbc ▸ hab
@@ -490,14 +512,23 @@ namespace Tactic.Positivity
490512
491513open Tactic
492514
493- /-- Tactic solving goals of the form `0 ≤ x`, `0 < x` and `x ≠ 0`. The tactic works recursively
494- according to the syntax of the expression `x`, if the atoms composing the expression all have
495- numeric lower bounds which can be proved positive/nonnegative/nonzero by `norm_num`. This tactic
496- either closes the goal or fails.
515+ /-- `positivity` solves goals of the form `0 ≤ x`, `0 < x` and `x ≠ 0`. The tactic works recursively
516+ according to the syntax of the expression `x`, by attempting to prove subexpressions are
517+ positive/nonnegative/nonzero and combining this into a final proof. This tactic either closes the
518+ goal or fails.
519+
520+ For each subexpression `e`, `positivity` will try to:
521+ * try `@[positivity]`-tagged extensions to recursively prove `e` is positive/nonnegative/nonzero
522+ based on its subexpressions (see the `positivity` attribute for more details), or
523+ * try the `norm_num` tactic to prove `e` is positive/nonnegative/nonzero, or
524+ * try showing `e : t` is nonnegative because there is a `CanonicallyOrderedAdd t` instance, or
525+ * use a local hypothesis of the form `0 ≤ e`, `0 < e` or `e ≠ 0`.
526+
527+ This tactic is extensible. See the `positivity` attribute documentation for more details.
497528
498- `positivity [t₁, …, tₙ]` first executes `have := t₁; …; have := tₙ` in the current goal,
499- then runs `positivity`. This is useful when `positivity` needs derived premises such as `0 < y`
500- for division/reciprocal, or `0 ≤ x` for real powers.
529+ * `positivity [t₁, …, tₙ]` first executes `have := t₁; …; have := tₙ` in the current goal,
530+ then runs `positivity`. This is useful when `positivity` needs derived premises such as `0 < y`
531+ for division/reciprocal, or `0 ≤ x` for real powers.
501532
502533 Examples:
503534```
0 commit comments