Skip to content

Commit 801069d

Browse files
arienmalecqawbecrdteynomeata
committed
feat: Port Data.Fintype.Perm (#1691)
Port of data.fintype.perm Co-authored-by: qawbecrdtey <qawbecrdtey@naver.com> Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
1 parent 81507de commit 801069d

File tree

2 files changed

+178
-0
lines changed

2 files changed

+178
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ import Mathlib.Data.Fintype.List
347347
import Mathlib.Data.Fintype.Option
348348
import Mathlib.Data.Fintype.Order
349349
import Mathlib.Data.Fintype.Parity
350+
import Mathlib.Data.Fintype.Perm
350351
import Mathlib.Data.Fintype.Pi
351352
import Mathlib.Data.Fintype.Powerset
352353
import Mathlib.Data.Fintype.Prod

Mathlib/Data/Fintype/Perm.lean

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/-
2+
Copyright (c) 2017 Mario Carneiro. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Mario Carneiro
5+
6+
! This file was ported from Lean 3 source module data.fintype.perm
7+
! leanprover-community/mathlib commit 509de852e1de55e1efa8eacfa11df0823f26f226
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.Data.Fintype.Card
12+
import Mathlib.GroupTheory.Perm.Basic
13+
import Mathlib.Tactic.Ring
14+
15+
/-!
16+
# `Fintype` instances for `Equiv` and `Perm`
17+
18+
Main declarations:
19+
* `permsOfFinset s`: The finset of permutations of the finset `s`.
20+
21+
-/
22+
23+
open Function
24+
25+
open Nat
26+
27+
universe u v
28+
29+
variable {α β γ : Type _}
30+
31+
open Finset Function List Equiv Equiv.Perm
32+
33+
variable [DecidableEq α] [DecidableEq β]
34+
35+
/-- Given a list, produce a list of all permutations of its elements. -/
36+
def permsOfList : List α → List (Perm α)
37+
| [] => [1]
38+
| a :: l => permsOfList l ++ l.bind fun b => (permsOfList l).map fun f => Equiv.swap a b * f
39+
#align perms_of_list permsOfList
40+
41+
theorem length_permsOfList : ∀ l : List α, length (permsOfList l) = l.length !
42+
| [] => rfl
43+
| a :: l => by
44+
rw [length_cons, Nat.factorial_succ]
45+
simp only [permsOfList, length_append, length_permsOfList, length_bind, comp,
46+
length_map, map_const', sum_replicate, smul_eq_mul, succ_mul]
47+
ring
48+
#align length_perms_of_list length_permsOfList
49+
50+
theorem mem_permsOfList_of_mem {l : List α} {f : Perm α} (h : ∀ x, f x ≠ x → x ∈ l) :
51+
f ∈ permsOfList l := by
52+
induction l generalizing f
53+
-- with a l IH
54+
case nil =>
55+
-- Porting note: Previous code was:
56+
-- exact List.mem_singleton.2 (Equiv.ext fun x => Decidable.by_contradiction <| h x)
57+
--
58+
-- `h x` does not work as expected.
59+
-- This is because `x ∈ []` is not `False` before `simp`.
60+
exact List.mem_singleton.2 (Equiv.ext fun x => Decidable.by_contradiction <| by
61+
intro h'; simp at h; apply h x; intro h''; apply h'; simp; exact h'')
62+
case cons a l IH =>
63+
by_cases hfa : f a = a
64+
· refine' mem_append_left _ (IH fun x hx => mem_of_ne_of_mem _ (h x hx))
65+
rintro rfl
66+
exact hx hfa
67+
have hfa' : f (f a) ≠ f a := mt (fun h => f.injective h) hfa
68+
have : ∀ x : α, (Equiv.swap a (f a) * f) x ≠ x → x ∈ l := by
69+
intro x hx
70+
have hxa : x ≠ a := by
71+
rintro rfl
72+
apply hx
73+
simp only [mul_apply, swap_apply_right]
74+
refine' List.mem_of_ne_of_mem hxa (h x fun h => _)
75+
simp only [mul_apply, swap_apply_def, mul_apply, Ne.def, apply_eq_iff_eq] at hx
76+
split_ifs at hx with h_1
77+
exacts[hxa (h.symm.trans h_1), hx h]
78+
suffices f ∈ permsOfList l ∨ ∃ b ∈ l, ∃ g ∈ permsOfList l, Equiv.swap a b * g = f by
79+
simpa only [permsOfList, exists_prop, List.mem_map', mem_append, List.mem_bind]
80+
refine' or_iff_not_imp_left.2 fun _hfl => ⟨f a, _, Equiv.swap a (f a) * f, IH this, _⟩
81+
· exact mem_of_ne_of_mem hfa (h _ hfa')
82+
· rw [← mul_assoc, mul_def (swap a (f a)) (swap a (f a)), swap_swap, ← Perm.one_def, one_mul]
83+
#align mem_perms_of_list_of_mem mem_permsOfList_of_mem
84+
85+
theorem mem_of_mem_permsOfList :
86+
-- porting notes: was `∀ {x}` but need to capture the `x`
87+
∀ {l : List α} {f : Perm α}, f ∈ permsOfList l → (x :α ) → f x ≠ x → x ∈ l
88+
| [], f, h, heq_iff_eq => by
89+
have : f = 1 := by simpa [permsOfList] using h
90+
rw [this]; simp
91+
| a :: l, f, h, x =>
92+
(mem_append.1 h).elim (fun h hx => mem_cons_of_mem _ (mem_of_mem_permsOfList h x hx))
93+
fun h hx =>
94+
let ⟨y, hy, hy'⟩ := List.mem_bind.1 h
95+
let ⟨g, hg₁, hg₂⟩ := List.mem_map'.1 hy'
96+
-- Porting note: Seems like the implicit variable `x` of type `α` is needed.
97+
if hxa : x = a then by simp [hxa]
98+
else
99+
if hxy : x = y then mem_cons_of_mem _ <| by rwa [hxy]
100+
else mem_cons_of_mem a <| mem_of_mem_permsOfList hg₁ _ <| by
101+
rw [eq_inv_mul_iff_mul_eq.2 hg₂, mul_apply, swap_inv, swap_apply_def]
102+
split_ifs <;> [exact Ne.symm hxy, exact Ne.symm hxa, exact hx]
103+
#align mem_of_mem_perms_of_list mem_of_mem_permsOfList
104+
105+
theorem mem_permsOfList_iff {l : List α} {f : Perm α} :
106+
f ∈ permsOfList l ↔ ∀ {x}, f x ≠ x → x ∈ l :=
107+
⟨mem_of_mem_permsOfList, mem_permsOfList_of_mem⟩
108+
#align mem_perms_of_list_iff mem_permsOfList_iff
109+
110+
theorem nodup_permsOfList : ∀ {l : List α} (_ : l.Nodup), (permsOfList l).Nodup
111+
| [], _ => by simp [permsOfList]
112+
| a :: l, hl => by
113+
have hl' : l.Nodup := hl.of_cons
114+
have hln' : (permsOfList l).Nodup := nodup_permsOfList hl'
115+
have hmeml : ∀ {f : Perm α}, f ∈ permsOfList l → f a = a := fun {f} hf =>
116+
not_not.1 (mt (mem_of_mem_permsOfList hf _) (nodup_cons.1 hl).1)
117+
rw [permsOfList, List.nodup_append, List.nodup_bind, pairwise_iff_get]
118+
refine ⟨?_, ⟨⟨?_,?_ ⟩, ?_⟩⟩
119+
· exact hln'
120+
· exact fun _ _ => hln'.map fun _ _ => mul_left_cancel
121+
· intros i j hij x hx₁ hx₂
122+
let ⟨f, hf⟩ := List.mem_map'.1 hx₁
123+
let ⟨g, hg⟩ := List.mem_map'.1 hx₂
124+
have hix : x a = List.get l i := by
125+
rw [← hf.2, mul_apply, hmeml hf.1, swap_apply_left]
126+
have hiy : x a = List.get l j := by
127+
rw [← hg.2, mul_apply, hmeml hg.1, swap_apply_left]
128+
have hieqj : i = j := nodup_iff_injective_get.1 hl' (hix.symm.trans hiy)
129+
exact absurd hieqj (_root_.ne_of_lt hij)
130+
· intros f hf₁ hf₂
131+
let ⟨x, hx, hx'⟩ := List.mem_bind.1 hf₂
132+
let ⟨g, hg⟩ := List.mem_map'.1 hx'
133+
have hgxa : g⁻¹ x = a := f.injective <| by rw [hmeml hf₁, ← hg.2]; simp
134+
have hxa : x ≠ a := fun h => (List.nodup_cons.1 hl).1 (h ▸ hx)
135+
exact (List.nodup_cons.1 hl).1 <|
136+
hgxa ▸ mem_of_mem_permsOfList hg.1 _ (by rwa [apply_inv_self, hgxa])
137+
#align nodup_perms_of_list nodup_permsOfList
138+
139+
/-- Given a finset, produce the finset of all permutations of its elements. -/
140+
def permsOfFinset (s : Finset α) : Finset (Perm α) :=
141+
Quotient.hrecOn s.1 (fun l hl => ⟨permsOfList l, nodup_permsOfList hl⟩)
142+
(fun a b hab =>
143+
hfunext (congr_arg _ (Quotient.sound hab)) fun ha hb _ =>
144+
heq_of_eq <| Finset.ext <| by simp [mem_permsOfList_iff, hab.mem_iff])
145+
s.2
146+
#align perms_of_finset permsOfFinset
147+
148+
theorem mem_perms_of_finset_iff :
149+
∀ {s : Finset α} {f : Perm α}, f ∈ permsOfFinset s ↔ ∀ {x}, f x ≠ x → x ∈ s := by
150+
rintro ⟨⟨l⟩, hs⟩ f ; exact mem_permsOfList_iff
151+
#align mem_perms_of_finset_iff mem_perms_of_finset_iff
152+
153+
theorem card_perms_of_finset : ∀ s : Finset α, (permsOfFinset s).card = s.card ! := by
154+
rintro ⟨⟨l⟩, hs⟩ ; exact length_permsOfList l
155+
#align card_perms_of_finset card_perms_of_finset
156+
157+
/-- The collection of permutations of a fintype is a fintype. -/
158+
def fintypePerm [Fintype α] : Fintype (Perm α) :=
159+
⟨permsOfFinset (@Finset.univ α _), by simp [mem_perms_of_finset_iff]⟩
160+
#align fintype_perm fintypePerm
161+
162+
instance equivFintype [Fintype α] [Fintype β] : Fintype (α ≃ β) :=
163+
if h : Fintype.card β = Fintype.card α then
164+
Trunc.recOnSubsingleton (Fintype.truncEquivFin α) fun eα =>
165+
Trunc.recOnSubsingleton (Fintype.truncEquivFin β) fun eβ =>
166+
@Fintype.ofEquiv _ (Perm α) fintypePerm
167+
(equivCongr (Equiv.refl α) (eα.trans (Eq.recOn h eβ.symm)) : α ≃ α ≃ (α ≃ β))
168+
else ⟨∅, fun x => False.elim (h (Fintype.card_eq.2 ⟨x.symm⟩))⟩
169+
170+
theorem Fintype.card_perm [Fintype α] : Fintype.card (Perm α) = (Fintype.card α)! :=
171+
Subsingleton.elim (@fintypePerm α _ _) (@equivFintype α α _ _ _ _) ▸ card_perms_of_finset _
172+
#align fintype.card_perm Fintype.card_perm
173+
174+
theorem Fintype.card_equiv [Fintype α] [Fintype β] (e : α ≃ β) :
175+
Fintype.card (α ≃ β) = (Fintype.card α)! :=
176+
Fintype.card_congr (equivCongr (Equiv.refl α) e) ▸ Fintype.card_perm
177+
#align fintype.card_equiv Fintype.card_equiv

0 commit comments

Comments
 (0)