|
1 | 1 | /-
|
2 | 2 | Copyright (c) 2018 Mario Carneiro. All rights reserved.
|
3 | 3 | Released under Apache 2.0 license as described in the file LICENSE.
|
4 |
| -Authors: Mario Carneiro |
| 4 | +Authors: Mario Carneiro, Yuyang Zhao |
5 | 5 | -/
|
| 6 | +import Mathlib.Data.List.Pi |
6 | 7 | import Mathlib.Data.Fintype.Basic
|
7 | 8 |
|
8 | 9 | /-!
|
9 | 10 | # Quotients of families indexed by a finite type
|
10 | 11 |
|
11 |
| -This file provides `Quotient.finChoice`, a mechanism to go from a finite family of quotients |
12 |
| -to a quotient of finite families. |
| 12 | +This file proves some basic facts and defines lifting and recursion principle for quotients indexed |
| 13 | +by a finite type. |
13 | 14 |
|
14 | 15 | ## Main definitions
|
15 | 16 |
|
16 |
| -* `Quotient.finChoice` |
| 17 | +* `Quotient.finChoice`: Given a function `f : Π i, Quotient (S i)` on a fintype `ι`, returns the |
| 18 | + class of functions `Π i, α i` sending each `i` to an element of the class `f i`. |
| 19 | +* `Quotient.finChoiceEquiv`: A finite family of quotients is equivalent to a quotient of |
| 20 | + finite families. |
| 21 | +* `Quotient.finLiftOn`: Given a fintype `ι`. A function on `Π i, α i` which respects |
| 22 | + setoid `S i` for each `i` can be lifted to a function on `Π i, Quotient (S i)`. |
| 23 | +* `Quotient.finRecOn`: Recursion principle for quotients indexed by a finite type. It is the |
| 24 | + dependent version of `Quotient.finLiftOn`. |
17 | 25 |
|
18 | 26 | -/
|
19 | 27 |
|
20 | 28 |
|
21 |
| -/-- An auxiliary function for `Quotient.finChoice`. Given a |
22 |
| -collection of setoids indexed by a type `ι`, a (finite) list `l` of |
23 |
| -indices, and a function that for each `i ∈ l` gives a term of the |
24 |
| -corresponding quotient type, then there is a corresponding term in the |
25 |
| -quotient of the product of the setoids indexed by `l`. -/ |
26 |
| -def Quotient.finChoiceAux {ι : Type*} [DecidableEq ι] {α : ι → Type*} [S : ∀ i, Setoid (α i)] : |
27 |
| - ∀ l : List ι, (∀ i ∈ l, Quotient (S i)) → @Quotient (∀ i ∈ l, α i) (by infer_instance) |
28 |
| - | [], _ => ⟦fun _ h => nomatch List.not_mem_nil _ h⟧ |
29 |
| - | i :: l, f => by |
30 |
| - refine Quotient.liftOn₂ (f i (List.mem_cons_self _ _)) |
31 |
| - (Quotient.finChoiceAux l fun j h => f j (List.mem_cons_of_mem _ h)) ?_ ?_ |
32 |
| - · exact fun a l => ⟦fun j h => |
33 |
| - if e : j = i then by rw [e]; exact a else l _ ((List.mem_cons.1 h).resolve_left e)⟧ |
34 |
| - refine fun a₁ l₁ a₂ l₂ h₁ h₂ => Quotient.sound fun j h => ?_ |
35 |
| - by_cases e : j = i |
36 |
| - · simp [e]; subst j |
37 |
| - exact h₁ |
38 |
| - · simpa [e] using h₂ _ _ |
39 |
| - |
40 |
| -theorem Quotient.finChoiceAux_eq {ι : Type*} [DecidableEq ι] {α : ι → Type*} |
41 |
| - [S : ∀ i, Setoid (α i)] : |
42 |
| - ∀ (l : List ι) (f : ∀ i ∈ l, α i), (Quotient.finChoiceAux l fun i h => ⟦f i h⟧) = ⟦f⟧ |
43 |
| - | [], _ => Quotient.sound fun _ h => nomatch List.not_mem_nil _ h |
44 |
| - | i :: l, f => by |
45 |
| - simp only [finChoiceAux, Quotient.finChoiceAux_eq l, eq_mpr_eq_cast, lift_mk] |
46 |
| - refine Quotient.sound fun j h => ?_ |
47 |
| - by_cases e : j = i <;> simp [e] <;> try exact Setoid.refl _ |
48 |
| - subst j; exact Setoid.refl _ |
49 |
| - |
50 |
| -/-- Given a collection of setoids indexed by a fintype `ι` and a |
51 |
| -function that for each `i : ι` gives a term of the corresponding |
52 |
| -quotient type, then there is corresponding term in the quotient of the |
53 |
| -product of the setoids. -/ |
54 |
| -def Quotient.finChoice {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*} |
55 |
| - [S : ∀ i, Setoid (α i)] (f : ∀ i, Quotient (S i)) : @Quotient (∀ i, α i) (by infer_instance) := |
56 |
| - Quotient.liftOn |
57 |
| - (@Quotient.recOn _ _ (fun l : Multiset ι => @Quotient (∀ i ∈ l, α i) (by infer_instance)) |
58 |
| - Finset.univ.1 (fun l => Quotient.finChoiceAux l fun i _ => f i) (fun a b h => by |
59 |
| - have := fun a => Quotient.finChoiceAux_eq a fun i _ => Quotient.out (f i) |
60 |
| - simp? [Quotient.out_eq] at this says simp only [out_eq] at this |
61 |
| - simp only [Multiset.quot_mk_to_coe, this] |
62 |
| - let g := fun a : Multiset ι => |
63 |
| - (⟦fun (i : ι) (_ : i ∈ a) => Quotient.out (f i)⟧ : Quotient (by infer_instance)) |
64 |
| - apply eq_of_heq |
65 |
| - trans (g a) |
66 |
| - · exact eqRec_heq (φ := fun l : Multiset ι => @Quotient (∀ i ∈ l, α i) (by infer_instance)) |
67 |
| - (Quotient.sound h) (g a) |
68 |
| - · change HEq (g a) (g b); congr 1; exact Quotient.sound h)) |
69 |
| - (fun f => ⟦fun i => f i (Finset.mem_univ _)⟧) (fun _ _ h => Quotient.sound fun i => by apply h) |
70 |
| - |
71 |
| -theorem Quotient.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*} |
72 |
| - [∀ i, Setoid (α i)] (f : ∀ i, α i) : (Quotient.finChoice fun i => ⟦f i⟧) = ⟦f⟧ := by |
73 |
| - dsimp only [Quotient.finChoice] |
74 |
| - conv_lhs => |
75 |
| - enter [1] |
76 |
| - tactic => |
77 |
| - change _ = ⟦fun i _ => f i⟧ |
78 |
| - exact Quotient.inductionOn (@Finset.univ ι _).1 fun l => Quotient.finChoiceAux_eq _ _ |
| 29 | +namespace Quotient |
| 30 | + |
| 31 | +section List |
| 32 | +variable {ι : Type*} [DecidableEq ι] {α : ι → Sort*} {S : ∀ i, Setoid (α i)} {β : Sort*} |
| 33 | + |
| 34 | +/-- Given a collection of setoids indexed by a type `ι`, a list `l` of indices, and a function that |
| 35 | + for each `i ∈ l` gives a term of the corresponding quotient type, then there is a corresponding |
| 36 | + term in the quotient of the product of the setoids indexed by `l`. -/ |
| 37 | +def listChoice {l : List ι} (q : ∀ i ∈ l, Quotient (S i)) : @Quotient (∀ i ∈ l, α i) piSetoid := |
| 38 | + match l with |
| 39 | + | [] => ⟦nofun⟧ |
| 40 | + | i :: _ => Quotient.liftOn₂ (List.Pi.head (i := i) q) |
| 41 | + (listChoice (List.Pi.tail q)) |
| 42 | + (⟦List.Pi.cons _ _ · ·⟧) |
| 43 | + (fun _ _ _ _ ha hl ↦ Quotient.sound (List.Pi.forall_rel_cons_ext ha hl)) |
| 44 | + |
| 45 | +theorem listChoice_mk {l : List ι} (a : ∀ i ∈ l, α i) : listChoice (S := S) (⟦a · ·⟧) = ⟦a⟧ := |
| 46 | + match l with |
| 47 | + | [] => Quotient.sound nofun |
| 48 | + | i :: l => by |
| 49 | + unfold listChoice List.Pi.tail |
| 50 | + rw [listChoice_mk] |
| 51 | + exact congrArg (⟦·⟧) (List.Pi.cons_eta a) |
| 52 | + |
| 53 | +/-- Choice-free induction principle for quotients indexed by a `List`. -/ |
| 54 | +@[elab_as_elim] |
| 55 | +lemma list_ind {l : List ι} {C : (∀ i ∈ l, Quotient (S i)) → Prop} |
| 56 | + (f : ∀ a : ∀ i ∈ l, α i, C (⟦a · ·⟧)) (q : ∀ i ∈ l, Quotient (S i)) : C q := |
| 57 | + match l with |
| 58 | + | [] => cast (congr_arg _ (funext₂ nofun)) (f nofun) |
| 59 | + | i :: l => by |
| 60 | + rw [← List.Pi.cons_eta q] |
| 61 | + induction' List.Pi.head q using Quotient.ind with a |
| 62 | + refine @list_ind _ (fun q ↦ C (List.Pi.cons _ _ ⟦a⟧ q)) ?_ (List.Pi.tail q) |
| 63 | + intro as |
| 64 | + rw [List.Pi.cons_map a as (fun i ↦ Quotient.mk (S i))] |
| 65 | + exact f _ |
| 66 | + |
| 67 | +end List |
| 68 | + |
| 69 | +section Fintype |
| 70 | +variable {ι : Type*} [Fintype ι] [DecidableEq ι] {α : ι → Sort*} {S : ∀ i, Setoid (α i)} {β : Sort*} |
| 71 | + |
| 72 | +/-- Choice-free induction principle for quotients indexed by a finite type. |
| 73 | + See `Quotient.induction_on_pi` for the general version assuming `Classical.choice`. -/ |
| 74 | +@[elab_as_elim] |
| 75 | +lemma ind_fintype_pi {C : (∀ i, Quotient (S i)) → Prop} |
| 76 | + (f : ∀ a : ∀ i, α i, C (⟦a ·⟧)) (q : ∀ i, Quotient (S i)) : C q := by |
| 77 | + have {m : Multiset ι} (C : (∀ i ∈ m, Quotient (S i)) → Prop) : |
| 78 | + ∀ (_ : ∀ a : ∀ i ∈ m, α i, C (⟦a · ·⟧)) (q : ∀ i ∈ m, Quotient (S i)), C q := by |
| 79 | + induction m using Quotient.ind |
| 80 | + exact list_ind |
| 81 | + exact this (fun q ↦ C (q · (Finset.mem_univ _))) (fun _ ↦ f _) (fun i _ ↦ q i) |
| 82 | + |
| 83 | +/-- Choice-free induction principle for quotients indexed by a finite type. |
| 84 | + See `Quotient.induction_on_pi` for the general version assuming `Classical.choice`. -/ |
| 85 | +@[elab_as_elim] |
| 86 | +lemma induction_on_fintype_pi {C : (∀ i, Quotient (S i)) → Prop} |
| 87 | + (q : ∀ i, Quotient (S i)) (f : ∀ a : ∀ i, α i, C (⟦a ·⟧)) : C q := |
| 88 | + ind_fintype_pi f q |
| 89 | + |
| 90 | +/-- Given a collection of setoids indexed by a fintype `ι` and a function that for each `i : ι` |
| 91 | + gives a term of the corresponding quotient type, then there is corresponding term in the quotient |
| 92 | + of the product of the setoids. |
| 93 | + See `Quotient.choice` for the noncomputable general version. -/ |
| 94 | +def finChoice (q : ∀ i, Quotient (S i)) : |
| 95 | + @Quotient (∀ i, α i) piSetoid := by |
| 96 | + let e := Equiv.subtypeQuotientEquivQuotientSubtype (fun l : List ι ↦ ∀ i, i ∈ l) |
| 97 | + (fun s : Multiset ι ↦ ∀ i, i ∈ s) (fun i ↦ Iff.rfl) (fun _ _ ↦ Iff.rfl) ⟨_, Finset.mem_univ⟩ |
| 98 | + refine e.liftOn |
| 99 | + (fun l ↦ (listChoice fun i _ ↦ q i).map (fun a i ↦ a i (l.2 i)) ?_) ?_ |
| 100 | + · exact fun _ _ h i ↦ h i _ |
| 101 | + intro _ _ _ |
| 102 | + refine ind_fintype_pi (fun a ↦ ?_) q |
| 103 | + simp_rw [listChoice_mk, Quotient.map_mk] |
| 104 | + |
| 105 | +theorem finChoice_eq (a : ∀ i, α i) : |
| 106 | + finChoice (S := S) (⟦a ·⟧) = ⟦a⟧ := by |
| 107 | + dsimp [finChoice] |
| 108 | + obtain ⟨l, hl⟩ := (Finset.univ.val : Multiset ι).exists_rep |
| 109 | + simp_rw [← hl, Equiv.subtypeQuotientEquivQuotientSubtype, listChoice_mk] |
| 110 | + rfl |
| 111 | + |
| 112 | +lemma eval_finChoice (f : ∀ i, Quotient (S i)) : |
| 113 | + eval (finChoice f) = f := |
| 114 | + induction_on_fintype_pi f (fun a ↦ by rw [finChoice_eq]; rfl) |
| 115 | + |
| 116 | +/-- Lift a function on `∀ i, α i` to a function on `∀ i, Quotient (S i)`. -/ |
| 117 | +def finLiftOn (q : ∀ i, Quotient (S i)) (f : (∀ i, α i) → β) |
| 118 | + (h : ∀ (a b : ∀ i, α i), (∀ i, a i ≈ b i) → f a = f b) : β := |
| 119 | + (finChoice q).liftOn f h |
| 120 | + |
| 121 | +@[simp] |
| 122 | +lemma finLiftOn_empty [e : IsEmpty ι] (q : ∀ i, Quotient (S i)) : |
| 123 | + finLiftOn (β := β) q = fun f _ ↦ f e.elim := by |
| 124 | + ext f h |
| 125 | + dsimp [finLiftOn] |
| 126 | + induction finChoice q using Quotient.ind |
| 127 | + exact h _ _ e.elim |
| 128 | + |
| 129 | +@[simp] |
| 130 | +lemma finLiftOn_mk (a : ∀ i, α i) : |
| 131 | + finLiftOn (S := S) (β := β) (⟦a ·⟧) = fun f _ ↦ f a := by |
| 132 | + ext f h |
| 133 | + dsimp [finLiftOn] |
| 134 | + rw [finChoice_eq] |
79 | 135 | rfl
|
80 | 136 |
|
| 137 | +/-- `Quotient.finChoice` as an equivalence. -/ |
| 138 | +@[simps] |
| 139 | +def finChoiceEquiv : |
| 140 | + (∀ i, Quotient (S i)) ≃ @Quotient (∀ i, α i) piSetoid where |
| 141 | + toFun := finChoice |
| 142 | + invFun := eval |
| 143 | + left_inv q := by |
| 144 | + refine induction_on_fintype_pi q (fun a ↦ ?_) |
| 145 | + rw [finChoice_eq] |
| 146 | + rfl |
| 147 | + right_inv q := by |
| 148 | + induction q using Quotient.ind |
| 149 | + exact finChoice_eq _ |
| 150 | + |
| 151 | +/-- Recursion principle for quotients indexed by a finite type. -/ |
| 152 | +@[elab_as_elim] |
| 153 | +def finHRecOn {C : (∀ i, Quotient (S i)) → Sort*} |
| 154 | + (q : ∀ i, Quotient (S i)) |
| 155 | + (f : ∀ a : ∀ i, α i, C (⟦a ·⟧)) |
| 156 | + (h : ∀ (a b : ∀ i, α i), (∀ i, a i ≈ b i) → HEq (f a) (f b)) : |
| 157 | + C q := |
| 158 | + eval_finChoice q ▸ (finChoice q).hrecOn f h |
| 159 | + |
| 160 | +/-- Recursion principle for quotients indexed by a finite type. -/ |
| 161 | +@[elab_as_elim] |
| 162 | +def finRecOn {C : (∀ i, Quotient (S i)) → Sort*} |
| 163 | + (q : ∀ i, Quotient (S i)) |
| 164 | + (f : ∀ a : ∀ i, α i, C (⟦a ·⟧)) |
| 165 | + (h : ∀ (a b : ∀ i, α i) (h : ∀ i, a i ≈ b i), |
| 166 | + Eq.ndrec (f a) (funext fun i ↦ Quotient.sound (h i)) = f b) : |
| 167 | + C q := |
| 168 | + finHRecOn q f (rec_heq_iff_heq.mp <| heq_of_eq <| h · · ·) |
| 169 | + |
| 170 | +@[simp] |
| 171 | +lemma finHRecOn_mk {C : (∀ i, Quotient (S i)) → Sort*} |
| 172 | + (a : ∀ i, α i) : |
| 173 | + finHRecOn (C := C) (⟦a ·⟧) = fun f _ ↦ f a := by |
| 174 | + ext f h |
| 175 | + refine eq_of_heq ((eqRec_heq _ _).trans ?_) |
| 176 | + rw [finChoice_eq] |
| 177 | + rfl |
| 178 | + |
| 179 | +@[simp] |
| 180 | +lemma finRecOn_mk {C : (∀ i, Quotient (S i)) → Sort*} |
| 181 | + (a : ∀ i, α i) : |
| 182 | + finRecOn (C := C) (⟦a ·⟧) = fun f _ ↦ f a := by |
| 183 | + unfold finRecOn |
| 184 | + simp |
| 185 | + |
| 186 | +end Fintype |
| 187 | + |
| 188 | +end Quotient |
| 189 | + |
| 190 | +namespace Trunc |
| 191 | +variable {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Sort*} {β : Sort*} |
| 192 | + |
81 | 193 | /-- Given a function that for each `i : ι` gives a term of the corresponding
|
82 | 194 | truncation type, then there is corresponding term in the truncation of the product. -/
|
83 |
| -def Trunc.finChoice {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*} |
84 |
| - (f : ∀ i, Trunc (α i)) : Trunc (∀ i, α i) := |
85 |
| - Quotient.map' id (fun _ _ _ => trivial) |
86 |
| - (Quotient.finChoice f (S := fun _ => trueSetoid)) |
| 195 | +def finChoice (q : ∀ i, Trunc (α i)) : Trunc (∀ i, α i) := |
| 196 | + Quotient.map' id (fun _ _ _ => trivial) (Quotient.finChoice q) |
87 | 197 |
|
88 |
| -theorem Trunc.finChoice_eq {ι : Type*} [DecidableEq ι] [Fintype ι] {α : ι → Type*} |
89 |
| - (f : ∀ i, α i) : (Trunc.finChoice fun i => Trunc.mk (f i)) = Trunc.mk f := |
| 198 | +theorem finChoice_eq (f : ∀ i, α i) : (Trunc.finChoice fun i => Trunc.mk (f i)) = Trunc.mk f := |
90 | 199 | Subsingleton.elim _ _
|
| 200 | + |
| 201 | +/-- Lift a function on `∀ i, α i` to a function on `∀ i, Trunc (α i)`. -/ |
| 202 | +def finLiftOn (q : ∀ i, Trunc (α i)) (f : (∀ i, α i) → β) (h : ∀ (a b : ∀ i, α i), f a = f b) : β := |
| 203 | + Quotient.finLiftOn q f (fun _ _ _ ↦ h _ _) |
| 204 | + |
| 205 | +@[simp] |
| 206 | +lemma finLiftOn_empty [e : IsEmpty ι] (q : ∀ i, Trunc (α i)) : |
| 207 | + finLiftOn (β := β) q = fun f _ ↦ f e.elim := |
| 208 | + funext₂ fun _ _ ↦ congrFun₂ (Quotient.finLiftOn_empty q) _ _ |
| 209 | + |
| 210 | +@[simp] |
| 211 | +lemma finLiftOn_mk (a : ∀ i, α i) : |
| 212 | + finLiftOn (β := β) (⟦a ·⟧) = fun f _ ↦ f a := |
| 213 | + funext₂ fun _ _ ↦ congrFun₂ (Quotient.finLiftOn_mk a) _ _ |
| 214 | + |
| 215 | +/-- `Trunc.finChoice` as an equivalence. -/ |
| 216 | +@[simps] |
| 217 | +def finChoiceEquiv : (∀ i, Trunc (α i)) ≃ Trunc (∀ i, α i) where |
| 218 | + toFun := finChoice |
| 219 | + invFun q i := q.map (· i) |
| 220 | + left_inv _ := Subsingleton.elim _ _ |
| 221 | + right_inv _ := Subsingleton.elim _ _ |
| 222 | + |
| 223 | +/-- Recursion principle for `Trunc`s indexed by a finite type. -/ |
| 224 | +@[elab_as_elim] |
| 225 | +def finRecOn {C : (∀ i, Trunc (α i)) → Sort*} |
| 226 | + (q : ∀ i, Trunc (α i)) |
| 227 | + (f : ∀ a : ∀ i, α i, C (mk <| a ·)) |
| 228 | + (h : ∀ (a b : ∀ i, α i), (Eq.ndrec (f a) (funext fun _ ↦ Trunc.eq _ _)) = f b) : |
| 229 | + C q := |
| 230 | + Quotient.finRecOn q (f ·) (fun _ _ _ ↦ h _ _) |
| 231 | + |
| 232 | +@[simp] |
| 233 | +lemma finRecOn_mk {C : (∀ i, Trunc (α i)) → Sort*} |
| 234 | + (a : ∀ i, α i) : |
| 235 | + finRecOn (C := C) (⟦a ·⟧) = fun f _ ↦ f a := by |
| 236 | + unfold finRecOn |
| 237 | + simp |
| 238 | + |
| 239 | +end Trunc |
0 commit comments