Zulip Chat Archive

Stream: mathlib4

Topic: positivity regression


Yaël Dillies (Sep 15 2023 at 09:40):

I have an issue with docs#Mathlib.Tactic.Positivity.evalMul (which came from @Mario Carneiro's #578). This line means that the extension only works in StrictOrderedSemirings, except that docs#mul_nonneg works more generally in ordered semirings.

Yaël Dillies (Sep 15 2023 at 09:41):

This is relevant to me since I am using positivity to prove goals of the form 0 ≤ f * g where f g : ι → ℝ, and ι → ℝ is not a strictly ordered semiring.

Yaël Dillies (Sep 15 2023 at 09:41):

Is there an easy fix?

Ruben Van de Velde (Sep 15 2023 at 09:59):

So what's the issue? Does weakening that line break its support for 0 < goals?

Eric Wieser (Sep 15 2023 at 09:59):

Isn't the easy fix replacing that synthesis line?

Ruben Van de Velde (Sep 15 2023 at 10:00):

If that's the case, could we move the synthesis into each of the match arms?

Yaël Dillies (Sep 15 2023 at 10:00):

That's what I would think. But I have no Lean 4 metaprogramming experience, and even less experience with Qq!

Eric Wieser (Sep 15 2023 at 10:00):

I think we might need to tweak the code slightly to look more like what I wrote in #7089

Eric Wieser (Sep 15 2023 at 10:01):

That is, to find the initial instances by unification so that we can call core on them, before looking for stronger instances in the match arms

Yaël Dillies (Sep 15 2023 at 10:05):

While I'm at it, is there any obvious reason why the following extension doesn't work?

import Mathlib.Data.Rat.Order
import Mathlib.Tactic.Positivity

lemma Rat.num_ne_zero {q : } : q.num  0  q  0 := Rat.num_eq_zero.not

namespace Mathlib.Meta.Positivity
open Lean Meta Qq Function Rat

alias _, num_pos_of_pos := num_pos_iff_pos
alias _, num_nonneg_of_nonneg := num_nonneg_iff_zero_le
alias _, num_ne_zero_of_ne_zero := num_ne_zero

/-- The `positivity` extension which identifies expressions of the form `Rat.num a`,
such that `positivity` successfully recognises `a`. -/
@[positivity (Rat.num _)]
def evalRatnum : PositivityExt where eval {_u } _zα _pα e := do
  let .app _ (a : Q())  withReducible (whnf e) | throwError "not Rat.num"
  let zα' : Q(Zero ) := q(inferInstance)
  let pα' : Q(PartialOrder ) := q(inferInstance)
  let ra  core zα' pα' a
  match ra with
  | .positive pa =>
    pure (.positive (q(num_pos_of_pos $pa) : Expr))
  | .nonnegative pa =>
    pure (.nonnegative (q(num_nonneg_of_nonneg $pa) : Expr))
  | .nonzero pa =>
    pure (.nonzero (q(num_ne_zero_of_ne_zero $pa) : Expr))
  | .none =>
    pure .none

/-- The `positivity` extension which identifies expressions of the form `Rat.den a`. -/
@[positivity Rat.den _]
def evalRatden : PositivityExt where eval {_u } _zα _pα e := do
  let .app _ (a : Q())  withReducible (whnf e) | throwError "not Rat.den"
  pure (.positive (q(den_pos $a) : Expr))

variable {q : }

example (hq : 0 < q) : 0 < q.num := by positivity -- failed
example (hq : 0  q) : 0  q.num := by positivity -- failed
example (hq : q  0) : q.num  0 := by positivity -- failed
example : 0 < q.den := by positivity -- failed

end Mathlib.Meta.Positivity

Yaël Dillies (Sep 15 2023 at 10:08):

