Zulip Chat Archive
Stream: new members
Topic: rw only simplifies if piped through my own function
Tobias Grosser (Sep 07 2018 at 05:52):
My first beginners question. I tampered with this since a while, but maybe somebody has a quick explanation for this:
https://gist.github.com/tobig/92b17c8cac76fd07e1537c9131a25260
Tobias Grosser (Sep 07 2018 at 05:53):
Rewriting with my own theorem works well, but if I directly use imp_iff_not_or things break
Tobias Grosser (Sep 07 2018 at 05:53):
with "function expected at"
Tobias Grosser (Sep 07 2018 at 05:54):
Probably a beginners mistake. It seems my declaration introduces some additional information which help the proof go through.
Simon Hudon (Sep 07 2018 at 05:56):
If you check the definition of imp_iff_not_or
, (type #check imp_iff_not_or
in your Lean buffer), you see that it does not take explicit arguments, only implicit ones
Simon Hudon (Sep 07 2018 at 05:57):
That means that they are meant to be inferred. But if you want to specify then, you can write @imp_iff_not_or
and then you have to provide an argument for the implicit and explicit arguments.
Simon Hudon (Sep 07 2018 at 05:59):
For reference:
#check imp_iff_not_or -- imp_iff_not_or : ?M_1 → ?M_2 ↔ ¬?M_1 ∨ ?M_2 #check @imp_iff_not_or -- imp_iff_not_or : ∀ {a b : Prop} [_inst_1 : decidable a], a → b ↔ ¬a ∨ b
The curly brackets around a
and b
means that they are implicit arguments. The square brackets around decidable a
means that it's a type class instance.
Tobias Grosser (Sep 07 2018 at 06:01):
https://leanprover.github.io/theorem_proving_in_lean/dependent_type_theory.html#implicit-arguments
Tobias Grosser (Sep 07 2018 at 06:02):
Works flawless. Need to read a little bit more on this.
Tobias Grosser (Sep 07 2018 at 06:02):
Thanks for the quick help.
Simon Hudon (Sep 07 2018 at 06:02):
No worries :)
Tobias Grosser (Sep 07 2018 at 06:05):
One last question:
Tobias Grosser (Sep 07 2018 at 06:05):
My proof looks now like this:
Tobias Grosser (Sep 07 2018 at 06:05):
((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = ((B → C) → (¬(¬A ∨ C) ∧ ¬(A ∨ B))) : by rw @imp_iff_not_or A C ... = ((B → C) → ((¬(¬A) ∧ ¬C) ∧ ¬(A ∨ B))) : by rw not_or_distrib ... = ((B → C) → ((¬(¬A) ∧ ¬C) ∧ (¬A ∧ ¬B))) : by rw not_or_distrib ... = ((B → C) → ((A ∧ ¬C) ∧ (¬A ∧ ¬B))) : by rw not_not ... = ((B → C) → ((A ∧ ¬C) ∧ ¬A ∧ ¬B)) : by rw and_assoc ... = ((B → C) → ((¬C ∧ A) ∧ ¬A ∧ ¬B)) : by rw and_comm (A) (¬C) ... = ((B → C) → (¬C ∧ A ∧ ¬A ∧ ¬B)) : by rw and_assoc ... = ((B → C) → (¬C ∧ (A ∧ ¬A) ∧ ¬B)) : by rw and_assoc ... = ((B → C) → (¬C ∧ ¬ B ∧ (A ∧ ¬A))) : by rw and_comm (¬ B) (A ∧ ¬A) ... = ((B → C) → (¬C ∧ ¬ B ∧ false )) : by rw and_not_self_iff A ... = ((B → C) → ((¬C) ∧ false )) : by rw and_false ... = ((B → C) → (false)) : by rw and_false ... = (¬(B → C) ∨ false) : by rw imp_iff_not_or ... = ¬(B → C) : by rw or_false ... = ¬(¬B ∨ C) : by rw imp_iff_not_or ... = ((¬¬B) ∧ (¬C)) : by rw not_or_distrib ... = (B ∧ ¬C) : by rw not_not
Tobias Grosser (Sep 07 2018 at 06:06):
It seems only imp_iff_not_or needs the '@'. All other functions are OK with explicit arguments (if given).
Tobias Grosser (Sep 07 2018 at 06:06):
Is there some schema when theorems take explicit arguments in mathlib?
Mario Carneiro (Sep 07 2018 at 06:07):
most iff theorems have implicit args
Kenny Lau (Sep 07 2018 at 06:07):
rw ← imp_iff_not_or
Kenny Lau (Sep 07 2018 at 06:07):
import logic.basic local attribute [instance] classical.prop_decidable example {A B C : Prop} : _ = _ := calc ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = ((B → C) → (¬(¬A ∨ C) ∧ ¬(A ∨ B))) : by rw ← imp_iff_not_or ... = ((B → C) → ((¬(¬A) ∧ ¬C) ∧ ¬(A ∨ B))) : by rw not_or_distrib ... = ((B → C) → ((¬(¬A) ∧ ¬C) ∧ (¬A ∧ ¬B))) : by rw not_or_distrib ... = ((B → C) → ((A ∧ ¬C) ∧ (¬A ∧ ¬B))) : by rw not_not ... = ((B → C) → ((A ∧ ¬C) ∧ ¬A ∧ ¬B)) : by rw and_assoc ... = ((B → C) → ((¬C ∧ A) ∧ ¬A ∧ ¬B)) : by rw and_comm (A) (¬C) ... = ((B → C) → (¬C ∧ A ∧ ¬A ∧ ¬B)) : by rw and_assoc ... = ((B → C) → (¬C ∧ (A ∧ ¬A) ∧ ¬B)) : by rw and_assoc ... = ((B → C) → (¬C ∧ ¬ B ∧ (A ∧ ¬A))) : by rw and_comm (¬ B) (A ∧ ¬A) ... = ((B → C) → (¬C ∧ ¬ B ∧ false )) : by rw and_not_self_iff A ... = ((B → C) → ((¬C) ∧ false )) : by rw and_false ... = ((B → C) → (false)) : by rw and_false ... = (¬(B → C) ∨ false) : by rw imp_iff_not_or ... = ¬(B → C) : by rw or_false ... = ¬(¬B ∨ C) : by rw imp_iff_not_or ... = ((¬¬B) ∧ (¬C)) : by rw not_or_distrib ... = (B ∧ ¬C) : by rw not_not
Tobias Grosser (Sep 07 2018 at 06:12):
Is there a specific reason why 'iff' terms have implict arguments and others not?
Kenny Lau (Sep 07 2018 at 06:14):
import logic.basic local attribute [instance] classical.prop_decidable example {A B C : Prop} : _ = _ := calc ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = ((B → C) → ((A ∧ ¬C) ∧ ¬(A ∨ B))) : by rw not_imp ... = ((B → C) → ((A ∧ ¬C) ∧ ¬A ∧ ¬B)) : by rw not_or_distrib ... = ((B → C) → ((¬C ∧ A) ∧ ¬A ∧ ¬B)) : by rw and_comm (A) (¬C) ... = ((B → C) → (¬C ∧ A ∧ ¬A ∧ ¬B)) : by rw and_assoc ... = ((B → C) → (¬C ∧ (A ∧ ¬A) ∧ ¬B)) : by rw and_assoc ... = ((B → C) → (¬C ∧ ¬ B ∧ (A ∧ ¬A))) : by rw and_comm (¬ B) (A ∧ ¬A) ... = ((B → C) → (¬C ∧ ¬ B ∧ false )) : by rw and_not_self_iff A ... = ((B → C) → ((¬C) ∧ false )) : by rw and_false ... = ((B → C) → (false)) : by rw and_false ... = ¬(B → C) : rfl ... = (B ∧ ¬C) : by rw not_imp
Tobias Grosser (Sep 07 2018 at 06:16):
Nice
Tobias Grosser (Sep 07 2018 at 06:16):
Really helpful.
Tobias Grosser (Sep 07 2018 at 06:17):
Thank you!
Kenny Lau (Sep 07 2018 at 06:18):
import logic.basic local attribute [instance] classical.prop_decidable example {A B C : Prop} : _ = _ := calc ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = ((B → C) → ((A ∧ ¬C) ∧ ¬(A ∨ B))) : by rw not_imp ... = ((B → C) → ((A ∧ ¬C) ∧ ¬A ∧ ¬B)) : by rw not_or_distrib ... = ((B → C) → ((A ∧ ¬A ∧ ¬B) ∧ ¬C)) : by rw and.right_comm ... = ((B → C) → (((A ∧ ¬A) ∧ ¬B) ∧ ¬C)) : by rw ← and_assoc ... = ((B → C) → ((false ∧ ¬B) ∧ ¬C)) : by rw and_not_self_iff A ... = ((B → C) → (false ∧ ¬C)) : by rw false_and ... = ((B → C) → (false)) : by rw false_and ... = ¬(B → C) : rfl ... = (B ∧ ¬C) : by rw not_imp
Simon Hudon (Sep 07 2018 at 06:21):
I'm a bit vague on the rule for iff
and other rewrite rules but in general, if an argument can be inferred from other arguments, it should be implicit. For rewrite rules, I think all the arguments that can be inferred from the lhs of the equation should be implicit.
Tobias Grosser (Sep 07 2018 at 06:23):
I see. Thanks @Simon Hudon
Mario Carneiro (Sep 07 2018 at 06:28):
example {A B C : Prop} : ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = (B ∧ ¬C) := by apply classical.cases_on A; apply classical.cases_on B; apply classical.cases_on C; simp
The idea behind the rule for iff is that these are more often used as combined unidirectional rules, and in this case any argument present on both lhs and rhs are inferrable
Simon Hudon (Sep 07 2018 at 06:29):
Have you tried tauto
?
Mario Carneiro (Sep 07 2018 at 06:29):
doesn't seem to do anything
Mario Carneiro (Sep 07 2018 at 06:30):
propext $ by tauto
works though
Simon Hudon (Sep 07 2018 at 06:30):
Right! You need the propositions to be decidable
Kenny Lau (Sep 07 2018 at 06:30):
example {A B C : Prop} : ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = (B ∧ ¬C) :=
by apply classical.cases_on A;
apply classical.cases_on B;
apply classical.cases_on C; simp
that's the proof of completeness!
Simon Hudon (Sep 07 2018 at 06:30):
propext $ by tauto
works though
Interesting! That should be worth adding to the tactic
Mario Carneiro (Sep 07 2018 at 06:31):
mathlib tries to avoid equality of propositions though
Mario Carneiro (Sep 07 2018 at 06:31):
it's always stated as an iff
Kenny Lau (Sep 07 2018 at 06:31):
example {A B C : Prop} : ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = (B ∧ ¬C) := by by_cases A; by_cases B; by_cases C; simp*
Mario Carneiro (Sep 07 2018 at 06:32):
oh, of course - simp
will rewrite A
to true
or false
given the by_cases
assumption
Tobias Grosser (Sep 07 2018 at 06:42):
Nice. I am currently translating some student exercises, so I try to use the 'calc' mode to really show step-by-step how things evolve.
Tobias Grosser (Sep 07 2018 at 06:42):
This worked quite well so far. Nice to see that the tactics work so well too.
Mario Carneiro (Sep 07 2018 at 06:43):
you should be able to use <->
in those calc blocks
Tobias Grosser (Sep 07 2018 at 06:45):
Yes, I can replace = with <->
Tobias Grosser (Sep 07 2018 at 06:45):
Does this have any benefits?
Mario Carneiro (Sep 07 2018 at 06:47):
only it's more idiomatic; rw
and friends will work either way
Tobias Grosser (Sep 07 2018 at 06:48):
Why exactly is it more idiomatic?
Mario Carneiro (Sep 07 2018 at 06:48):
because it's easier to work with iff since you can destruct it, and you don't need the propext axiom to prove things about it
Simon Hudon (Sep 07 2018 at 06:48):
=
has stronger precedence than <->
and the other connectives so <->
yields formulas with fewer brackets
Tobias Grosser (Sep 07 2018 at 06:50):
Great.
Tobias Grosser (Sep 07 2018 at 06:50):
Need to get back to normal life. Thanks for your help.
Mario Carneiro (Sep 07 2018 at 06:50):
But "idiomatic" really just means that it is used, like a convention - it doesn't need a reason per se, it's valuable because it is the convention
Mario Carneiro (Sep 07 2018 at 06:51):
i.e. it will make it easier to fit with and apply existing theorems
Tobias Grosser (Sep 07 2018 at 06:51):
I understand the meaning of idiomatic.
Tobias Grosser (Sep 07 2018 at 06:51):
Wanted understand the underlying motivation.
Mario Carneiro (Sep 07 2018 at 06:51):
so another answer is "there are two options, we picked one"
Tobias Grosser (Sep 07 2018 at 06:52):
If I want my proofs to be understood in the end, it helps to learn the choices you as a community have taken.
Mario Carneiro (Sep 07 2018 at 06:52):
I think logic textbooks usually use <->
Mario Carneiro (Sep 07 2018 at 06:52):
or sometimes ≡
Tobias Grosser (Sep 07 2018 at 06:52):
I can learn them easier if I can get an intuition where things come from.
Keeley Hoek (Sep 11 2018 at 04:25):
Cool fact: rewrite_search
solves this problem instantly:
local attribute [search] imp_iff_not_or not_or_distrib not_not and_assoc and_comm and_not_self_iff and_false not_not example {A B C : Prop} : ((B → C) → (¬(A → C) ∧ ¬(A ∨ B))) = (B ∧ ¬C) := by rewrite_search_using [`search]
Scott Morrison (Sep 11 2018 at 06:12):
We really need to think about automatic lemma selection for rewrite_search.
Scott Morrison (Sep 11 2018 at 06:12):
Possible just finer attribute tagging (e.g. [search logic], [search list], [search category_theory]).
Scott Morrison (Sep 11 2018 at 06:13):
Perhaps even teach rewrite_search to automatically select from different bundles of lemmas depending on what it sees in the goal.
Keeley Hoek (Sep 11 2018 at 06:25):
At least for me, just printing out every definition in a modest real-ish maths environment takes 30 seconds, so I think some form of bundling will have to be the way to go. Maybe barring some emergency "show me the way" mode.
Keeley Hoek (Sep 11 2018 at 06:26):
Though "find me a lemma" mode could be a useful tactic in its own right I suppose
Keeley Hoek (Sep 11 2018 at 06:30):
I guess that's what I'll try next
Patrick Massot (Sep 11 2018 at 07:27):
We really need to think about automatic lemma selection for rewrite_search.
This is all very nice, but don't forget that this is a whole research area. So don't expect this to be super easy, and maybe have a look at what already exists. I think the keyword is "relevance filter"
Last updated: Dec 20 2023 at 11:08 UTC