doc-next-gen

Mathlib.Tactic.Positivity.Core

Module docstring

{"## positivity core functionality

This file sets up the positivity tactic and the @[positivity] attribute, which allow for plugging in new positivity functionality around a positivity-based driver. The actual behavior is in @[positivity]-tagged definitions in Tactic.Positivity.Basic and elsewhere. "}

ne_of_ne_of_eq' theorem
{α : Sort*} {a c b : α} (hab : (a : α) ≠ c) (hbc : a = b) : b ≠ c
Full source
lemma ne_of_ne_of_eq' {α : Sort*} {a c b : α} (hab : (a : α) ≠ c) (hbc : a = b) : b ≠ c := hbc ▸ hab
Inequality Preservation Under Equality: $a \neq c$ and $a = b$ implies $b \neq c$
Informal description
For any elements $a$, $b$, and $c$ of a type $\alpha$, if $a \neq c$ and $a = b$, then $b \neq c$.
Mathlib.Meta.Positivity.Strictness inductive
(e : Q($α))
Full source
/-- The result of `positivity` running on an expression `e` of type `α`. -/
inductive Strictness (e : Q($α)) where
  | positive (pf : Q(0 < $e))
  | nonnegative (pf : Q(0 ≤ $e))
  | nonzero (pf : Q($e ≠ 0))
  | none
  deriving Repr
Positivity strictness outcomes
Informal description
An inductive type representing the possible outcomes when the `positivity` tactic analyzes an expression `e` of type `α`. This type captures whether `e` is positive, non-negative, or has some other strictness property.
Mathlib.Meta.Positivity.instReprStrictness instance
{u✝} {α✝} {zα✝} {pα✝} {e✝} : Repr✝ (@Mathlib.Meta.Positivity.Strictness✝ u✝ α✝ zα✝ pα✝ e✝)
Full source
Repr
Representation Instance for Positivity Strictness Outcomes
Informal description
The type `Strictness` in the `positivity` tactic framework has a canonical representation instance.
Mathlib.Meta.Positivity.Strictness.toString definition
{e : Q($α)} : Strictness zα pα e → String
Full source
/-- Gives a generic description of the `positivity` result. -/
def Strictness.toString {e : Q($α)} : Strictness zα pα e → String
  | positive _ => "positive"
  | nonnegative _ => "nonnegative"
  | nonzero _ => "nonzero"
  | none => "none"
String representation of positivity strictness outcomes
Informal description
The function converts a `Strictness` outcome (which represents the result of analyzing an expression's positivity properties) into a human-readable string. It maps: - `positive` to "positive", - `nonnegative` to "nonnegative", - `nonzero` to "nonzero", - `none` to "none".
Mathlib.Meta.Positivity.Strictness.toNonneg definition
{e} : Strictness zα pα e → Option Q(0 ≤ $e)
Full source
/-- Extract a proof that `e` is nonnegative, if possible, from `Strictness` information about `e`.
-/
def Strictness.toNonneg {e} : Strictness zα pα e → Option Q(0 ≤ $e)
  | .positive pf => some q(le_of_lt $pf)
  | .nonnegative pf => some pf
  | _ => .none
Extraction of non-negativity proof from strictness information
Informal description
Given a term `e` of type `α` and a `Strictness` proof about `e`, this function extracts a proof that `0 ≤ e` if possible. Specifically: - If `e` is positive (i.e., `0 < e`), it returns a proof that `0 ≤ e` by applying the lemma `le_of_lt`. - If `e` is non-negative (i.e., `0 ≤ e`), it returns the given proof directly. - Otherwise, it returns no proof.
Mathlib.Meta.Positivity.Strictness.toNonzero definition
{e} : Strictness zα pα e → Option Q($e ≠ 0)
Full source
/-- Extract a proof that `e` is nonzero, if possible, from `Strictness` information about `e`. -/
def Strictness.toNonzero {e} : Strictness zα pα e → Option Q($e ≠ 0)
  | .positive pf => some q(ne_of_gt $pf)
  | .nonzero pf => some pf
  | _ => .none
Extraction of nonzero proof from strictness information
Informal description
Given a `Strictness` proof about an expression `e`, this function attempts to extract a proof that `e` is nonzero. If the `Strictness` proof indicates that `e` is positive or already known to be nonzero, it returns the corresponding proof; otherwise, it returns `none`.
Mathlib.Meta.Positivity.PositivityExt structure
Full source
/-- An extension for `positivity`. -/
structure PositivityExt where
  /-- Attempts to prove an expression `e : α` is `>0`, `≥0`, or `≠0`. -/
  eval {u : Level} {α : Q(Type u)} (zα : Q(Zero $α)) (pα : Q(PartialOrder $α)) (e : Q($α)) :
    MetaM (Strictness zα pα e)
Positivity Extension
Informal description
The structure `PositivityExt` represents an extension for the `positivity` tactic, which is used to determine the positivity (non-negativity, strict positivity, or non-zero status) of mathematical expressions. This structure allows plugging in new functionality to extend the capabilities of the `positivity` tactic.
Mathlib.Meta.Positivity.mkPositivityExt definition
(n : Name) : ImportM PositivityExt
Full source
/-- Read a `positivity` extension from a declaration of the right type. -/
def mkPositivityExt (n : Name) : ImportM PositivityExt := do
  let { env, opts, .. } ← read
  IO.ofExcept <| unsafe env.evalConstCheck PositivityExt opts ``PositivityExt n
Positivity extension constructor
Informal description
The function `mkPositivityExt` constructs a positivity extension from a declaration with the given name, evaluating it in the current environment to produce an instance of `PositivityExt`.
Mathlib.Meta.Positivity.Entry abbrev
Full source
/-- Each `positivity` extension is labelled with a collection of patterns
which determine the expressions to which it should be applied. -/
abbrev Entry := ArrayArray (Array DiscrTree.Key) × Name
Positivity Extension Entry Structure
Informal description
The structure `Entry` represents an entry in the `positivity` tactic's extension system, which is used to store and manage the patterns and associated functionality for determining the positivity of mathematical expressions.
Mathlib.Meta.Positivity.positivityExt opaque
: PersistentEnvExtension Entry (Entry × PositivityExt) (List Entry × DiscrTree PositivityExt)
Full source
/-- Environment extensions for `positivity` declarations -/
initialize positivityExt : PersistentEnvExtension Entry (Entry × PositivityExt)
    (List Entry × DiscrTree PositivityExt) ←
  -- we only need this to deduplicate entries in the DiscrTree
  have : BEq PositivityExt := ⟨fun _ _ => false⟩
  let insert kss v dt := kss.foldl (fun dt ks => dt.insertCore ks v) dt
  registerPersistentEnvExtension {
    mkInitial := pure ([], {})
    addImportedFn := fun s => do
      let dt ← s.foldlM (init := {}) fun dt s => s.foldlM (init := dt) fun dt (kss, n) => do
        pure (insert kss (← mkPositivityExt n) dt)
      pure ([], dt)
    addEntryFn := fun (entries, s) ((kss, n), ext) => ((kss, n) :: entries, insert kss ext s)
    exportEntriesFn := fun s => s.1.reverse.toArray
  }
Positivity Extension Environment for Mathematical Expression Analysis
Informal description
The `positivityExt` is a persistent environment extension that maintains a collection of `Entry` and `PositivityExt` pairs, organized as a list of entries and a discrimination tree of positivity extensions. This structure is used to store and manage the patterns and associated functionality for determining the positivity of mathematical expressions in the `positivity` tactic.
Mathlib.Meta.Positivity.lt_of_le_of_ne' theorem
{a b : A} [PartialOrder A] : (a : A) ≤ b → b ≠ a → a < b
Full source
lemma lt_of_le_of_ne' {a b : A} [PartialOrder A] :
    (a : A) ≤ b → b ≠ a → a < b := fun h₁ h₂ => lt_of_le_of_ne h₁ h₂.symm
Strict Inequality from Non-Equal Weak Inequality
Informal description
Let $A$ be a partially ordered set. For any elements $a, b \in A$, if $a \leq b$ and $b \neq a$, then $a < b$.
Mathlib.Meta.Positivity.pos_of_isNat theorem
{n : ℕ} [Semiring A] [PartialOrder A] [IsOrderedRing A] [Nontrivial A] (h : NormNum.IsNat e n) (w : Nat.ble 1 n = true) : 0 < (e : A)
Full source
lemma pos_of_isNat {n : } [Semiring A] [PartialOrder A] [IsOrderedRing A] [Nontrivial A]
    (h : NormNum.IsNat e n) (w : Nat.ble 1 n = true) : 0 < (e : A) := by
  rw [NormNum.IsNat.to_eq h rfl]
  apply Nat.cast_pos.2
  simpa using w
Positivity of Natural Number Casts in Ordered Semirings
Informal description
Let $A$ be a nontrivial ordered semiring. For any natural number $n \geq 1$ and any expression $e$ in $A$ such that $e$ is equal to the canonical image of $n$ in $A$ (i.e., $\text{IsNat}(e, n)$ holds), we have $0 < e$ in $A$.
Mathlib.Meta.Positivity.nonneg_of_isNat theorem
{n : ℕ} [Semiring A] [PartialOrder A] [IsOrderedRing A] (h : NormNum.IsNat e n) : 0 ≤ (e : A)
Full source
lemma nonneg_of_isNat {n : } [Semiring A] [PartialOrder A] [IsOrderedRing A]
    (h : NormNum.IsNat e n) : 0 ≤ (e : A) := by
  rw [NormNum.IsNat.to_eq h rfl]
  exact Nat.cast_nonneg n
Nonnegativity of Natural Number Casts in Ordered Semirings
Informal description
Let $A$ be an ordered semiring. For any natural number $n$ and any expression $e$ in $A$ such that $e$ is equal to the canonical image of $n$ in $A$ (i.e., $e = n$ as elements of $A$), we have $0 \leq e$.
Mathlib.Meta.Positivity.nz_of_isNegNat theorem
{n : ℕ} [Ring A] [PartialOrder A] [IsStrictOrderedRing A] (h : NormNum.IsInt e (.negOfNat n)) (w : Nat.ble 1 n = true) : (e : A) ≠ 0
Full source
lemma nz_of_isNegNat {n : } [Ring A] [PartialOrder A] [IsStrictOrderedRing A]
    (h : NormNum.IsInt e (.negOfNat n)) (w : Nat.ble 1 n = true) : (e : A) ≠ 0 := by
  rw [NormNum.IsInt.neg_to_eq h rfl]
  simp only [ne_eq, neg_eq_zero]
  apply ne_of_gt
  simpa using w
Nonzero Property of Negative Integer Casts in Strict Ordered Rings
Informal description
Let $A$ be a strict ordered ring. For any natural number $n \geq 1$ and any expression $e$ in $A$ such that $e$ is equal to the canonical image of $-n$ in $A$ (i.e., $\text{IsInt}(e, -n)$ holds), we have $e \neq 0$ in $A$.
Mathlib.Meta.Positivity.pos_of_isRat theorem
{n : ℤ} {d : ℕ} [Ring A] [LinearOrder A] [IsStrictOrderedRing A] : (NormNum.IsRat e n d) → (decide (0 < n)) → ((0 : A) < (e : A))
Full source
lemma pos_of_isRat {n : } {d : } [Ring A] [LinearOrder A] [IsStrictOrderedRing A] :
    (NormNum.IsRat e n d) → (decide (0 < n)) → ((0 : A) < (e : A))
  | ⟨inv, eq⟩, h => by
    have pos_invOf_d : (0 < ⅟ (d : A)) := pos_invOf_of_invertible_cast d
    have pos_n : (0 < (n : A)) := Int.cast_pos (n := n) |>.2 (of_decide_eq_true h)
    rw [eq]
    exact mul_pos pos_n pos_invOf_d
Positivity of Positive Rational Expressions in Strict Ordered Rings
Informal description
Let $A$ be a strict ordered ring with a linear order. For any integer $n \in \mathbb{Z}$ and natural number $d \in \mathbb{N}$, if an expression $e \in A$ satisfies $\text{IsRat}(e, n, d)$ (i.e., $e$ is equal to the fraction $\frac{n}{d}$ in $A$) and $0 < n$, then $0 < e$ in $A$.
Mathlib.Meta.Positivity.nonneg_of_isRat theorem
{n : ℤ} {d : ℕ} [Ring A] [LinearOrder A] : (NormNum.IsRat e n d) → (decide (n = 0)) → (0 ≤ (e : A))
Full source
lemma nonneg_of_isRat {n : } {d : } [Ring A] [LinearOrder A] :
    (NormNum.IsRat e n d) → (decide (n = 0)) → (0 ≤ (e : A))
  | ⟨inv, eq⟩, h => by rw [eq, of_decide_eq_true h]; simp
Nonnegativity of Zero Rational in Ordered Ring
Informal description
Let $A$ be a linearly ordered ring and let $e \in A$. If $e$ is equal to a fraction $\frac{n}{d}$ where $n \in \mathbb{Z}$, $d \in \mathbb{N}$, and $n = 0$, then $0 \leq e$.
Mathlib.Meta.Positivity.nz_of_isRat theorem
{n : ℤ} {d : ℕ} [Ring A] [LinearOrder A] [IsStrictOrderedRing A] : (NormNum.IsRat e n d) → (decide (n < 0)) → ((e : A) ≠ 0)
Full source
lemma nz_of_isRat {n : } {d : } [Ring A] [LinearOrder A] [IsStrictOrderedRing A] :
    (NormNum.IsRat e n d) → (decide (n < 0)) → ((e : A) ≠ 0)
  | ⟨inv, eq⟩, h => by
    have pos_invOf_d : (0 < ⅟ (d : A)) := pos_invOf_of_invertible_cast d
    have neg_n : ((n : A) < 0) := Int.cast_lt_zero (n := n) |>.2 (of_decide_eq_true h)
    have neg := mul_neg_of_neg_of_pos neg_n pos_invOf_d
    rw [eq]
    exact ne_iff_lt_or_gt.2 (Or.inl neg)
Nonzero Property of Negative Rationals in Strict Ordered Semirings: $\frac{n}{d} < 0 \implies e \neq 0$
Informal description
Let $A$ be a linearly ordered strict semiring and let $e \in A$. If $e$ is equal to a fraction $\frac{n}{d}$ where $n \in \mathbb{Z}$, $d \in \mathbb{N}$, and $n < 0$, then $e \neq 0$.
Mathlib.Meta.Positivity.catchNone definition
{e : Q($α)} (t : MetaM (Strictness zα pα e)) : MetaM (Strictness zα pα e)
Full source
/-- Converts a `MetaM Strictness` which can fail
into one that never fails and returns `.none` instead. -/
def catchNone {e : Q($α)} (t : MetaM (Strictness zα pα e)) : MetaM (Strictness zα pα e) :=
  try t catch e =>
    trace[Tactic.positivity.failure] "{e.toMessageData}"
    pure .none
Safe strictness computation handler
Informal description
Given a monadic computation `t` that produces a `Strictness` result (which may fail), this function converts it into one that never fails and returns `.none` in case of failure.
Mathlib.Meta.Positivity.throwNone definition
{m : Type → Type*} {e : Q($α)} [Monad m] [Alternative m] (t : m (Strictness zα pα e)) : m (Strictness zα pα e)
Full source
/-- Converts a `MetaM Strictness` which can return `.none`
into one which never returns `.none` but fails instead. -/
def throwNone {m : Type → Type*} {e : Q($α)} [Monad m] [Alternative m]
    (t : m (Strictness zα pα e)) : m (Strictness zα pα e) := do
  match ← t with
  | .none => failure
  | r => pure r
Conversion of optional strictness to failure
Informal description
Given a monadic computation `t` that may produce a `Strictness` result or `.none`, this function converts it into one that fails when `t` would return `.none`, and otherwise returns the same result as `t`.
Mathlib.Meta.Positivity.normNumPositivity definition
(e : Q($α)) : MetaM (Strictness zα pα e)
Full source
/-- Attempts to prove a `Strictness` result when `e` evaluates to a literal number. -/
def normNumPositivity (e : Q($α)) : MetaM (Strictness zα pα e) := catchNone do
  match ← NormNum.derive e with
  | .isBool .. => failure
  | .isNat _ lit p =>
    if 0 < lit.natLit! then
      let _a ← synthInstanceQ q(Semiring $α)
      let _a ← synthInstanceQ q(PartialOrder $α)
      let _a ← synthInstanceQ q(IsOrderedRing $α)
      let _a ← synthInstanceQ q(Nontrivial $α)
      assumeInstancesCommute
      have p : Q(NormNum.IsNat $e $lit) := p
      haveI' p' : Nat.ble 1 $lit =Q true := ⟨⟩
      pure (.positive q(pos_of_isNat (A := $α) $p $p'))
    else
      let _a ← synthInstanceQ q(Semiring $α)
      let _a ← synthInstanceQ q(PartialOrder $α)
      let _a ← synthInstanceQ q(IsOrderedRing $α)
      assumeInstancesCommute
      have p : Q(NormNum.IsNat $e $lit) := p
      pure (.nonnegative q(nonneg_of_isNat $p))
  | .isNegNat _ lit p =>
    let _a ← synthInstanceQ q(Ring $α)
    let _a ← synthInstanceQ q(PartialOrder $α)
    let _a ← synthInstanceQ q(IsStrictOrderedRing $α)
    assumeInstancesCommute
    have p : Q(NormNum.IsInt $e (Int.negOfNat $lit)) := p
    haveI' p' : Nat.ble 1 $lit =Q true := ⟨⟩
    pure (.nonzero q(nz_of_isNegNat $p $p'))
  | .isRat _i q n d p =>
    let _a ← synthInstanceQ q(Ring $α)
    let _a ← synthInstanceQ q(LinearOrder $α)
    let _a ← synthInstanceQ q(IsStrictOrderedRing $α)
    assumeInstancesCommute
    have p : Q(NormNum.IsRat $e $n $d) := p
    if 0 < q then
      haveI' w : decide (0 < $n) =Q true := ⟨⟩
      pure (.positive q(pos_of_isRat $p $w))
    else if q = 0 then -- should not be reachable, but just in case
      haveI' w : decide ($n = 0) =Q true := ⟨⟩
      pure (.nonnegative q(nonneg_of_isRat $p $w))
    else
      haveI' w : decide ($n < 0) =Q true := ⟨⟩
      pure (.nonzero q(nz_of_isRat $p $w))
Positivity proof for numeric literals
Informal description
The function attempts to prove a `Strictness` result for an expression `e` of type `α` when `e` evaluates to a literal number. It handles different cases: - For natural number literals: if positive, proves positivity; otherwise proves non-negativity - For negative integer literals: proves nonzeroness - For rational number literals: proves positivity when positive, non-negativity when zero, and nonzeroness when negative
Mathlib.Meta.Positivity.positivityCanon definition
(e : Q($α)) : MetaM (Strictness zα pα e)
Full source
/-- Attempts to prove that `e ≥ 0` using `zero_le` in a `CanonicallyOrderedAdd` monoid. -/
def positivityCanon (e : Q($α)) : MetaM (Strictness zα pα e) := do
  let _add ← synthInstanceQ q(AddMonoid $α)
  let _le ← synthInstanceQ q(PartialOrder $α)
  let _i ← synthInstanceQ q(CanonicallyOrderedAdd $α)
  assumeInstancesCommute
  pure (.nonnegative q(zero_le $e))
Non-negativity in canonically ordered additive monoids
Informal description
The function attempts to prove that an expression \( e \) of type \( \alpha \) satisfies \( e \geq 0 \) in a canonically ordered additive monoid by using the lemma `zero_le`.
Mathlib.Meta.Positivity.compareHypLE definition
(lo e : Q($α)) (p₂ : Q($lo ≤ $e)) : MetaM (Strictness zα pα e)
Full source
/-- A variation on `assumption` when the hypothesis is `lo ≤ e` where `lo` is a numeral. -/
def compareHypLE (lo e : Q($α)) (p₂ : Q($lo ≤ $e)) : MetaM (Strictness zα pα e) := do
  match ← normNumPositivity zα pα lo with
  | .positive p₁ => pure (.positive q(lt_of_lt_of_le $p₁ $p₂))
  | .nonnegative p₁ => pure (.nonnegative q(le_trans $p₁ $p₂))
  | _ => pure .none
Positivity inference from lower bound
Informal description
Given expressions `lo` and `e` of type `α` and a proof `p₂` that `lo ≤ e`, this function attempts to determine the strictness property of `e` by first analyzing `lo`: - If `lo` is positive (with proof `p₁`), then `e` is positive (since `lo ≤ e` and `0 < lo` implies `0 < e`) - If `lo` is non-negative (with proof `p₁`), then `e` is non-negative (since `0 ≤ lo ≤ e` implies `0 ≤ e`) - Otherwise, no conclusion can be drawn about `e`
Mathlib.Meta.Positivity.compareHypLT definition
(lo e : Q($α)) (p₂ : Q($lo < $e)) : MetaM (Strictness zα pα e)
Full source
/-- A variation on `assumption` when the hypothesis is `lo < e` where `lo` is a numeral. -/
def compareHypLT (lo e : Q($α)) (p₂ : Q($lo < $e)) : MetaM (Strictness zα pα e) := do
  match ← normNumPositivity zα pα lo with
  | .positive p₁ => pure (.positive q(lt_trans $p₁ $p₂))
  | .nonnegative p₁ => pure (.positive q(lt_of_le_of_lt $p₁ $p₂))
  | _ => pure .none
Positivity from lower bound inequality
Informal description
Given expressions `lo` and `e` of type `α` and a proof `p₂` that `lo < e`, the function attempts to prove a `Strictness` result for `e` by first analyzing `lo`: - If `lo` is positive (with proof `p₁`), it proves `e` is positive using transitivity of `<` - If `lo` is non-negative (with proof `p₁`), it proves `e` is positive by combining `p₁` and `p₂` - Otherwise, it returns no result
Mathlib.Meta.Positivity.compareHypEq definition
(e x : Q($α)) (p₂ : Q($x = $e)) : MetaM (Strictness zα pα e)
Full source
/-- A variation on `assumption` when the hypothesis is `x = e` where `x` is a numeral. -/
def compareHypEq (e x : Q($α)) (p₂ : Q($x = $e)) : MetaM (Strictness zα pα e) := do
  match ← normNumPositivity zα pα x with
  | .positive p₁ => pure (.positive q(lt_of_lt_of_eq $p₁ $p₂))
  | .nonnegative p₁ => pure (.nonnegative q(le_of_le_of_eq $p₁ $p₂))
  | .nonzero p₁ => pure (.nonzero q(ne_of_ne_of_eq' $p₁ $p₂))
  | .none => pure .none
Positivity analysis for equality hypotheses
Informal description
Given expressions `e` and `x` of type `α` and a proof `p₂` that `x = e`, the function attempts to determine the strictness property of `e` by first analyzing `x` using `normNumPositivity`. Depending on the result for `x`, it returns: - If `x` is positive, proves `e` is positive - If `x` is non-negative, proves `e` is non-negative - If `x` is nonzero, proves `e` is nonzero - Otherwise returns no conclusion
Mathlib.Meta.Positivity.compareHyp definition
(e : Q($α)) (ldecl : LocalDecl) : MetaM (Strictness zα pα e)
Full source
/-- A variation on `assumption` which checks if the hypothesis `ldecl` is `a [</≤/=] e`
where `a` is a numeral. -/
def compareHyp (e : Q($α)) (ldecl : LocalDecl) : MetaM (Strictness zα pα e) := do
  have e' : Q(Prop) := ldecl.type
  let p : Q($e') := .fvar ldecl.fvarId
  match e' with
  | ~q(@LE.le.{u} $β $_le $lo $hi) =>
    let .defEq (_ : $α =Q $β) ← isDefEqQ α β | return .none
    let .defEq _ ← isDefEqQ e hi | return .none
    match lo with
    | ~q(0) =>
      assertInstancesCommute
      return .nonnegative q($p)
    | _ => compareHypLE zα pα lo e p
  | ~q(@LT.lt.{u} $β $_lt $lo $hi) =>
    let .defEq (_ : $α =Q $β) ← isDefEqQ α β | return .none
    let .defEq _ ← isDefEqQ e hi | return .none
    match lo with
    | ~q(0) =>
      assertInstancesCommute
      return .positive q($p)
    | _ => compareHypLT zα pα lo e p
  | ~q(@Eq.{u+1} $α' $lhs $rhs) =>
    let .defEq (_ : $α =Q $α') ← isDefEqQ α α' | pure .none
    match ← isDefEqQ e rhs with
    | .defEq _ =>
      match lhs with
      | ~q(0) => pure <| .nonnegative q(le_of_eq $p)
      | _ => compareHypEq zα pα e lhs q($p)
    | .notDefEq =>
      let .defEq _ ← isDefEqQ e lhs | pure .none
      match rhs with
      | ~q(0) => pure <| .nonnegative q(ge_of_eq $p)
      | _ => compareHypEq zα pα e rhs q(Eq.symm $p)
  | ~q(@Ne.{u + 1} $α' $lhs $rhs) =>
    let .defEq (_ : $α =Q $α') ← isDefEqQ α α' | pure .none
    match lhs, rhs with
    | ~q(0), _ =>
      let .defEq _ ← isDefEqQ e rhs | pure .none
      pure <| .nonzero q(Ne.symm $p)
    | _, ~q(0) =>
      let .defEq _ ← isDefEqQ e lhs | pure .none
      pure <| .nonzero q($p)
    | _, _ => pure .none
  | _ => pure .none
Positivity analysis from hypothesis
Informal description
Given an expression `e` of type `α` and a local declaration `ldecl`, this function checks if `ldecl` is of the form `a [
Mathlib.Meta.Positivity.orElse definition
{e : Q($α)} (t₁ : Strictness zα pα e) (t₂ : MetaM (Strictness zα pα e)) : MetaM (Strictness zα pα e)
Full source
/-- The main combinator which combines multiple `positivity` results.
It assumes `t₁` has already been run for a result, and runs `t₂` and takes the best result.
It will skip `t₂` if `t₁` is already a proof of `.positive`, and can also combine
`.nonnegative` and `.nonzero` to produce a `.positive` result. -/
def orElse {e : Q($α)} (t₁ : Strictness zα pα e) (t₂ : MetaM (Strictness zα pα e)) :
    MetaM (Strictness zα pα e) := do
  match t₁ with
  | .none => catchNone t₂
  | p@(.positive _) => pure p
  | .nonnegative p₁ =>
    match ← catchNone t₂ with
    | p@(.positive _) => pure p
    | .nonzero p₂ => pure (.positive q(lt_of_le_of_ne' $p₁ $p₂))
    | _ => pure (.nonnegative p₁)
  | .nonzero p₁ =>
    match ← catchNone t₂ with
    | p@(.positive _) => pure p
    | .nonnegative p₂ => pure (.positive q(lt_of_le_of_ne' $p₂ $p₁))
    | _ => pure (.nonzero p₁)
Positivity result combination combinator
Informal description
The combinator `orElse` combines two positivity results for an expression `e` of type `α`. Given an initial strictness result `t₁` and a monadic computation `t₂` producing another strictness result, it returns the best possible combined result. Specifically: - If `t₁` is already `.positive`, it returns `t₁` immediately. - If `t₁` is `.nonnegative` and `t₂` yields `.nonzero`, it combines them to produce a `.positive` result. - If `t₁` is `.nonzero` and `t₂` yields `.nonnegative`, it combines them to produce a `.positive` result. - In all other cases, it returns the original result `t₁`.
Mathlib.Meta.Positivity.core definition
(e : Q($α)) : MetaM (Strictness zα pα e)
Full source
/-- Run each registered `positivity` extension on an expression, returning a `NormNum.Result`. -/
def core (e : Q($α)) : MetaM (Strictness zα pα e) := do
  let mut result := .none
  trace[Tactic.positivity] "trying to prove positivity of {e}"
  for ext in ← (positivityExt.getState (← getEnv)).2.getMatch e do
    try
      result ← orElse result <| ext.eval zα pα e
    catch err =>
      trace[Tactic.positivity] "{e} failed: {err.toMessageData}"
  result ← orElse result <| normNumPositivity zα pα e
  result ← orElse result <| positivityCanon zα pα e
  if let .positive _ := result then
    trace[Tactic.positivity] "{e} => {result.toString}"
    return result
  for ldecl in ← getLCtx do
    if !ldecl.isImplementationDetail then
      result ← orElse result <| compareHyp zα pα e ldecl
  trace[Tactic.positivity] "{e} => {result.toString}"
  throwNone (pure result)
Positivity analysis core function
Informal description
The function `core` attempts to determine the positivity properties of an expression `e` of type `α` by systematically applying all registered positivity extensions, numerical analysis, canonical order properties, and local hypotheses. It returns a `Strictness` result indicating whether `e` is positive, non-negative, or non-zero, or fails if no such property can be established. The analysis proceeds in several steps: 1. Applies all matching registered positivity extensions 2. Attempts numerical analysis for literal numbers 3. Uses canonical order properties when applicable 4. Considers local hypotheses that might imply positivity properties 5. Returns the strongest conclusion found or fails if no property is established
Mathlib.Meta.Positivity.bestResult definition
(e : Expr) : MetaM (Bool × Expr)
Full source
/-- Given an expression `e`, use the core method of the `positivity` tactic to prove it positive,
or, failing that, nonnegative; return a boolean (signalling whether the strict or non-strict
inequality was established) together with the proof as an expression. -/
def bestResult (e : Expr) : MetaM (BoolBool × Expr) := do
  let ⟨u, α, _⟩ ← inferTypeQ' e
  let zα ← synthInstanceQ q(Zero $α)
  let pα ← synthInstanceQ q(PartialOrder $α)
  match ← try? (Meta.Positivity.core zα pα e) with
  | some (.positive pf) => pure (true, pf)
  | some (.nonnegative pf) => pure (false, pf)
  | _ => throwError "could not establish the nonnegativity of {e}"
Optimal positivity result for an expression
Informal description
Given an expression `e`, the function `bestResult` attempts to determine the strongest positivity property that can be established for `e`. It returns a boolean indicating whether a strict positivity result was obtained (true for positive, false for non-negative) along with a proof of the corresponding inequality. The function first infers the type of `e`, synthesizes instances for zero and partial order, then attempts to apply the core positivity analysis. If successful, it returns either a proof of positivity or non-negativity; otherwise, it throws an error indicating that non-negativity could not be established.
Mathlib.Meta.Positivity.proveNonneg definition
(e : Expr) : MetaM Expr
Full source
/-- Given an expression `e`, use the core method of the `positivity` tactic to prove it nonnegative.
-/
def proveNonneg (e : Expr) : MetaM Expr := do
  let (strict, pf) ← bestResult e
  if strict then mkAppM ``le_of_lt #[pf] else pure pf
Non-negativity prover for expressions
Informal description
Given an expression `e`, the function `proveNonneg` attempts to prove that `e` is non-negative. It first uses the `bestResult` function to determine the strongest positivity property of `e` (either strict positivity or non-negativity), and then returns a proof of non-negativity. If `bestResult` returns a proof of strict positivity, it converts this to a proof of non-negativity using the lemma `le_of_lt`.
Mathlib.Meta.Positivity.solve definition
(t : Q(Prop)) : MetaM Expr
Full source
/-- An auxiliary entry point to the `positivity` tactic. Given a proposition `t` of the form
`0 [≤/</≠] e`, attempts to recurse on the structure of `t` to prove it. It returns a proof
or fails. -/
def solve (t : Q(Prop)) : MetaM Expr := do
  let rest {u : Level} (α : Q(Type u)) z e (relDesired : OrderRel) : MetaM Expr := do
    let zα ← synthInstanceQ q(Zero $α)
    assumeInstancesCommute
    let .true ← isDefEq z q(0 : $α) | throwError "not a positivity goal"
    let pα ← synthInstanceQ q(PartialOrder $α)
    assumeInstancesCommute
    let r ← catchNone <| Meta.Positivity.core zα pα e
    let throw (a b : String) : MetaM Expr := throwError
      "failed to prove {a}, but it would be possible to prove {b} if desired"
    let p ← show MetaM Expr from match relDesired, r with
    | .lt, .positive p
    | .le, .nonnegative p
    | .ne, .nonzero p => pure p
    | .le, .positive p => pure q(le_of_lt $p)
    | .ne, .positive p => pure q(ne_of_gt $p)
    | .ne', .positive p => pure q(ne_of_lt $p)
    | .ne', .nonzero p => pure q(Ne.symm $p)
    | .lt, .nonnegative _ => throw "strict positivity" "nonnegativity"
    | .lt, .nonzero _ => throw "strict positivity" "nonzeroness"
    | .le, .nonzero _ => throw "nonnegativity" "nonzeroness"
    | .ne, .nonnegative _
    | .ne', .nonnegative _ => throw "nonzeroness" "nonnegativity"
    | _, .none => throwError "failed to prove positivity/nonnegativity/nonzeroness"
    pure p
  match t with
  | ~q(@LE.le $α $_a $z $e) => rest α z e .le
  | ~q(@LT.lt $α $_a $z $e) => rest α z e .lt
  | ~q($a ≠ ($b : ($α : Type _))match t with
  | ~q(@LE.le $α $_a $z $e) => rest α z e .le
  | ~q(@LT.lt $α $_a $z $e) => rest α z e .lt
  | ~q($a ≠ ($b : ($α : Type _))) =>
    let _zα ← synthInstanceQ q(Zero $α)
    if ← isDefEq b q((0 : $α)) then
      rest α b a .ne
    else
      let .true ← isDefEq a q((0 : $α)) | throwError "not a positivity goal"
      rest α a b .ne'
  | _ => throwError "not a positivity goal"
Positivity goal solver
Informal description
The function `solve` takes a proposition `t` of the form `0 ≤ e`, `0 < e`, or `e ≠ 0` (for some expression `e` of type `α` with zero and partial order structure) and attempts to prove it by recursively analyzing the structure of `e`. It returns a proof of the proposition if successful, or fails otherwise. The analysis proceeds by: 1. Checking if the goal matches one of the supported forms (`0 ≤ e`, `0 < e`, or `e ≠ 0`) 2. Synthesizing required typeclass instances (zero and partial order) 3. Applying the core positivity analysis to determine the strongest provable property of `e` 4. Converting the result to match the desired relation in the goal 5. Returning an appropriate proof or failing with an informative error message
Mathlib.Meta.Positivity.positivity definition
(goal : MVarId) : MetaM Unit
Full source
/-- The main entry point to the `positivity` tactic. Given a goal `goal` of the form `0 [≤/</≠] e`,
attempts to recurse on the structure of `e` to prove the goal.
It will either close `goal` or fail. -/
def positivity (goal : MVarId) : MetaM Unit := do
  let t : Q(Prop) ← withReducible goal.getType'
  let p ← solve t
  goal.assign p
Positivity tactic
Informal description
The `positivity` tactic attempts to prove goals of the form \(0 \leq e\), \(0 < e\), or \(e \neq 0\) by recursively analyzing the structure of the expression \(e\). If successful, it closes the goal; otherwise, it fails.
Mathlib.Tactic.Positivity.positivity definition
: Lean.ParserDescr✝
Full source
/-- Tactic solving goals of the form `0 ≤ x`, `0 < x` and `x ≠ 0`.  The tactic works recursively
according to the syntax of the expression `x`, if the atoms composing the expression all have
numeric lower bounds which can be proved positive/nonnegative/nonzero by `norm_num`.  This tactic
either closes the goal or fails.

Examples:
```
example {a : ℤ} (ha : 3 < a) : 0 ≤ a ^ 3 + a := by positivity

example {a : ℤ} (ha : 1 < a) : 0 < |(3:ℤ) + a| := by positivity

example {b : ℤ} : 0 ≤ max (-3) (b ^ 2) := by positivity
```
-/
elab (name := positivity) "positivity" : tactic => do
  liftMetaTactic fun g => do Meta.Positivity.positivity g; pure []
Positivity tactic
Informal description
The `positivity` tactic is designed to solve goals of the form \(0 \leq x\), \(0 < x\), or \(x \neq 0\). It operates recursively on the structure of the expression \(x\), provided that all its constituent atoms have numeric lower bounds that can be verified as positive, nonnegative, or nonzero using the `norm_num` tactic. The tactic either successfully closes the goal or fails. Examples of its use include proving \(0 \leq a^3 + a\) given \(3 < a\), \(0 < |3 + a|\) given \(1 < a\), and \(0 \leq \max(-3, b^2)\) for an integer \(b\).