(actually, feel free to move this to #metaprogramming / tactics, I forgot that stream existed)

Yaël Dillies (Sep 15 2023 at 10:16):

Update: Just added my attempt for Rat.den, which is even easier but which I still failed miserably :sob:

Eric Wieser (Sep 15 2023 at 10:18):

I'll have a go at those in half an hour

Eric Wieser (Sep 15 2023 at 13:00):

This works:

import Mathlib.Data.Rat.Order
import Mathlib.Tactic.Positivity

namespace Mathlib.Meta.Positivity
open Lean Meta Qq Function Rat

alias _, num_pos_of_pos := num_pos_iff_pos
alias _, num_nonneg_of_nonneg := num_nonneg_iff_zero_le
alias _, num_ne_zero_of_ne_zero := num_ne_zero

/-- The `positivity` extension which identifies expressions of the form `Rat.num a`,
such that `positivity` successfully recognises `a`. -/
@[positivity (Rat.num _)]
def evalRatnum : PositivityExt where eval {_u } _zα _pα (e : Q()) := do
  let ~q(Rat.num $a) := e | throwError "not Rat.num"
  let zα' : Q(Zero ) := q(inferInstance)
  let pα' : Q(PartialOrder ) := q(inferInstance)
  -- TODO: what's the right way to write these `: Expr`s?
  match  core zα' pα' a with
  | .positive pa =>
    return .positive (q(num_pos_of_pos $pa) : Expr)
  | .nonnegative pa =>
    return .nonnegative (q(num_nonneg_of_nonneg $pa) : Expr)
  | .nonzero pa =>
    return .nonzero (q(num_ne_zero_of_ne_zero $pa) : Expr)
  | .none =>
    pure .none

/-- The `positivity` extension which identifies expressions of the form `Rat.den a`. -/
@[positivity Rat.den _]
def evalRatden : PositivityExt where eval {_u } _zα _pα (e : Q()) := do
  let ~q(Rat.den $a) := e | throwError "not Rat.den"
  return .positive (q(den_pos $a) :)

variable {q : }

example (hq : 0 < q) : 0 < q.num := by positivity -- ok!
example (hq : 0  q) : 0  q.num := by positivity -- ok!
example (hq : q  0) : q.num  0 := by positivity -- ok!
example : 0 < q.den := by positivity -- ok!

end Mathlib.Meta.Positivity

Eric Wieser (Sep 15 2023 at 13:01):

These : Exprs feel like one of:

  • A design flaw in PositivityExt
  • A Qq bug
  • Me not knowing what I'm doing with Qq

Yaël Dillies (Sep 15 2023 at 13:05):

So my mistake was the match?

Yaël Dillies (Sep 15 2023 at 13:08):

Aaah, I see. Am I right in thinking it's because I didn't type-ascript e, so Qq couldn't derive the type-correctness of my subsequent match?

Eric Wieser (Sep 15 2023 at 20:09):

Yes, the match isn't even well-typed if you don't first lie about the type of e

David Renshaw (Sep 15 2023 at 20:13):

in what sense is that ascription a "lie"?

David Renshaw (Sep 15 2023 at 20:14):

My understanding of (e : Q(ℕ)) is that we are asserting that e is an expression of type .

Eric Wieser (Sep 15 2023 at 20:21):

Right, but we've been told it's of type _α : Q(Type u) (we also aren't told that u = level.zero)

Eric Wieser (Sep 15 2023 at 20:22):

Which we're ignoring because we "know better" (about the internals of the positivity tactic and how it promises to call us)

Mario Carneiro (Sep 15 2023 at 20:24):

it's more about the fact that your let ~q(Rat.num $a) := e implies some things about u and alpha which the type system doesn't know

Eric Wieser (Sep 15 2023 at 20:24):

Is it something that the type system could know?

Mario Carneiro (Sep 15 2023 at 20:24):

working on it

Eric Wieser (Sep 15 2023 at 20:25):

It seems like we could refactor positivity extensions somehow so that the match and lookup are simultaneous

Yury G. Kudryashov (Oct 29 2023 at 05:30):

positivity extension for docs#Real.sqrt doesn't work for me.

Yury G. Kudryashov (Oct 29 2023 at 05:30):

How do I debug it?

Yury G. Kudryashov (Oct 29 2023 at 05:43):

More details:

example (x : ) (hx : 0 < x) : 0 < Real.sqrt x := by positivity -- works
example (x : ) : 0  Real.sqrt x := by positivity -- fails

Yury G. Kudryashov (Oct 29 2023 at 06:29):

It looks like the function doesn't get past the let ra ← core zα' pα' a line without (_ : 0 < x).

Yury G. Kudryashov (Oct 29 2023 at 06:38):

Probably, the call to core fails instead of returning none.

David Renshaw (Oct 29 2023 at 12:48):

Yep:
https://github.com/leanprover-community/mathlib4/blob/b56efa53d7479fda9740f364170cbaef34699dee/Mathlib/Tactic/Positivity/Core.lean#L304

David Renshaw (Oct 29 2023 at 12:54):

This fixes it:

diff --git a/Mathlib/Data/Real/Sqrt.lean b/Mathlib/Data/Real/Sqrt.lean
index 970b33638..ca73aab94 100644
--- a/Mathlib/Data/Real/Sqrt.lean
+++ b/Mathlib/Data/Real/Sqrt.lean
@@ -380,7 +380,7 @@ def evalSqrt : PositivityExt where eval {_ _} _zα _pα e := do
   let (.app _ (a : Q(Real)))  whnfR e | throwError "not Real.sqrt"
   let zα'  synthInstanceQ (q(Zero Real) : Q(Type))
   let pα'  synthInstanceQ (q(PartialOrder Real) : Q(Type))
-  let ra  core zα' pα' a
+  let ra  catchNone <| core zα' pα' a
   assertInstancesCommute
   match ra with

David Renshaw (Oct 29 2023 at 12:55):

But makes me wonder why the throwNone exists in the first place

David Renshaw (Oct 29 2023 at 13:02):

mathlib4#8014

Yury G. Kudryashov (Oct 29 2023 at 15:31):

Thanks a lot!


Last updated: Dec 20 2023 at 11:08 UTC