Zulip Chat Archive
Stream: new members
Topic: match with toLex
Eric Paul (Jun 22 2024 at 00:23):
I would like the following to work but it does not. Any recommendations?
import Mathlib
variable (α : Type*) (β : Type*)
theorem lex_match_fail :
∀a : α,
match ((Sum.inlₗ a) : α ⊕ₗ β) with
| Sum.inlₗ a => True
| Sum.inrₗ b => True := by
simp
Bjørn Kjos-Hanssen (Jun 22 2024 at 06:03):
You can do this:
import Mathlib
variable (α : Type*) (β : Type*)
theorem lex_match_fail :
∀a : α,
match ((Sum.inlₗ a) : α ⊕ₗ β) with
| Sum.inlₗ a => True
| Sum.inrₗ b => True := by exact fun a => trivial
Eric Paul (Jun 22 2024 at 06:37):
I see, thank you. That is useful but I'm confused as to why it works and I'd really like to be able to simplify the match expression as that would make more complicated situations easier.
To be more specific, this is what I'm trying to prove. What you suggested helped me prove the left_inv
and right_inv
but now I'm struggling with map_rel_iff'
. It really seems like I should be able to simplify the match
.
import Mathlib
variable (α : Type*) (β : Type*) (γ : Type*)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
def distribute : ((α ⊕ₗ β) ×ₗ γ ≃o (α ×ₗ γ) ⊕ₗ (β ×ₗ γ)) where
toFun x :=
match x.fst with
| Sum.inlₗ a => Sum.inlₗ (toLex (a, x.snd))
| Sum.inrₗ b => Sum.inrₗ (toLex (b, x.snd))
invFun x :=
match x with
| Sum.inlₗ a => toLex (Sum.inlₗ a.fst, a.snd)
| Sum.inrₗ b => toLex (Sum.inrₗ b.fst, b.snd)
left_inv := by
simp [Function.LeftInverse]
constructor <;> intros a b <;> trivial
right_inv := by
simp [Function.RightInverse, Function.LeftInverse]
constructor <;> intros a b <;> trivial
map_rel_iff' := by
simp
constructor <;> intros a b
<;> constructor <;> intros c d <;> trivial
Eric Paul (Jun 22 2024 at 07:06):
I was able to prove it as follows, but I had to use change
in order to simplify the match
. My hope is to be able to reason with toLex
without needing to use change
.
import Mathlib
variable (α : Type*) (β : Type*) (γ : Type*)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
def distribute : ((α ⊕ₗ β) ×ₗ γ ≃o (α ×ₗ γ) ⊕ₗ (β ×ₗ γ)) where
toFun x :=
match x.fst with
| Sum.inlₗ a => Sum.inlₗ (toLex (a, x.snd))
| Sum.inrₗ b => Sum.inrₗ (toLex (b, x.snd))
invFun x :=
match x with
| Sum.inlₗ a => toLex (Sum.inlₗ a.fst, a.snd)
| Sum.inrₗ b => toLex (Sum.inrₗ b.fst, b.snd)
left_inv := by
simp [Function.LeftInverse]
constructor <;> intros a b <;> trivial
right_inv := by
simp [Function.RightInverse, Function.LeftInverse]
constructor <;> intros a b <;> trivial
map_rel_iff' := by
simp; constructor <;> intros a b
<;> constructor <;> intros c d
· change (Sum.inlₗ (toLex (a, b))) ≤ (Sum.inlₗ (toLex (c, d))) ↔ _; simp [Prod.Lex.le_iff]
· change (Sum.inlₗ (toLex (a, b))) ≤ (Sum.inrₗ (toLex (c, d))) ↔ _; simp [Prod.Lex.le_iff]
· change (Sum.inrₗ (toLex (a, b))) ≤ (Sum.inlₗ (toLex (c, d))) ↔ _; simp [Prod.Lex.le_iff]
· change (Sum.inrₗ (toLex (a, b))) ≤ (Sum.inrₗ (toLex (c, d))) ↔ _; simp [Prod.Lex.le_iff]
Eric Paul (Jun 22 2024 at 07:54):
Or at least I'd like to hide the change
away and have simp
work. Something like the following, but the following doesn't work
import Mathlib
variable (α : Type*) (β : Type*) (γ : Type*)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
@[simp]
theorem lex_match_left
{motive : α ⊕ₗ β → Sort w}
(a : α)
(left : (val : α) → motive (Sum.inlₗ val))
(right : (val : β) → motive (Sum.inrₗ val)) :
(match (Sum.inlₗ a : α ⊕ₗ β) with
| Sum.inlₗ c => left c
| Sum.inrₗ d => right d) = left a := by
change left a = left a
trivial
Eric Paul (Jun 23 2024 at 10:36):
Adding these simps let me hide all the change
and make map_rel_iff'
just a simp
but now I'm not sure why right_inv
and left_inv
are not just simp
as well.
import Mathlib
variable (α : Type*) (β : Type*) (γ : Type*)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
@[simp]
theorem lex_fst (a : α) (b : β) : (toLex (a, b)).1 = a := rfl
@[simp]
theorem lex_snd (a : α) (b : β) : (toLex (a, b)).2 = b := rfl
@[simp]
theorem lex_match_left
{motive : α ⊕ₗ β → Sort w}
(a : α)
(left : (val : α) → motive (Sum.inlₗ val))
(right : (val : β) → motive (Sum.inrₗ val)) :
(match (Sum.inlₗ a : α ⊕ₗ β) with
| Sum.inlₗ c => left c
| Sum.inrₗ d => right d) = left a := by
change left a = left a
trivial
@[simp]
theorem lex_match_right
{motive : α ⊕ₗ β → Sort w}
(b : β)
(left : (val : α) → motive (Sum.inlₗ val))
(right : (val : β) → motive (Sum.inrₗ val)) :
(match (Sum.inrₗ b : α ⊕ₗ β) with
| Sum.inlₗ c => left c
| Sum.inrₗ d => right d) = right b := by
change right b = right b
trivial
def distribute : ((α ⊕ₗ β) ×ₗ γ ≃o (α ×ₗ γ) ⊕ₗ (β ×ₗ γ)) where
toFun x :=
match x.fst with
| Sum.inlₗ a => Sum.inlₗ (toLex (a, x.snd))
| Sum.inrₗ b => Sum.inrₗ (toLex (b, x.snd))
invFun x :=
match x with
| Sum.inlₗ a => toLex (Sum.inlₗ a.fst, a.snd)
| Sum.inrₗ b => toLex (Sum.inrₗ b.fst, b.snd)
left_inv := by
simp [Function.LeftInverse]
constructor <;> intros a b <;> trivial
right_inv := by
simp [Function.RightInverse, Function.LeftInverse]
constructor <;> intros a b <;> trivial
map_rel_iff' := by
simp [Prod.Lex.le_iff]
Eric Paul (Jun 23 2024 at 21:03):
Here's a smaller mwe that shows the issue I'm struggling with.
Notice how test0
works but test1
does not. I'm not sure why there is a difference.
import Mathlib
variable (α : Type*) (β : Type*) (γ : Type*)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
@[simp]
theorem lex_match_left
{motive : α ⊕ₗ β → Sort w}
(a : α)
(left : (val : α) → motive (Sum.inlₗ val))
(right : (val : β) → motive (Sum.inrₗ val)) :
(match (Sum.inlₗ a : α ⊕ₗ β) with
| Sum.inlₗ c => left c
| Sum.inrₗ d => right d) = left a := by
change left a = left a
trivial
theorem test0 (a : α) :
(match (Sum.inlₗ a : α ⊕ₗ β) with
| Sum.inlₗ b => 2
| Sum.inrₗ c => 3) = 2 := by
simp
theorem test1 (a : α) (g : γ) :
(match (Sum.inlₗ (toLex (a, g)) : (α ×ₗ γ) ⊕ₗ β) with
| Sum.inlₗ b => 2
| Sum.inrₗ c => 3) = 2 := by
simp
Eric Paul (Jun 24 2024 at 23:07):
Interestingly, if I use the theorem manually with rewrite to replace all 2
s with the whole match
expression, then simp
is able to automatically turn those match
s back into 2
s.
So I inspected the types in the introduced match
s from the rw
and the only difference I can find is in the types of numbers. In the 2
and 3
I wrote myself, they have type @OfNat.ofNat ℕ 2 (instOfNatNat 2) : ℕ
but the ones that appear form using the rw
have the type @OfNat.ofNat ((fun x => ℕ) (Sum.inlₗ c)) 2 (instOfNatNat 2) : (fun x => ℕ) (Sum.inlₗ c)
and then after simp
lifying, the new 2
s have type 2 : (fun x => ℕ) (Sum.inlₗ (toLex (a, g)))
.
I thought that maybe this could be the cause of the issue but I still have 2
s and 3
s in the example where simp
does work. So I can't figure out the difference between the match
s that simp
is simplifying and the ones it isn't.
import Mathlib
universe u x w
variable (α : Type u) (β : Type x) (γ : Type w)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
@[simp]
theorem lex_match_left
(motive : α ⊕ₗ β → Sort w)
(a : α)
(left : (val : α) → motive (Sum.inlₗ val))
(right : (val : β) → motive (Sum.inrₗ val)) :
(match (Sum.inlₗ a : α ⊕ₗ β) with
| Sum.inlₗ c => left c
| Sum.inrₗ d => right d) = left a := by
change left a = left a
trivial
theorem test1 (a : α) (g : γ) :
(match (Sum.inlₗ (toLex (a, g)) : (α ×ₗ γ) ⊕ₗ β) with
| Sum.inl b => 2
| Sum.inr c => 3) = 2 := by
rw [←lex_match_left (motive := fun _ => Nat) (α := (α ×ₗ γ)) (β := β) (toLex (a,g) : (α ×ₗ γ)) (fun _ => 2) (fun _ => 3)]
simp
Eric Paul (Jun 25 2024 at 20:19):
I guess I have reduced the question to the following MWE:
Why does this rw
not work?
import Mathlib
universe u x w z
variable (α : Type u) (β : Type x) (γ : Type w)
[LinearOrder α] [LinearOrder β] [LinearOrder γ]
theorem lex_match_left
{α : Type u} {β : Type x}
{motive : α ⊕ₗ β → Sort z}
(a : α)
(left : (val : α) → motive (Sum.inlₗ val))
(right : (val : β) → motive (Sum.inrₗ val)) :
(match (Sum.inlₗ a : α ⊕ₗ β) with
| Sum.inlₗ c => left c
| Sum.inrₗ d => right d) = left a := by
change left a = left a
trivial
theorem test1 (a : α) (g : γ) :
(match (Sum.inlₗ (toLex (a, g)) : (α ×ₗ γ) ⊕ₗ β) with
| Sum.inl c => 2
| Sum.inr d => 3) = 2 := by
rw [lex_match_left (motive := fun _ => ℕ) (toLex (a,g)) (fun _ => (2 : ℕ)) (fun _ => (3 : ℕ))]
Kevin Buzzard (Jun 27 2024 at 07:41):
I don't know the answer to your question, but note that rfl
closes the goal.
Eric Wieser (Jun 27 2024 at 07:45):
I think this is a general problem with match
and type synonyms, where match
unfolds the synonym matchers (such as Sum.inlₗ
) in the generated term
Eric Wieser (Jun 27 2024 at 07:47):
There are at least two problems here:
- The generated
lex_match_left.match_1
is about the wrong type - The first lemma is about
lex_match_left.match_1
, the second one is abouttest1.match_1
Eric Paul (Jul 01 2024 at 01:38):
Eric Wieser said:
There are at least two problems here:
- The generated
lex_match_left.match_1
is about the wrong type- The first lemma is about
lex_match_left.match_1
, the second one is abouttest1.match_1
I don't think I understand. I looked at the type of lex_match_left.match_1
and looks like what I expected to be:
lex_match_left.match_1.{u_1, u_2, u_3} {α : Type u_2} {β : Type u_1} (motive : Lex (α ⊕ β) → Sort u_3) :
(x : Lex (α ⊕ β)) → ((c : α) → motive (Sum.inl c)) → ((d : β) → motive (Sum.inr d)) → motive x
What are the lemmas you're talking about?
I appreciate you having taken a look at this. I hadn't heard of the match_1
s before. Is there some documentation about it?
Eric Wieser (Jul 01 2024 at 07:42):
Eric Paul said:
Eric Wieser said:
There are at least two problems here:
- The generated
lex_match_left.match_1
is about the wrong type- The first lemma is about
lex_match_left.match_1
, the second one is abouttest1.match_1
I don't think I understand. I looked at the type of
lex_match_left.match_1
and looks like what I expected to be:lex_match_left.match_1.{u_1, u_2, u_3} {α : Type u_2} {β : Type u_1} (motive : Lex (α ⊕ β) → Sort u_3) : (x : Lex (α ⊕ β)) → ((c : α) → motive (Sum.inl c)) → ((d : β) → motive (Sum.inr d)) → motive x
That's not type correct though, that inl
should be the lex version
Eric Paul (Jul 12 2024 at 17:21):
Eric Wieser said:
That's not type correct though, that
inl
should be the lex version
Ah I see, I missed that. That makes sense.
Do you have a recommendation for how to fix this?
Could I somehow write what the match_1
s should be?
Is a fix to how match
works something reasonable that I could pursure?
Eric Wieser (Jul 12 2024 at 17:49):
I think the first step would be to file a mathlib-free bug report against Lean itself
Last updated: May 02 2025 at 03:31 UTC