Zulip Chat Archive
Stream: general
Topic: Proving equality of sigma types
Sabrina Jewson (Jan 07 2023 at 22:46):
Hi, so I’m still trying to implement finmap β ≃ Σ (keys : finset α), (Π (key ∈ keys), β key)
, and I’ve made some progress but now I’m completely stuck in heq hell. I need to prove equality of two sigma types to show that pair → map → pair is an identity (my goal is roughly of the form f (g x) = x
where x : sigma β
) — the trouble is that nearly every attempt to break apart that equality to prove it results in heq
because of the nature of the sigma type. My code so far looks like this:
import data.finmap
import data.finset.image
import data.fintype.basic
import data.list.sigma
universes u v
private lemma option.heq_some_iff_get_heq {α : Type*} {β : Type*} {o : option α} {a : β} :
o == some a ↔ ∃ h : o.is_some, option.get h == a :=
begin
sorry
end
private def list.pmap_eq_self {α : Type*} {p : α → Prop}
{f : Π a, p a → α} {l : list α} {prover : ∀ (a ∈ l), p a}
(h : ∀ (x ∈ l), f x (prover x H) = x)
: list.pmap f l prover = l
:= begin
induction l,
refl,
rw list.pmap,
rw h l_hd (or.inl rfl),
rw l_ih (λ x H, h x (or.inr H)),
end
private def make_entries {α : Type*} {β : α → Type*} [decidable_eq α]
(keys : finset α) (value : Π (key ∈ keys), β key)
: multiset (sigma β)
:= keys.val.pmap
(λ (elem : α) (elem_mem : elem ∈ keys.val), ⟨elem, value elem elem_mem⟩)
(λ (elem : α), id)
def finmap.equiv_finset_fun {α : Type*} {β : α → Type*} [decidable_eq α] :
finmap β ≃ Σ (keys : finset α), (Π (key ∈ keys), β key)
:= {
to_fun := λ map, {
fst := map.keys,
snd := λ x x_mem, option.get (finmap.lookup_is_some.mpr x_mem),
},
inv_fun := λ pair, {
entries := make_entries pair.1 pair.2,
nodupkeys := @quot.ind _ _
(λ (keys : multiset α),
Π (keys_nodup : keys.nodup) (value : Π (key ∈ keys), β key),
(make_entries ⟨keys, keys_nodup⟩ value).nodupkeys)
(λ (keys : list α) (keys_nodup : keys.nodup) value,
by simp [make_entries, list.nodupkeys, list.keys, list.map_pmap, keys_nodup])
pair.1.val
pair.1.nodup
pair.2,
},
-- map → pair → map is an identity (not a pretty proof but I’ll come back to this later)
left_inv := λ map, begin
cases map,
dsimp only [finmap.keys],
apply finmap.ext,
dsimp only,
rw make_entries,
dsimp only,
simp only [multiset.keys],
induction map_entries,
simp,
rw [list.pmap_map],
convert ← list.perm.refl _,
apply list.pmap_eq_self,
intros x x_mem,
cases x,
simp,
dsimp at map_nodupkeys,
apply (@exists_prop_of_true _ (λ h, option.get h = x_snd) _).mp,
apply option.eq_some_iff_get_eq.mp,
dsimp only,
apply @finmap.induction_on _ _
(λ f, sigma.mk x_fst x_snd ∈ f.entries → finmap.lookup x_fst f = some x_snd) _
(λ _, alist.mem_lookup_iff.mpr),
exact x_mem,
refl,
end,
-- pair → map → pair is an identity
right_inv := λ pair, begin
cases pair with keys val,
cases keys,
induction keys_val,
-- STRATEGY 1: Don’t break the sigma
dsimp only,
dsimp only [make_entries],
dsimp only [multiset.quot_mk_to_coe''],
dsimp only [multiset.coe_pmap],
dsimp only [finmap.keys],
dsimp only [multiset.coe_keys],
dsimp only [list.keys],
have h :
list.map sigma.fst (list.pmap (λ (elem : α) (elem_mem : elem ∈ ↑keys_val), ⟨ elem, val elem elem_mem ⟩) keys_val _)
= list.pmap (λ (elem : α) (elem_mem : elem ∈ ↑keys_val), sigma.fst ⟨ elem, val elem elem_mem ⟩) keys_val _,
{ apply list.map_pmap },
dsimp only [h],
-- ^ errors, for some reason; `rw` and `simp` also fail, hence all the dsimps
-- STRATEGY 2: Break the sigma
fapply sigma.eq,
simp [finmap.keys, make_entries, multiset.keys, list.map_pmap, list.map_id''],
-- What now? How do I prove a goal of the form `_.rec_on (…) = …`?
-- STRATEGY 3: Embrace the heq
simp,
constructor,
{ simp [finmap.keys, make_entries, multiset.keys, list.map_pmap, list.map_id''], },
dsimp only,
apply function.hfunext, refl, intros a b a_heq_b,
have a_eq_b : a = b, from eq_of_heq a_heq_b,
apply function.hfunext,
{ simp [finmap.keys, make_entries, multiset.keys, a_eq_b], },
intros a_mem b_mem a_mem_eq_b_mem,
apply (@exists_prop_of_true _ (λ h, option.get h == val b b_mem) _).mp,
apply option.heq_some_iff_get_heq.mp,
dsimp only [make_entries, multiset.quot_mk_to_coe'', multiset.coe_pmap],
-- What now? I have no ideä how to simplify or prove this goal because it uses `heq`…
end,
}
You can see the three different strategies I’ve tried, but with each one I encountered a dead end somehow. Any ideäs on this?
Yury G. Kudryashov (Jan 07 2023 at 22:59):
Do you mean "equality of 2 elements of a sigma type"? Because equality of types is something different.
Yury G. Kudryashov (Jan 08 2023 at 01:28):
Here is a complete proof with some auxiliary lemmas that should go to other files. The main trick I used was to use a subtype of a product type as an intermediate type. Probably, one can golf the last equivalence using existing equiv.*_congr constructions.
Code
Sabrina Jewson (Jan 08 2023 at 07:46):
Thank you very much! I’ll have to spend a while studying that :D
Yury G. Kudryashov (Jan 08 2023 at 08:09):
It's hard to work with equality of x y : Σ i, α i
unless x.1 = y.1
is a definitional equality. So, it helps to isolate "actual work" from wrapping in convenient types.
Yury G. Kudryashov (Jan 08 2023 at 08:09):
BTW, I don't know which of the equivalences is more useful in practice.
Yaël Dillies (Jan 08 2023 at 08:17):
The trick to work with sigma types is to make x.1 = y.1
an equality of at least one free variable, then subst
it. Then x.2 == y.2
becomes x.2 = y.2
.
Yury G. Kudryashov (Jan 12 2023 at 20:31):
PRd non-sigma version: #18151. I'm not sure that we need the sigma version in mathlib
because the math content is there but it's easier to deal with a subtype of a product than with a sigma type.
Last updated: Dec 20 2023 at 11:08 UTC