|
| 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