Zulip Chat Archive
Stream: new members
Topic: Bundling a decidability instance with a structure/object?
Jake Levinson (Apr 10 2022 at 23:41):
I've been working on something the last few months and running into two problems that might be interrelated. I've tried to distill to a #mwe but haven't succeeded -- sorry, this thread doesn't have a #mwe (but maybe with help I can generate one). Maybe I can get some help anyway.
(1) I have defined various structure
s and Lean sometimes asks for decidability instances. Mostly I have gone the route of "add the requested instance as an assumption [decidable ...]
or [decidable_pred ...]
wherever requested".
The first problem is that this has led to a proliferation of assumptions -- now (towards the later stages of the construction) I think I am up to six running decidability assumptions. Maybe some of these could be deduced from each other, but I've just been blindly adding whatever Lean asks for. They are things pretty similar to the following:
structure myobj :=
(f : ℕ → Prop)
(g : ℕ → ℕ)
variables
[∀ (X : myobj) (n : ℕ), decidable (X.f n)]
[∀ (X : myobj) m, decidable (∀ n, X.f n → X.g n < m)]
[∀ (X : myobj) m, decidable_pred (λ i, X.f i → m < X.g i)]
[∀ (X : myobj) m, decidable_pred (λ i, X.f 0 → m < X.g i)]
-- etc, 2-3 more variations like these
Question 1. Is there a simple "smallest possible" decidability assumption from which to deduce the examples listed above? The parameters are mostly about inequalities involving functions of the form f : ℕ → Prop
and g : ℕ → ℕ
above. Actually technically f : ℕ → ℕ → Prop
and g : ℕ → ℕ → ℕ
.
Question 2. Should I bundle such decidability assumption(s) into myobj
? The thing is, I definitely want two otherwise-equal objects with different decidability instances to still be equal.
Anyway there is a second more serious problem.
(2) The structure
s I'm defining are similar to fin (n : ℕ)
in that they depend on auxiliary parameters.
structure myobj2 (X : myobj) := sorry
structure myobj3 {X : myobj} (Y : myobj2 X) := sorry
I have been (to the best of my ability) intentional about what to bundle and what to leave out, since it's relevant to the construction to have various objects from the same underlying parameters. I tried bundling everything at one point and it seemed to make things much more complicated -- not least because there were no longer shared decidability instances.
Well, I am encountering more and more difficult motive is not type correct
errors.
- Sometimes this is because two parameters are only propositionally-equal (like
3+3
and6
forfin n
, only instead of nats as parameters it'smyobj
ormyobj2
).
I can resolve this mostly by using copy
patterns (https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/dependent.20structures). Though, I also have to re-assume, or else transfer, decidability instances on the copied object. Sometimes this seems to cause a diamond.
- The more serious problem is that even when things are definitionally equal, sometimes I can't seem to rewrite them without getting a
motive is not type correct
error. The main thing will be a definition like
def f x := if (p x) then (f1 x) else (f2 x)
and then later, I will get motive is not type correct
errors when trying to rewrite f x
to whichever of f1 x
or f2 x
it is. Sometimes simp_rw
fixes it but not always.
In some cases I can't even rewrite/unfold f x
to ite (p x) (f1 x) (f2 x)
!
(Or, it might be something to do with recursion -- my actual f
is defined using well-founded recursion...)
I think this is because, in context, there might be other objects that depend on "f x
" that might need to be rewritten simultaneously (e.g. I have X : my_complicated_object (f x)
. Or, it might be something about not being able to rw
on the decidability assumptions?
Question 3. How do I diagnose / understand a motive is not type correct
error? I think this is sometimes about rewriting under binders, and simp_rw
can fix it. But the error messages I get are very complicated and I am not able to even identify where the error is generated.
Patrick Johnson (Apr 11 2022 at 00:18):
You may want to add this to your file:
noncomputable theory
open_locale classical
In another thread, Keving suggested you to remove open_locale classical
and use explicit decidability instances to avoid diamonds. I think it makes sense only if you have a small number of decidability instances and you want your decidability algorithms to be computable. But in your case using convert
instead of exact
in some places is easier than having so many decidability instances flying around.
Kyle Miller (Apr 11 2022 at 00:27):
Given the examples, it looks like [∀ (X : myobj) (n : ℕ), decidable (X.f n)]
and [∀ (X : myobj) m, decidable (∀ n, X.f n → X.g n < m)]
are the only ones you need. Numbers 3 and 4 are consequences of the first one.
Kyle Miller (Apr 11 2022 at 00:32):
Another thing you might do is, rather than have f : ℕ → Prop
, use f : ℕ → bool
, which is a way to bake-in the decidability of the the predicate. It's hard to say whether this is appropriate given just the example though.
For ∀ n, X.f n → X.g n < m
, what does this being true or false represent?
Jake Levinson (Apr 11 2022 at 00:40):
Patrick Johnson said:
You may want to add this to your file:
noncomputable theory open_locale classical
In another thread, Kevin suggested you to remove
open_locale classical
and use explicit decidability instances to avoid diamonds. I think it makes sense only if you have a small number of decidability instances and you want your decidability algorithms to be computable. But in your case usingconvert
instead ofexact
in some places is easier than having so many decidability instances flying around.
It does seem worth trying, yes. I just wasn't sure if the statements I listed actually are decidable already or something -- like I think a < b
for natural numbers might be decidable (?), so maybe something like a < g m
is too?
Jake Levinson (Apr 11 2022 at 00:43):
Kyle Miller said:
Given the examples, it looks like
[∀ (X : myobj) (n : ℕ), decidable (X.f n)]
and[∀ (X : myobj) m, decidable (∀ n, X.f n → X.g n < m)]
are the only ones you need. Numbers 3 and 4 are consequences of the first one.
Hmm. Should Lean be able to fill in 3 and 4 automatically, given the first one? This might well be a place where I blindly copied a request from the infoview (for the more complicated statement 3 or 4), then later on added in statement 1 for something else simpler.
Kyle Miller (Apr 11 2022 at 00:44):
Yes, that is a decidable proposition already given any pair of natural numbers m
and n
.
variables (m n : ℕ)
#check (infer_instance : decidable (m < n)) -- doesn't throw an error
Kyle Miller (Apr 11 2022 at 00:46):
Jake Levinson said:
Should Lean be able to fill in 3 and 4 automatically, given the first one?
Yes, that's what I mean.
variables (p q : Prop) [decidable q]
--variables [decidable p] -- fails if this line is commented out
#check (infer_instance : decidable (p → q))
Jake Levinson (Apr 11 2022 at 00:46):
Kyle Miller said:
Another thing you might do is, rather than have
f : ℕ → Prop
, usef : ℕ → bool
, which is a way to bake-in the decidability of the the predicate. It's hard to say whether this is appropriate given just the example though.
Oh I see. Interesting, I could try it. Separately, maybe I should just make a separate thread about what I'm trying to do. I'd hoped to avoid posting about it until it was done...
For
∀ n, X.f n → X.g n < m
, what does this being true or false represent?
Just something like "X.g
is (or isn't) bounded by m
in the region where X.f
is true".
Last updated: Dec 20 2023 at 11:08 UTC