|
| 1 | +(* -------------------------------------------------------------------- *) |
| 2 | +require import AllCore List Ring Binomial Perms FinType Finite Distr. |
| 3 | +require (*--*) Subtype. |
| 4 | + |
| 5 | +(* -------------------------------------------------------------------- *) |
| 6 | +type t. |
| 7 | + |
| 8 | +clone FinType as FinT with type t <- t. |
| 9 | + |
| 10 | +hint simplify FinT.enumP. |
| 11 | + |
| 12 | +hint exact : FinT.enum_uniq. |
| 13 | + |
| 14 | +(* -------------------------------------------------------------------- *) |
| 15 | +(* FIXME: move this *) |
| 16 | +lemma uniq_nth ['a] (x0 : 'a) (s : 'a list) : |
| 17 | + uniq s => forall i j, 0 <= i < size s => 0 <= j < size s => |
| 18 | + nth x0 s i = nth x0 s j => i = j. |
| 19 | +proof. |
| 20 | +move=> uqs i j rgi rgj /(congr1 (fun x => index x s)) /=. |
| 21 | +by rewrite !index_uniq. |
| 22 | +qed. |
| 23 | + |
| 24 | +(* -------------------------------------------------------------------- *) |
| 25 | +(* FIXME: move this *) |
| 26 | +lemma inj_bij (f : t -> t) : injective f => bijective f. |
| 27 | +proof. |
| 28 | +pose P y x := y = f x; pose g := fun y => choiceb (P y) witness. |
| 29 | +move=> inj_f; exists g; split. |
| 30 | +- move=> x @/g; have := choicebP (P (f x)) witness _ => /=. |
| 31 | + - by exists x. - by move/inj_f => /eq_sym. |
| 32 | +move=> y @/g; have /eq_sym // := choicebP (P y) witness _ => /=. |
| 33 | +pose s := map f FinT.enum; suff: perm_eq s FinT.enum. |
| 34 | +- by move/perm_eq_mem/(_ y) => /= /mapP[x] /= ->; exists x. |
| 35 | +have uqs: uniq s by rewrite map_inj_in_uniq //#. |
| 36 | +apply/perm_eq_sym/uniq_eq_perm_eq => //; last first. |
| 37 | +- by rewrite size_map. |
| 38 | +apply/fun_ext=> x /=; rewrite eq_sym &(eqT). |
| 39 | +suff: perm_eq s FinT.enum by move/perm_eq_mem/(_ x). |
| 40 | +apply: uniq_le_perm_eq => //. |
| 41 | +- by move=> x' /=. (* ??? *) |
| 42 | +- by rewrite size_map. |
| 43 | +qed. |
| 44 | + |
| 45 | +(* -------------------------------------------------------------------- *) |
| 46 | +type preperm = t -> t. |
| 47 | + |
| 48 | +op isperm (p : preperm) = |
| 49 | + bijective p. |
| 50 | + |
| 51 | +subtype perm as PSub = { p : preperm | isperm p }. |
| 52 | + |
| 53 | +realize inhabited by exists idfun; smt(). |
| 54 | + |
| 55 | +(* -------------------------------------------------------------------- *) |
| 56 | +abbrev "_.[_]" (p : perm) (x : t) = (PSub.val p) x. |
| 57 | + |
| 58 | +(* -------------------------------------------------------------------- *) |
| 59 | +op preperm1 : preperm = |
| 60 | + idfun. |
| 61 | + |
| 62 | +op prepermM (p1 p2 : preperm) = |
| 63 | + p1 \o p2. |
| 64 | + |
| 65 | +op prepermV (p : preperm) = |
| 66 | + choiceb (fun pV => cancel p pV) witness. |
| 67 | + |
| 68 | +(* -------------------------------------------------------------------- *) |
| 69 | +lemma perm1_spec : isperm preperm1 by smt(). |
| 70 | + |
| 71 | +lemma permM_spec (p1 p2 : preperm) : |
| 72 | + isperm p1 => isperm p2 => isperm (prepermM p1 p2). |
| 73 | +proof. by apply: bij_comp. qed. |
| 74 | + |
| 75 | +lemma permV_spec (p : preperm) : |
| 76 | + isperm p => isperm (prepermV p). |
| 77 | +proof. |
| 78 | +move=> ^bijp [pV] [can_p can_pV]. |
| 79 | +have ?: cancel p (prepermV p). |
| 80 | +- apply: (choicebP (fun pV => cancel p pV) witness) => /=. |
| 81 | + by exists pV. |
| 82 | +suff ->: prepermV p = pV by smt(bij_can_bij). |
| 83 | +- by apply/fun_ext; apply: (bij_can_eq _ _ _ bijp) => //#. |
| 84 | +qed. |
| 85 | + |
| 86 | +(* -------------------------------------------------------------------- *) |
| 87 | +op perm1 = |
| 88 | + PSub.insubd preperm1. |
| 89 | + |
| 90 | +op ( \o ) (p1 p2 : perm) = |
| 91 | + PSub.insubd (prepermM (PSub.val p1) (PSub.val p2)). |
| 92 | + |
| 93 | +op [ ! ] (p : perm) = |
| 94 | + PSub.insubd (prepermV (PSub.val p)). |
| 95 | + |
| 96 | +(* -------------------------------------------------------------------- *) |
| 97 | +lemma perm1E (x : t) : perm1.[x] = x. |
| 98 | +proof. by rewrite /perm1 PSub.val_insubd ifT // &(perm1_spec). qed. |
| 99 | + |
| 100 | +lemma permME (p1 p2 : perm) (x : t) : (p1 \o p2).[x] = p1.[p2.[x]]. |
| 101 | +proof. by rewrite /(+) PSub.val_insubd ifT 1:(permM_spec) // PSub.valP. qed. |
| 102 | + |
| 103 | +hint simplify perm1E, permME. |
| 104 | + |
| 105 | +(* -------------------------------------------------------------------- *) |
| 106 | +lemma perm_eqP (p1 p2 : perm) : |
| 107 | + (p1 = p2) <=> (forall x, p1.[x] = p2.[x]). |
| 108 | +proof. by split=> [->//|eqext]; apply/PSub.val_inj/fun_ext. qed. |
| 109 | + |
| 110 | +(* -------------------------------------------------------------------- *) |
| 111 | +lemma mulpA: associative (\o). |
| 112 | +proof. by move=> p q r; apply/perm_eqP=> x. qed. |
| 113 | + |
| 114 | +(* -------------------------------------------------------------------- *) |
| 115 | +lemma mulp1: left_id perm1 (\o). |
| 116 | +proof. by move=> p; apply/perm_eqP=> x. qed. |
| 117 | + |
| 118 | +(* -------------------------------------------------------------------- *) |
| 119 | +lemma mul1p: right_id perm1 (\o). |
| 120 | +proof. by move=> p; apply/perm_eqP=> x. qed. |
| 121 | + |
| 122 | +(* -------------------------------------------------------------------- *) |
| 123 | +lemma mulpV : right_inverse perm1 [!] (\o). |
| 124 | +proof. |
| 125 | +move=> p; apply/perm_eqP=> x /=. |
| 126 | +rewrite /[!] PSub.insubdK 1:&(permV_spec) 1:(PSub.valP). |
| 127 | +have ->//: cancel (prepermV (PSub.val p)) (PSub.val p). |
| 128 | +apply/bij_can_sym; first by apply/PSub.valP. |
| 129 | +apply: (choicebP(fun pV => cancel (PSub.val p) pV) witness). |
| 130 | +by case: (PSub.valP p) => g [] *; exists g. |
| 131 | +qed. |
| 132 | + |
| 133 | +(* -------------------------------------------------------------------- *) |
| 134 | +lemma mulpVE (p : perm) (x : t) : p.[(!p).[x]] = x. |
| 135 | +proof. by rewrite -permME mulpV. qed. |
| 136 | + |
| 137 | +hint simplify mulpVE. |
| 138 | + |
| 139 | +(* -------------------------------------------------------------------- *) |
| 140 | +lemma bij_perm (p : perm) : bijective (PSub.val p). |
| 141 | +proof. by apply: PSub.valP. qed. |
| 142 | + |
| 143 | +(* -------------------------------------------------------------------- *) |
| 144 | +lemma inj_perm (p : perm) : injective (PSub.val p). |
| 145 | +proof. by apply: (bij_inj _ (bij_perm p)). qed. |
| 146 | + |
| 147 | +(* -------------------------------------------------------------------- *) |
| 148 | +hint simplify mulp1, mul1p, mulpV. |
| 149 | + |
| 150 | +(* -------------------------------------------------------------------- *) |
| 151 | +op tolist (p : perm) : t list = |
| 152 | + map (fun x => p.[x]) FinT.enum. |
| 153 | + |
| 154 | +(* -------------------------------------------------------------------- *) |
| 155 | +op pre_oflist (s : t list) : preperm = |
| 156 | + fun x => nth witness s (index x FinT.enum). |
| 157 | + |
| 158 | +(* -------------------------------------------------------------------- *) |
| 159 | +op oflist (s : t list) : perm = |
| 160 | + PSub.insubd (pre_oflist s). |
| 161 | + |
| 162 | +(* -------------------------------------------------------------------- *) |
| 163 | +lemma isperm_pre_oflist (s : t list) : |
| 164 | + perm_eq s FinT.enum => isperm (pre_oflist s). |
| 165 | +proof. |
| 166 | +move=> sfull; apply: inj_bij => x y @/pre_oflist. |
| 167 | +have eqsz: size s = size FinT.enum by apply: perm_eq_size. |
| 168 | +have hid_x: 0 <= index x FinT.enum < size s. |
| 169 | +- by rewrite index_ge0 /= eqsz index_mem. |
| 170 | +have hid_y: 0 <= index y FinT.enum < size s. |
| 171 | +- by rewrite index_ge0 /= eqsz index_mem. |
| 172 | +have: uniq s by rewrite (perm_eq_uniq _ _ sfull). |
| 173 | +move/uniq_nth => + eqnth - /(_ witness _ _ hid_x hid_y eqnth). |
| 174 | +by move/(congr1 (nth witness FinT.enum)); rewrite !nth_index. |
| 175 | +qed. |
| 176 | + |
| 177 | +(* -------------------------------------------------------------------- *) |
| 178 | +lemma oflistE (s : t list) (x : t) : |
| 179 | + perm_eq s FinT.enum => (oflist s).[x] = nth witness s (index x FinT.enum). |
| 180 | +proof. by move/isperm_pre_oflist => h; rewrite PSub.insubdK. qed. |
| 181 | + |
| 182 | +(* -------------------------------------------------------------------- *) |
| 183 | +lemma tolist_nth_index (p : perm) (x : t) : |
| 184 | + nth witness (tolist p) (index x FinT.enum) = p.[x]. |
| 185 | +proof. |
| 186 | +rewrite /tolist (nth_map witness) -1:nth_index //. |
| 187 | +by rewrite index_ge0 index_mem. |
| 188 | +qed. |
| 189 | + |
| 190 | +(* -------------------------------------------------------------------- *) |
| 191 | +lemma perm_tolist (p : perm) : perm_eq (tolist p) FinT.enum. |
| 192 | +proof. |
| 193 | +apply/perm_eq_sym/uniq_eq_perm_eq. |
| 194 | +- by apply: FinT.enum_uniq. |
| 195 | +- apply/fun_ext=> x; rewrite eq_sym /= eqT. |
| 196 | + by apply/mapP; exists (!p).[x]. |
| 197 | +- by rewrite size_map. |
| 198 | +qed. |
| 199 | + |
| 200 | +(* -------------------------------------------------------------------- *) |
| 201 | +lemma inj_tolist : injective tolist. |
| 202 | +proof. |
| 203 | +move=> p q; apply/contraLR; rewrite perm_eqP negb_forall. |
| 204 | +case=> x neq; pose i := index x FinT.enum. |
| 205 | +apply/negP => /(congr1 (fun s => nth witness s i)) /=. |
| 206 | +by rewrite !tolist_nth_index. |
| 207 | +qed. |
| 208 | + |
| 209 | +(* -------------------------------------------------------------------- *) |
| 210 | +lemma inj_oflist (p q : t list) : |
| 211 | + perm_eq p FinT.enum |
| 212 | + => perm_eq q FinT.enum |
| 213 | + => oflist p = oflist q |
| 214 | + => p = q. |
| 215 | +proof. |
| 216 | +move=> hp hq eq; apply: (eq_from_nth witness). |
| 217 | +- by rewrite (perm_eq_size _ _ hp) (perm_eq_size _ _ hq). |
| 218 | +move=> i; rewrite (perm_eq_size _ _ hp) => rgi. |
| 219 | +pose x := nth witness FinT.enum i. |
| 220 | +move/(congr1 PSub.val): eq => /fun_ext /(_ x). |
| 221 | +by rewrite !oflistE // !index_uniq. |
| 222 | +qed. |
| 223 | + |
| 224 | +(* -------------------------------------------------------------------- *) |
| 225 | +lemma oflistK : cancel tolist oflist. |
| 226 | +proof. |
| 227 | +move=> p; apply/perm_eqP=> x; rewrite oflistE 1:&(perm_tolist). |
| 228 | +rewrite (nth_map witness) /=. |
| 229 | +- by rewrite index_ge0 /= index_mem. |
| 230 | +- by rewrite nth_index. |
| 231 | +qed. |
| 232 | + |
| 233 | +(* -------------------------------------------------------------------- *) |
| 234 | +op dperm : perm distr = dmap (duniform (allperms FinT.enum)) oflist. |
| 235 | + |
| 236 | +(* -------------------------------------------------------------------- *) |
| 237 | +lemma dperm_ll : is_lossless dperm. |
| 238 | +proof. |
| 239 | +apply/dmap_ll/duniform_ll. |
| 240 | +suff: FinT.enum \in allperms FinT.enum by smt(). |
| 241 | +by rewrite allpermsP &(perm_eq_refl). |
| 242 | +qed. |
| 243 | + |
| 244 | +(* -------------------------------------------------------------------- *) |
| 245 | +lemma dperm_uni : is_uniform dperm. |
| 246 | +proof. |
| 247 | +rewrite /dperm dmap_duniform. |
| 248 | +- move=> p q /allpermsP /perm_eq_sym hp /allpermsP /perm_eq_sym hq. |
| 249 | + by apply: inj_oflist. |
| 250 | +- by apply: duniform_uni. |
| 251 | +qed. |
| 252 | + |
| 253 | +hint exact : dperm_uni. |
| 254 | + |
| 255 | +(* -------------------------------------------------------------------- *) |
| 256 | +lemma dperm_full : is_full dperm. |
| 257 | +proof. |
| 258 | +move=> p; apply/supp_dmap; exists (tolist p); split. |
| 259 | +- by apply/supp_duniform/allpermsP/perm_eq_sym/perm_tolist. |
| 260 | +- by rewrite oflistK. |
| 261 | +qed. |
| 262 | + |
| 263 | +hint exact : dperm_full. |
| 264 | + |
| 265 | +(* -------------------------------------------------------------------- *) |
| 266 | +lemma dperm_funiform : is_funiform dperm. |
| 267 | +proof. by apply: is_full_funiform. qed. |
| 268 | + |
| 269 | +hint exact : dperm_funiform. |
0 commit comments