-
Notifications
You must be signed in to change notification settings - Fork 447
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
fix: remove special handling of numerals in DiscrTree
#3684
base: master
Are you sure you want to change the base?
Conversation
c07cc9e
to
d980642
Compare
Mathlib CI status (docs):
|
d980642
to
97d88ed
Compare
DiscrTree
Blocked by #3686 which would fix the only remaining failing test. |
Fixes leanprover#2867 by removing special handling of `OfNat.ofNat` numerals from `DiscrTree`. The special handling was added in 2b8e55c to fix a bug represented in the test `tests/lean/run/bugNatLitDiscrTree.lean`, but with leanprover#2916 fixed, that test case passes without the special handling. Some special handling of `Nat.zero` and `Nat.succ` remains.
97d88ed
to
cfc21db
Compare
awaiting-review |
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 believe this PR is ready, although I'm flagging one shortcoming which I hope can be addressed in future work.
|
||
For example, to reach `P (Nat.zero.succ.succ)`, | ||
the first recursive step contains the unification problem `P (Nat.zero.succ.succ) =?= P (?n.succ)`, | ||
which the kernel solves by setting `?n := 1`, *not* `?n := Nat.zero.succ`. |
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.
It just occurred to me to test this for nat_lit 0
, and lo and behold, unification has the same surprising behavior of setting the metavariable to 1
:
set_option pp.natLit true in
#check (show (nat_lit 0).succ.succ = Nat.succ _ from rfl)
-- Nat.succ (Nat.succ (nat_lit 0)) = Nat.succ 1
If we replace Nat.zero
with nat_lit 0
in this test case, we get a new test case which fails after this PR:
class MyClass (n : Nat) : Prop where
instance myClass_succ [MyClass n] : MyClass (n.succ) := ⟨⟩
instance myClass_nat_lit_zero : MyClass (nat_lit 0) := ⟨⟩
example : MyClass (nat_lit 0).succ.succ :=
inferInstance -- failed to synthesize instance
Making this instance path work as expected would require a significantly more complicated fix to the discrtree code (namely, normalize nat_nit n
to OfNat.ofNat (nat_lit n)
, except when already inside OfNat.ofNat
), and the behavior after the current PR is easy to work around (add an instance for 0
instead of or in addition to nat_lit 0
). Would it be acceptable to leave addressing this case as future work?
@leodemoura I would love if you would review this PR when you get the chance. I think you are effectively the code owner for the discrimination tree. |
This seems like a significant usability regression from my perspective. If failing to decorate a term in one spot with a special modifier leads to various tools degrading in their performance or not working well, but doesn't throw an error, then I suspect we'll mostly end up with various tools degrading in their performance. Is there a way to fix this elsewhere? |
You're right. Getting an error message |
Upon further reflection, I am realizing that the following might be a helpful guiding principle for discrimination tree behavior: If Given this specification, let's evaluate the status quo and this PR on three key examples: /-! For each reducible defeq, test that instances for the LHS apply to the RHS -/
class MyClass (n : Nat) : Prop where
def myClass_zero : MyClass 0 where
def myClass_ofNat (n : Nat) : MyClass (OfNat.ofNat n) where
#check show 0 = nat_lit 0 by with_reducible rfl -- OK (reducibly defeq)
attribute [local instance] myClass_zero in
#synth MyClass (nat_lit 0)
-- Status quo: OK (instance applied)
-- This PR: ERROR (instance didn't apply)
#check show OfNat.ofNat _ = 0 by with_reducible rfl -- OK (reducibly defeq)
attribute [local instance] myClass_ofNat in
#synth MyClass 0
-- Status quo: ERROR (instance didn't apply)
-- This PR: OK (instance applied)
#check show OfNat.ofNat _ = nat_lit 0 by with_reducible rfl -- ERROR (not reducibly defeq)
attribute [local instance] myClass_ofNat in
#synth MyClass (nat_lit 0)
-- Status quo: ERROR (instance didn't apply)
-- This PR: ERROR (instance didn't apply) As you can see, the key change with this PR is that the discrimination tree now fails to honor the reducible defeq I've included the third example to highlight that the current behavior of reducible defeq is actually non-transitive: We have I think there are two reasonable approaches to fixing this:
This PR would move the discrimination tree a step towards the former approach of demoting Now that we're discussing it though, I think the latter approach might have some serious benefits. Namely, it would mean that you (almost?) never have to mentally distinguish between What do you think @david-christiansen? |
I don't feel like I have enough context to evaluate the technical trade-offs of the concrete proposals - sorry! But I do know that explaining where and why |
(and thank you for the thorough consideration!) |
Without implying that it is sufficient, a Mathlib adaptation branch would be necessary for progress here. |
We use `no_index` to work around special-handling of `OfNat.ofNat` in `DiscrTree`, which has been reported as an issue in #2867 and is currently in the process of being fixed in #3684. As the potential fix seems non-trivial and might need some time to arrive in-tree, we meanwhile add the `no_index` keyword to the problematic subterm. --------- Co-authored-by: Eric Wieser <[email protected]>
Fixes #2867 by removing special handling of
OfNat.ofNat
numerals fromDiscrTree
.The special handling was added in 2b8e55c to fix a bug represented in the test
tests/lean/run/bugNatLitDiscrTree.lean
, but with #2916 fixed, that test case passes without the special handling.Some special handling of
Nat.zero
andNat.succ
remains to ensure that keys continue to match when unification replaces constants of the formNat.zero...succ.succ
with numerals.One notable implication of the removal of this special handling is that it means that instances of
OfNat MyType n
for specific natural numbersn
should be written asOfNat MyType (nat_lit n)
. See tests/run/rewrites.lean for an example of this modification being needed.Since this PR changes the persisted discrimination tree format, an
update stage0
commit is necessary to make tests pass. (Otherwise oleans produced by the stage0 compiler with old discrimination tree data are used alongside the new discrimination tree algorithm.)