Zulip Chat Archive
Stream: new members
Topic: Include in proof context the patterns that didn't match?
George Zakhour (Mar 05 2025 at 13:05):
Hey everyone :)
Setup
I have an inductive type (call it T
) with a lot of constructors, let's call them K1
up to Kn
.
I have a proposition (P : T -> Prop
) that I am proving by case analysis on T
without using tactics.
Basically I have something that looks like this:
theorem thm (e: T) : P e :=
match e with
| K1 _ => ...
...
| Kn => ...
Now I happen to know that for a large majority of these constructors, P holds "trivially" (i.e. with not a lot of code) and that the mess is really in the first 3 constructors.
So ideally I would love to write
theorem thm (e: T) : P e :=
match e with
| K1 => ...
| K2 => ...
| K3 => ...
| _ => trivial
Problem
I lose the fact that e = K4 \or e = K5 \or ... \or e = Kn
which is the only way to make progress in my proof. I know I could write
match e with
...
| K4 | K5 | K6 | ... | Kn => all_goals (trivial)
but I would love not having to enumerate all the remaining constructors.
Question
Any way I can get information about which patterns an expression didn't match in my proof context so I can use it?
I appreciate any help!
Aaron Liu (Mar 05 2025 at 13:07):
theorem thm (e: T) : P e := by
cases e with
| K1 => ...
| K2 => ...
| K3 => ...
| _ => trivial
George Zakhour (Mar 05 2025 at 13:10):
But I do not have in my context e = K4 \or e = K5 \or ... \or e = Kn
in the branch with the wildcard. I can't make progress on my proof without this hypothesis.
Aaron Liu (Mar 05 2025 at 13:20):
In the branch with the wildcard, you should be working on the cases K4
, K5
, ..., Kn
simultaneously.
Aaron Liu (Mar 05 2025 at 13:22):
This is the same as
match e with
...
| K4 | K5 | K6 | ... | Kn => all_goals (trivial)
but without needing to enumerate all the remaining constructors.
George Zakhour (Mar 05 2025 at 13:22):
yes I know this, but in the proof context I don't know this.
Maybe i miscommunicated, but the proof term in the last branch isn't exactly the tactic trivial
.
It's a placeholder for some expression in which I need to use the fact that e = K4 \or ... \or e = Kn
if I want to finish the proof.
Aaron Liu (Mar 05 2025 at 13:23):
You will need to provide more details for me to help you more.
George Zakhour (Mar 05 2025 at 13:31):
I appreciate your help, I will try to minimize my case and paste it here and I hope it won't be a wall of text.
IG
is my inductive type with 5 constructors.
I am trying to prove a lemma on two values of IG
. I happen to know that it's symmetric and I really want to avoid duplicating parts of the proof.
I hope you can see that the pattern matches after -- symmetric cases
look obnoxious, and if I can collapse them under a wildcard that'd be ideal.
The problem is that if I do so, I lose the possibilities for g1
and g2
and i cannot use that to say that they violate ord_cond
@[simp]
def constructor_num {α: Type} (g: IG) : Nat := match g with
| IG.Empty => 0
| IG.Add _ _ => 1
| IG.Remove _ _ => 2
| IG.Connect _ _ _ => 3
| IG.Disconnect _ _ _ => 4
theorem symmetric_lemma {α: Type}
(g1 g2: IG)
(ord_cond: constructor_num g1 <= constructor_num g2)
(cond: ⟦g1⟧ = ⟦g2⟧)
: g1 ≃ g2
:= match case: (g1, g2) with
| ⟨IG.Empty, IG.Empty⟩ => sorry
| ⟨IG.Empty, IG.Add a g⟩ => sorry
| ⟨IG.Empty, IG.Remove a g⟩ => sorry
| ⟨IG.Empty, IG.Connect a b g⟩ => sorry
| ⟨IG.Empty, IG.Disconnect a b g⟩ => sorry
| ⟨IG.Add a g1, IG.Add b g2⟩ => sorry
| ⟨IG.Add a g1, IG.Remove b g2⟩ => sorry
| ⟨IG.Add a g1, IG.Connect b c g2⟩ => sorry
| ⟨IG.Add a g1, IG.Disconnect b c g2⟩ => sorry
| ⟨IG.Remove a g1, IG.Remove b g2⟩ => sorry
| ⟨IG.Remove a g1, IG.Connect b c g2⟩ => sorry
| ⟨IG.Remove a g1, IG.Disconnect b c g2⟩ => sorry
| ⟨IG.Connect a b g1, IG.Connect c d g2⟩ => sorry
| ⟨IG.Connect a b g1, IG.Disconnect c d g2⟩ => sorry
| ⟨IG.Disconnect a b g1, IG.Disconnect c d g2⟩ => sorry
-- symmetric cases
| ⟨IG.Add _ _, IG.Empty⟩ | ⟨IG.Remove _ _, IG.Empty⟩ | ⟨IG.Remove _ _, IG.Add _ _⟩
| ⟨IG.Connect _ _ _, IG.Empty⟩ | ⟨IG.Connect _ _ _, IG.Add _ _⟩ | ⟨IG.Connect _ _ _, IG.Remove _ _⟩
| ⟨IG.Disconnect _ _ _, IG.Connect _ _ _⟩
| ⟨IG.Disconnect _ _ _, IG.Remove _ _⟩ | ⟨IG.Disconnect _ _ _, IG.Add _ _⟩
| ⟨IG.Disconnect _ _ _, IG.Empty⟩ => by all_goals (simp at case; simp [case] at ord_cond)
theorem lemma
: ∀ (g1 g2: IG), ⟦g1⟧ = ⟦g2⟧ → g1 ≃ g2
:= by
intros g1 g2 cond
by_cases ord_cond: constructor_num g1 < constructor_num g2
. exact lemma_equiv_rules_complete g1 g2 (Nat.le_of_lt ord_cond) cond
. exact Equiv.Symm $ symmetric_lemma g2 g1 (Nat.le_of_not_lt ord_cond) (by simp [cond])
I hope that helps in clarifying my need
Aaron Liu (Mar 05 2025 at 13:56):
You can do cases
on g1
, and then do cases
on g2
Last updated: May 02 2025 at 03:31 UTC