Zulip Chat Archive

Stream: mathlib4

Topic: writing a positivity extension


Jireh Loreaux (Nov 10 2023 at 21:09):

I'm trying to write a positivity extension for docs#StarOrderedRing to make use of things like docs#mul_star_self_nonneg and docs#conjugate_nonneg. By cargo cult coding from the basic positivity extensions, I can make the former work fairly easily. However, when I try to generalize to make it handle multiple forms simultaneously by matching on the expression, I get errors. What am I doing wrong here in the second attempt?

import Mathlib

namespace Mathlib.Meta.Positivity
open Lean Meta Expr Qq

/-- The `positivity` extension which identifies expressions of the form `star a * a`. -/
@[positivity _ * _, Mul.mul _ _] def evalStarMul : PositivityExt where eval {u α}   e := do
  let _a  synthInstanceQ q(NonUnitalSemiring $α)
  let _a'  synthInstanceQ q(StarOrderedRing $α)
  assumeInstancesCommute
  let .app (.app (f : Q($α  $α  $α)) (.app (s : Q($α  $α)) (a : Q($α)))) (b : Q($α))  withReducible (whnf e)
    | throwError "not *"
  let _e_eq : $e =Q $f ($s $a) $b := ⟨⟩
  let _f_eq  withDefault <| withNewMCtxDepth <| assertDefEqQ (u := u.succ) f q(HMul.hMul)
  let _s_eq  withDefault <| withNewMCtxDepth <| assertDefEqQ (u := u.succ) s q(Star.star)
  let _a_eq_b  withDefault <| withNewMCtxDepth <| assertDefEqQ (u := u) a b
  pure (.nonnegative q(star_mul_self_nonneg $a))

example (a : ) : 0  star a * a := by
  positivity -- works! yay!

@[positivity _ * _, Mul.mul _ _] def evalStarMul' : PositivityExt where eval {u α}   e := do
  let e : Q($α)  whnfR e
  let _inst₁  synthInstanceQ q(NonUnitalSemiring $α)
  let _inst₂  synthInstanceQ q(StarOrderedRing $α)
  assumeInstancesCommute
  match e with
  | ~q((star $a) * $b) =>
    let _a_eq_b  withDefault <| withNewMCtxDepth <| assertDefEqQ (u := u) a b
    let _e_eq : $e =Q (star $a) * $a := ⟨⟩
    pure (.nonnegative q(star_mul_self_nonneg $a))
    /-
    type mismatch
      star_mul_self_nonneg «$a»
    has type
      0 ≤ star «$a» * «$a» : Prop
    but is expected to have type
      0 ≤ $e✝ : Prop
    -/

Jireh Loreaux (Nov 10 2023 at 21:13):

Separate but connected question: is it possible to make positivity attributes scoped? when I tried to do that I got "invalid attribute positivity, must be global"

Yaël Dillies (Nov 10 2023 at 21:16):

It was the case in Lean 3. Not anymore :sad:

Jireh Loreaux (Nov 10 2023 at 21:29):

nevermind, this is just because I called it e again in the first let so the original was inaccessible. Ignore the noise.

Jireh Loreaux (Nov 10 2023 at 21:40):

Why can't it be scoped anymore?

Yaël Dillies (Nov 10 2023 at 21:41):

No clue. Probably it simply hasn't been implemented?

Mario Carneiro (Nov 10 2023 at 21:41):

scoped extensions have to be implemented individually, it's just a matter of implementation work

Mario Carneiro (Nov 10 2023 at 21:41):

it's also a bit slower/more complicated than global-only attributes

Scott Morrison (Nov 11 2023 at 00:21):

See Std.Tactic.LabelAttr for a minimal example of how to set up removable attributes.

(These label attributes are for cases where we're not doing any work when adding the attribute: we just need to know if it is there or not.)

Someone needs to add this functionality to the positivity attribute.

Frédéric Dupuis (Nov 11 2023 at 01:05):

(deleted)

Yury G. Kudryashov (Jan 08 2024 at 16:25):

I see that most positivity extensions fist tell the expression(s) they can handle in the @[positivity] argument, then match using Qq. Why do we need this?

David Renshaw (Jan 08 2024 at 16:26):

The match pattern in the attribute dictates when the extension is activated (via a DiscrTree lookup). The match inside the body is typically to extract subterms.

Yury G. Kudryashov (Jan 08 2024 at 16:33):

It would be nice to have an attribute that generates correct code for simple cases like src#Mathlib.Meta.Positivity.evalENNRealtoReal

Yury G. Kudryashov (Jan 08 2024 at 16:34):

In #9545, @Eric Wieser suggested that we use a different pattern in a very similar case.

Yury G. Kudryashov (Jan 08 2024 at 16:36):

And a generic function looks like a better way to handle this (rather than going through the library and making sure that all functions follow the same pattern)

Eric Wieser (Jan 08 2024 at 16:38):

I think part of the reason is that a DiscrTree lookup is not guaranteed to be a perfect match, and so we have to do a second check to be sure

Yaël Dillies (Jan 08 2024 at 16:40):

I don't know how relevant this is here, but note that you can overapply functions, eg you can do @[positivity (_ * _) _] to match applied pointwise multiplication.

Eric Wieser (Feb 02 2024 at 21:50):

Related to this conversation; #10196 starts cleaning up some of the matches to exploit the fixes in Lean v4.6.0-rc1.


Last updated: May 02 2025 at 03:31 UTC