Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - feat: Port positivity extensions for Nat.ceil, Int.ceil, Int.floor #7089

Closed
wants to merge 11 commits into from

Conversation

dwrensha
Copy link
Member


Open in Gitpod

@dwrensha dwrensha added the awaiting-review The author would like community review of the PR label Sep 10, 2023
Comment on lines 1738 to 1739
let (.app (.app (.app (.app _ (α' : Q(Type))) _) _) a) ← whnfR e
| throwError "failed to match on Int.floor application"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to tell what this is matching for!

And is it really meant to be constrained to Type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use a Qq match here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to tell what this is matching for!

I added some comments and included the .const head. Hopefully that makes things clearer.

And is it really meant to be constrained to Type?

Ah, good point. This should be Type u. Fixed.

Copy link
Member Author

@dwrensha dwrensha Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use a Qq match here?

Maybe! But I was unable to figure out how. Even if we do figure it out, I suspect the result will be more complicated that what I have here. (For one thing, I think it would require adding more synthInstanceQ.)

Comment on lines 1738 to 1740
-- match on `@Int.floor α' _ _ a`
let (.app (.app (.app (.app (.const ``Int.floor _) (α' : Q(Type $u))) _) _) a) ← whnfR e
| throwError "failed to match on Int.floor application"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Qq syntax is something like

  have e : Q(ℤ) := ← whnfR e
  let ~q(@Int.floor $α' $inst1 $inst2 $a) := e | throwError "failed to match on Int.floor application"

thought I seem to be having trouble making the rest work

Comment on lines 1735 to 1746
/-- Extension for the `positivity` tactic: `Int.floor` is nonnegative if its input is. -/
@[positivity ⌊ _ ⌋]
def evalFloor : PositivityExt where eval {u _α} _zα _pα e := do
-- match on `@Int.floor α' _ _ a`
let (.app (.app (.app (.app (.const ``Int.floor _) (α' : Q(Type $u))) _) _) a) ← whnfR e
| throwError "failed to match on Int.floor application"
let zα' : Q(Zero $α') ← synthInstanceQ q(Zero $α')
let pα' : Q(PartialOrder $α') ← synthInstanceQ q(PartialOrder $α')
match ← core zα' pα' a with
| .positive pa => pure (.nonnegative (← mkAppM ``int_floor_nonneg_of_pos #[pa]))
| .nonnegative pa => pure (.nonnegative (← mkAppM ``int_floor_nonneg #[pa]))
| _ => pure .none
Copy link
Member

@eric-wieser eric-wieser Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a full Qq version:

Suggested change
/-- Extension for the `positivity` tactic: `Int.floor` is nonnegative if its input is. -/
@[positivity ⌊ _ ⌋]
def evalFloor : PositivityExt where eval {u _α} _zα _pα e := do
-- match on `@Int.floor α' _ _ a`
let (.app (.app (.app (.app (.const ``Int.floor _) (α' : Q(Type $u))) _) _) a) ← whnfR e
| throwError "failed to match on Int.floor application"
let zα' : Q(Zero $α') ← synthInstanceQ q(Zero $α')
let pα' : Q(PartialOrder $α') ← synthInstanceQ q(PartialOrder $α')
match ← core zα' pα' a with
| .positive pa => pure (.nonnegative (← mkAppM ``int_floor_nonneg_of_pos #[pa]))
| .nonnegative pa => pure (.nonnegative (← mkAppM ``int_floor_nonneg #[pa]))
| _ => pure .none
/-- Extension for the `positivity` tactic: `Int.floor` is nonnegative if its input is. -/
@[positivity ⌊ _ ⌋]
def evalFloor : PositivityExt where eval {_u _α} _zα _pα (e : Q(ℤ)) := do
let ~q(@Int.floor $α' $i $j $a) := e | throwError "failed to match on Int.floor application"
let zα' : Q(Zero $α') ← synthInstanceQ (u := u_1.succ) _
let pα' : Q(PartialOrder $α') ← synthInstanceQ (u := u_1.succ) _
assertInstancesCommute
match ← core zα' pα' a with
| .positive pa =>
letI ret : Q(0 ≤ $e) := q(int_floor_nonneg_of_pos (α := $α') $pa)
pure (.nonnegative ret)
| .nonnegative pa =>
letI ret : Q(0 ≤ $e) := q(int_floor_nonneg (α := $α') $pa)
pure (.nonnegative ret)
| _ => pure .none

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
I actually prefer what I have, as it's shorter and easier (for me at least) to understand.

I guess that u_1 gets inserted into the context from the ~q() match? Is there a way to make that binding explicit?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the u_1 is being inserted unhygienically and I can't work out how to name it.

The advantage of my spelling is that it's much less fragile to argument changes to Int.floor.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The advantage of my spelling is that it's much less fragile to argument changes to Int.floor.

How so? It seems to me that your matching on ~q(@Int.floor $α' $i $j $a) is essentially the same as my matching on (.app (.app (.app (.app (.const ``Int.floor [u']) (α' : Q(Type $u'))) _) _) a)

Copy link
Member

@eric-wieser eric-wieser Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a shorter version, that does the instance search at compile time:

Suggested change
/-- Extension for the `positivity` tactic: `Int.floor` is nonnegative if its input is. -/
@[positivity ⌊ _ ⌋]
def evalFloor : PositivityExt where eval {u _α} _zα _pα e := do
-- match on `@Int.floor α' _ _ a`
let (.app (.app (.app (.app (.const ``Int.floor _) (α' : Q(Type $u))) _) _) a) ← whnfR e
| throwError "failed to match on Int.floor application"
let zα' : Q(Zero $α') ← synthInstanceQ q(Zero $α')
let pα' : Q(PartialOrder $α') ← synthInstanceQ q(PartialOrder $α')
match ← core zα' pα' a with
| .positive pa => pure (.nonnegative (← mkAppM ``int_floor_nonneg_of_pos #[pa]))
| .nonnegative pa => pure (.nonnegative (← mkAppM ``int_floor_nonneg #[pa]))
| _ => pure .none
/-- Extension for the `positivity` tactic: `Int.floor` is nonnegative if its input is. -/
@[positivity ⌊ _ ⌋]
def evalFloor : PositivityExt where eval {_u _α} _zα _pα (e : Q(ℤ)) := do
let ~q(@Int.floor $α' $i $j $a) := e | throwError "failed to match on Int.floor application"
match ← core q(inferInstance) q(inferInstance) a with
| .positive pa =>
letI ret : Q(0 ≤ $e) := q(int_floor_nonneg_of_pos (α := $α') $pa)
pure (.nonnegative <| ret)
| .nonnegative pa =>
letI ret : Q(0 ≤ $e) := q(int_floor_nonneg (α := $α') $pa)
pure (.nonnegative ret)
| _ => pure .none

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, that's starting to look more reasonable. I'll try that.

Copy link
Member

@eric-wieser eric-wieser Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How so? It seems to me that your matching on ~q(@Int.floor $α' $i $j $a) is essentially the same as my matching on (.app (.app (.app (.app (.const ``Int.floor [u']) (α' : Q(Type $u'))) _) _) a)

If the syntax changes, my code will become a Qq error at compile time. Yours will become a match failure at tactic use.

@dwrensha
Copy link
Member Author

I have not been able to get the Nat.ceil case to fully work with Qq. Here's what I have:

/-- Extension for the `positivity` tactic: `Nat.ceil` is positive if its input is. -/
@[positivity ⌈ _ ⌉₊]
def evalNatCeil : PositivityExt where eval {_u _α} _zα _pα (e : Q(ℕ)) := do
  let ~q(@Nat.ceil $α' $i $j $a) := e | throwError "failed to match on Nat.ceil application"
  match ← core q(inferInstance) q(inferInstance) a with
  | .positive pa =>
      let _los : Q(LinearOrderedSemiring $α') ← synthInstanceQ q(LinearOrderedSemiring $α')
      letI ret : Q(0 < $e) := q(nat_ceil_pos (α := $α') $pa)
      pure (.positive ret)
  | _ => pure .none

and I get the error:

application type mismatch
  Mathlib.Meta.Positivity.nat_ceil_pos «$pa»
argument
  «$pa»
has type
  @OfNat.ofNat «$α'» 0 (@Zero.toOfNat0 «$α'» inferInstance) < «$a» : Prop
but is expected to have type
  @OfNat.ofNat «$α'» 0 (@Zero.toOfNat0 «$α'» MonoidWithZero.toZero) < ?m.346824 : Prop

@dwrensha
Copy link
Member Author

I pushed a version that uses Qq for the matching part of Nat.ceil. I still have not figured out how to make it work for the proof construction part, but I'm not too worried about that, as the matching part is where the main concerns were in our discussion above.

Comment on lines +1726 to +1733
private theorem int_floor_nonneg [LinearOrderedRing α] [FloorRing α] {a : α} (ha : 0 ≤ a) :
0 ≤ ⌊a⌋ :=
Int.floor_nonneg.2 ha

private theorem int_floor_nonneg_of_pos [LinearOrderedRing α] [FloorRing α] {a : α}
(ha : 0 < a) :
0 ≤ ⌊a⌋ :=
int_floor_nonneg ha.le
Copy link
Member

@eric-wieser eric-wieser Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if there's now any benefit to these; presumably you could inline them in the q()s below. Maybe there's a performance benefit with having them separated? cc @semorrison, @gebner.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious too! I kept them like this (as they were in mathlib3) for the sake of making the port as direct as possible.

Copy link
Member Author

@dwrensha dwrensha Sep 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the point is that in mathlib3, inlining was more painful because there was no q()?

(hm... but these are all just a single application, so constructing them without q() is not very cumbersome at all. So... I'm at a loss)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote the original extensions. It was very hard to make mk_app work reliably and I resorted to never use it more than once per term construction. A typical problem is that it would eagerly try to insert the a = 0 argument when I wanted to construct a term of type a ≠ 0.

@eric-wieser
Copy link
Member

I still have not figured out how to make it work for the proof construction part

I pushed a change to do this

Copy link
Collaborator

@YaelDillies YaelDillies left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Analytic number theory really needs those extensions back.

maintainer merge

@YaelDillies YaelDillies added the t-meta Tactics, attributes or user commands label Sep 25, 2023
@github-actions
Copy link

🚀 Pull request has been placed on the maintainer queue by YaelDillies.

@YaelDillies YaelDillies changed the title feat: port positivity extensions for Int.floor, Nat.ceil, and Int.ceil feat: Port positivity extensions for Nat.ceil, Int.ceil, Int.floor Sep 25, 2023
@fpvandoorn
Copy link
Member

bors merge

@github-actions github-actions bot added the ready-to-merge This PR has been sent to bors. label Sep 26, 2023
@github-actions github-actions bot removed the awaiting-review The author would like community review of the PR label Sep 26, 2023
bors bot pushed a commit that referenced this pull request Sep 26, 2023
…or` (#7089)

Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
@bors
Copy link

bors bot commented Sep 26, 2023

Pull request successfully merged into master.

Build succeeded!

The publicly hosted instance of bors-ng is deprecated and will go away soon.

If you want to self-host your own instance, instructions are here.
For more help, visit the forum.

If you want to switch to GitHub's built-in merge queue, visit their help page.

@bors bors bot changed the title feat: Port positivity extensions for Nat.ceil, Int.ceil, Int.floor [Merged by Bors] - feat: Port positivity extensions for Nat.ceil, Int.ceil, Int.floor Sep 26, 2023
@bors bors bot closed this Sep 26, 2023
@bors bors bot deleted the positivity-floor branch September 26, 2023 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-to-merge This PR has been sent to bors. t-meta Tactics, attributes or user commands
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants