Zulip Chat Archive
Stream: new members
Topic: How to use choice tactic?
Li Yao'an (Nov 20 2019 at 03:20):
When we have an existential statement, we can use choice to construct a witness w. However, while w retains the correct type, the fact that it is a witness to a particular proposition is sometimes (seemingly) lost. Here is an example:
import tactic open function noncomputable theory def inv {α β} (f : α → β) (h : surjective f) : β → α := begin intro b, rw [surjective] at h, choose a h using h b, exact a end theorem should_be_trivial {α β} (f : α → β) (h : surjective f) : let f' := inv f h in ∀ b : β, f (f' b) = b := begin simp, intro b, rw inv, admit end
Rewriting inv gives some scary-looking term, and simp-ing gives "f (classical.some _) = b", when it seems that the proposition that choice was made on has been lost.
What is a good way of recovering the proposition in an existential statement? How could this proof be fixed? (A proof ending with "assumption" would be extra nice, to show how the proposition can be added as a hypothesis)
Bryan Gin-ge Chen (Nov 20 2019 at 04:53):
The key is classical.some_spec
:
import tactic open function noncomputable theory def inv {α β} (f : α → β) (h : surjective f) : β → α := begin intro b, rw [surjective] at h, choose a h using h b, exact a end theorem should_be_trivial {α β} (f : α → β) (h : surjective f) : let f' := inv f h in ∀ b : β, f (f' b) = b := begin intros f' b, exact classical.some_spec (h b), end -- n.b. using tactics in defs is discouraged (because it leads to scary-looking terms) def inv' {α β} (f : α → β) (h : surjective f) : β → α := λ b, classical.some (h b)
Bryan Gin-ge Chen (Nov 20 2019 at 05:22):
foo_spec
seems to be the conventional name for the theorem that provides the defining property of foo
, e.g. nat.find_greatest_spec
(for nat.find_greatest
), finset.choose_spec
(for finset.choose
), etc.
Li Yao'an (Nov 20 2019 at 08:20):
Thanks for the reply, but I am still confused. I believe this is at least in part due to the "classical.some _" terms which appear.
It seems to me that after unfolding the definition, the witnesses appear in the interactive tactic window as classical.some _, which does not tell us what the value is a witness for (although Lean seems to know of this). For example:
theorem contrived_example {α β} (f : α → β) (h : surjective f) (a1 a2 : α) (b1 b2 : β) (h2 : a1 = inv' f h b1) (h3 : a2 = inv' f h b2) (h4 : b1 = b2): a1 = a2 := begin rw [h2, h3], dunfold inv', -- At this point the goal is to show "classical.some _ = classical.some _", refl fails simp [h4] -- something happens behind the scenes and it's probably eventually resolved by refl end
Is there a way to elaborate this "classical.some _"?
Additionally, would it be possible to have an interactive tactic to extract the propositions from the values resulting from the application of classical.some? For example, if we had "p : nat -> Prop" and "h : \exists n, p n", then we could replace instances of "classical.some h" with x and add an additional hypothesis "p x".
Mario Carneiro (Nov 20 2019 at 08:24):
it's a printing setting. Try setting set_option pp.proofs true
Kevin Buzzard (Nov 20 2019 at 08:32):
I thought the whole point of choose
was so that the user didn't have to know about classical.some_spec
?
Kevin Buzzard (Nov 20 2019 at 08:35):
Aah I see. So in the def
you get the proof you need, but then the def finishes and the proof is lost. I guess you shouldn't be using tactic mode for the definition of the inverse function really. If you define it using choose
in should_be_trivial
you'll be OK. I guess an alternative is to define inv
not just to return a function but to return a pair consisting of a function and the proof that it's an inverse.
Kevin Buzzard (Nov 20 2019 at 08:43):
import tactic.linarith open function noncomputable def inv' {α β} (f : α → β) (h : surjective f) : { f' : β → α // ∀ b : β, f (f' b) = b} := begin rw [surjective] at h, choose f' hh using h, exact ⟨f', hh⟩, end
Mario Carneiro (Nov 20 2019 at 08:56):
The recommended way to define functions using choice is to write down the property defining the function and prove it straight away with some
and some_spec
:
def inv {α β} (f : α → β) (h : surjective f) : β → α := λ b, classical.some (h b) theorem should_be_trivial {α β} (f : α → β) (h : surjective f) : let f' := inv f h in ∀ b : β, f (f' b) = b := λ b, classical.some_spec (h b)
Mario Carneiro (Nov 20 2019 at 08:56):
The choose
tactic is only appropriate if you only need the function local to a proof
Li Yao'an (Nov 20 2019 at 09:04):
Thanks everybody who replied. Here is my takeaway from this thread (hopefully useful to any future lost souls):
1) When using choice to extract witnesses, "set_option pp.proofs true" elaborates the tactics state so that it makes sense.
2) We can use classical.some_spec to extract the hypothesis of the witness.
Example:
theorem should_be_trivial {α β} (f : α → β) (h : surjective f) : let f' := inv' f h in ∀ b : β, f (f' b) = b := begin intros f' b, simp [f'], dunfold inv', have := classical.some_spec (h b), -- the argument of some_spec is precisely that of classical.some in the tactic state assumption end
Mario Carneiro (Nov 20 2019 at 09:13):
1) Lean doesn't print holes in terms as _
, it prints them as ?m_1
. If you see a _
it's a proof that has been suppressed from printing but is present internally
Mario Carneiro (Nov 20 2019 at 09:14):
so it's not about "elaborating the tactic state", it's about showing more information (hence the pp
for pretty printer)
Last updated: Dec 20 2023 at 11:08 UTC