-
Notifications
You must be signed in to change notification settings - Fork 251
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
Conversation
dwrensha
commented
Sep 10, 2023
Mathlib/Algebra/Order/Floor.lean
Outdated
let (.app (.app (.app (.app _ (α' : Q(Type))) _) _) a) ← whnfR e | ||
| throwError "failed to match on Int.floor application" |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
.)
Mathlib/Algebra/Order/Floor.lean
Outdated
-- 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" |
There was a problem hiding this comment.
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
Mathlib/Algebra/Order/Floor.lean
Outdated
/-- 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 |
There was a problem hiding this comment.
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:
/-- 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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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:
/-- 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
I have not been able to get the /-- 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:
|
I pushed a version that uses |
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
.
I pushed a change to do this |
There was a problem hiding this 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
🚀 Pull request has been placed on the maintainer queue by YaelDillies. |
Nat.ceil
, Int.ceil
, Int.floor
bors merge |
…or` (#7089) Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
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. If you want to switch to GitHub's built-in merge queue, visit their help page. |
Nat.ceil
, Int.ceil
, Int.floor
Nat.ceil
, Int.ceil
, Int.floor