Revision b529da0913cdf6dfc184487d2f99b3a837407271 authored by Alley Stoughton on 29 March 2021, 13:09:27 UTC, committed by Alley Stoughton on 29 March 2021, 13:09:27 UTC
1 parent c57f05e
FSet.ec
(* --------------------------------------------------------------------
* Copyright (c) - 2012--2016 - IMDEA Software Institute
* Copyright (c) - 2012--2018 - Inria
* Copyright (c) - 2012--2018 - Ecole Polytechnique
*
* Distributed under the terms of the CeCILL-B-V1 license
* -------------------------------------------------------------------- *)
(* -------------------------------------------------------------------- *)
require import Core Int List StdRing StdOrder.
(*---*) import IntOrder.
(* -------------------------------------------------------------------- *)
(* Finite sets are abstractly represented as the quotient by [perm_eq] *)
(* of lists without duplicates - i.e. as the quotient of lists by the *)
(* membership operation. *)
type 'a fset.
op elems : 'a fset -> 'a list.
op oflist : 'a list -> 'a fset.
axiom elemsK (s : 'a fset): oflist (elems s) = s.
axiom oflistK (s : 'a list): perm_eq (undup s) (elems (oflist s)).
axiom fset_eq (s1 s2 : 'a fset):
(perm_eq (elems s1) (elems s2)) => (s1 = s2).
(* -------------------------------------------------------------------- *)
lemma oflist_uniq (s : 'a list) : uniq s =>
perm_eq s (elems (oflist s)).
proof. by move/undup_id => {1}<-; apply/oflistK. qed.
(* -------------------------------------------------------------------- *)
lemma uniq_elems (s : 'a fset): uniq (elems s).
proof.
rewrite -(elemsK s); move: (elems s) => {s} s.
by rewrite -(perm_eq_uniq (undup s)) ?(undup_uniq, oflistK).
qed.
(* -------------------------------------------------------------------- *)
lemma perm_eq_oflist (s1 s2 : 'a list) :
oflist s1 = oflist s2 => perm_eq (undup s1) (undup s2).
proof.
move=> oflist_eq; rewrite (perm_eq_trans _ _ _ (oflistK s1)) oflist_eq.
by rewrite perm_eq_sym oflistK.
qed.
lemma oflist_perm_eq (s1 s2 : 'a list):
perm_eq s1 s2 => oflist s1 = oflist s2.
proof.
move=> peq_s1s2; apply/fset_eq/uniq_perm_eq; 1,2: exact/uniq_elems.
move=> x; rewrite -(perm_eq_mem _ _ (oflistK s1)).
rewrite -(perm_eq_mem _ _ (oflistK s2)).
by rewrite !mem_undup (perm_eq_mem _ _ peq_s1s2).
qed.
(* -------------------------------------------------------------------- *)
op card ['a] (s : 'a fset) = size (elems s) axiomatized by cardE.
(* -------------------------------------------------------------------- *)
op mem ['a] (s : 'a fset) (x : 'a) = mem (elems s) x
axiomatized by memE.
abbrev (\in) (z : 'a) (s : 'a fset) = mem s z.
lemma mem_oflist (s : 'a list):
forall x, mem (oflist s) x <=> mem s x.
proof.
move=> x; rewrite !memE (perm_eq_mem _ (undup s)) 2:mem_undup //.
by rewrite perm_eq_sym oflistK.
qed.
lemma fsetP (s1 s2 : 'a fset):
(s1 = s2) <=> (forall x, mem s1 x <=> mem s2 x).
proof.
split=> // h; apply/fset_eq/uniq_perm_eq; 1,2: exact/uniq_elems.
by move=> x; rewrite -!memE h.
qed.
(* -------------------------------------------------------------------- *)
op fset0 ['a] = oflist [<:'a>] axiomatized by set0E.
op fset1 ['a] (z : 'a) = oflist [z] axiomatized by set1E.
op (`|`) ['a] (s1 s2 : 'a fset) = oflist (elems s1 ++ elems s2)
axiomatized by setUE.
op (`&`) ['a] (s1 s2 : 'a fset) = oflist (filter (mem s2) (elems s1))
axiomatized by setIE.
op (`\`) ['a] (s1 s2 : 'a fset) = oflist (filter (predC (mem s2)) (elems s1))
axiomatized by setDE.
(* -------------------------------------------------------------------- *)
lemma in_fset0: forall x, mem fset0<:'a> x <=> false.
proof. by move=> x; rewrite set0E mem_oflist. qed.
lemma in_eq_fset0 ['a] (X : 'a fset): (forall x, !x \in X) => X = fset0.
proof. by move=> mem_X; apply/fsetP=> x; rewrite mem_X in_fset0. qed.
lemma elems_fset0 ['a]: elems fset0 = [<:'a>].
proof.
rewrite set0E; apply/perm_eq_small/perm_eq_sym=> //=.
by rewrite -{1}(undup_id []) ?oflistK.
qed.
lemma elems_eq_fset0 ['a] (A : 'a fset): elems A = [<:'a>] => A = fset0.
proof.
by move=> elems_nil; apply/fsetP=> x; rewrite !memE elems_fset0 elems_nil.
qed.
lemma in_fset1 z: forall x, mem (fset1<:'a> z) x <=> x = z.
proof. by move=> x; rewrite set1E /= mem_oflist. qed.
lemma in_eq_fset1 ['a] (X : 'a fset) x0:
(forall x, x \in X <=> x = x0) => X = fset1 x0.
proof. by move=> mem_X; apply/fsetP=> x; rewrite in_fset1 mem_X. qed.
lemma elems_fset1 (x : 'a) : elems (fset1 x) = [x].
proof.
rewrite set1E; apply/perm_eq_small/perm_eq_sym=> //=.
by rewrite -{1}(undup_id [x]) ?oflistK.
qed.
lemma elems_eq_fset1 (A : 'a fset) x : elems A = [x] => A = fset1 x.
proof.
by move=> elems_x; apply/fsetP=> x0; rewrite !memE elems_fset1 elems_x.
qed.
lemma in_fsetU (s1 s2 : 'a fset):
forall x, mem (s1 `|` s2) x <=> mem s1 x \/ mem s2 x.
proof. by move=> x; rewrite setUE mem_oflist mem_cat !memE. qed.
lemma in_fsetI (s1 s2 : 'a fset):
forall x, mem (s1 `&` s2) x <=> mem s1 x /\ mem s2 x.
proof. by move=> x; rewrite setIE mem_oflist mem_filter !memE. qed.
lemma in_fsetD (s1 s2 : 'a fset):
forall x, mem (s1 `\` s2) x <=> mem s1 x /\ !mem s2 x.
proof. by move=> x; rewrite setDE mem_oflist mem_filter /predC !memE. qed.
lemma setD1E (s : 'a fset) x :
perm_eq (elems (s `\` fset1 x)) (rem x (elems s)).
proof.
rewrite setDE; pose s' := List.filter _ _; apply/(perm_eq_trans s').
rewrite perm_eq_sym oflist_uniq ?filter_uniq ?uniq_elems.
rewrite /s' rem_filter ?uniq_elems; apply/uniq_perm_eq;
rewrite ?filter_uniq ?uniq_elems // => y.
by rewrite !mem_filter /predC in_fset1.
qed.
lemma perm_to_rem (s:'a fset) x :
mem s x => perm_eq (elems s) (x :: elems (s `\` fset1 x)).
proof.
rewrite memE => /perm_to_rem /perm_eqlP->; apply/perm_cons.
have /perm_eqlP <- := (setD1E s x); rewrite perm_eq_refl.
qed.
(* -------------------------------------------------------------------- *)
hint rewrite inE : in_fset0 in_fset1 in_fsetU in_fsetI in_fsetD.
lemma oflist_cons ['a] (x : 'a) s : oflist (x::s) = fset1 x `|` oflist s.
proof. by apply fsetP => z;rewrite mem_oflist !inE mem_oflist /=. qed.
lemma oflist_cat ['a] (s1 s2 : 'a list) :
oflist (s1 ++ s2) = oflist s1 `|` oflist s2.
proof. by apply fsetP => z; rewrite in_fsetU !mem_oflist mem_cat. qed.
(* -------------------------------------------------------------------- *)
lemma in_fsetU1 (s : 'a fset) x:
forall x', mem (s `|` fset1 x) x' <=> mem s x' \/ x' = x.
proof. by move=> x'; rewrite in_fsetU in_fset1. qed.
lemma in_fsetI1 (s : 'a fset) x:
forall x', mem (s `&` fset1 x) x' <=> mem s x /\ x' = x.
proof. by move=> x'; rewrite in_fsetI in_fset1. qed.
lemma in_fsetD1 (s : 'a fset) x:
forall x', mem (s `\` fset1 x) x' <=> mem s x' /\ x' <> x.
proof. by move=> x'; rewrite in_fsetD in_fset1. qed.
(* -------------------------------------------------------------------- *)
op pick ['a] (A : 'a fset) = head witness (elems A)
axiomatized by pickE.
lemma pick0: pick<:'a> fset0 = witness.
proof. by rewrite pickE elems_fset0. qed.
lemma mem_pick (A : 'a fset): A <> fset0 => mem A (pick A).
proof.
move=> /(contra _ _ (elems_eq_fset0 A)); rewrite pickE memE.
by move=> /(mem_head_behead witness) <-.
qed.
(* -------------------------------------------------------------------- *)
op filter ['a] (p : 'a -> bool) (s : 'a fset) =
oflist (filter p (elems s))
axiomatized by filterE.
(* -------------------------------------------------------------------- *)
lemma in_filter (p : 'a -> bool) (s : 'a fset):
forall x, mem (filter p s) x <=> p x /\ mem s x.
proof. by move=> x; rewrite filterE mem_oflist mem_filter memE. qed.
lemma filter0 (p : 'a -> bool): filter p fset0 = fset0.
proof. by apply/fsetP=> x; rewrite in_filter in_fset0. qed.
lemma filter1 (p : 'a -> bool) (a : 'a):
filter p (fset1 a) = if (p a) then fset1 a else fset0.
proof.
apply/fsetP=> x; rewrite in_filter fun_if2 in_fset1 in_fset0.
by case (x = a).
qed.
lemma filterU (p : 'a -> bool) (A B : 'a fset):
filter p (A `|` B) = filter p A `|` filter p B.
proof. by apply/fsetP=> x; rewrite !(inE,in_filter) andb_orr. qed.
lemma filterI (p : 'a -> bool) (A B : 'a fset):
filter p (A `&` B) = filter p A `&` filter p B.
proof. by apply/fsetP=> x; rewrite !(inE,in_filter) andbACA andbb. qed.
lemma filterD (p : 'a -> bool) (A B : 'a fset):
filter p (A `\` B) = filter p A `\` filter p B.
proof.
apply/fsetP=> x; rewrite !(inE,in_filter) !negb_and andb_orr.
by rewrite andbAC andbN andbA.
qed.
lemma filter_pred0 (A : 'a fset): filter pred0 A = fset0.
proof. by apply/fsetP=> x; rewrite in_fset0 in_filter. qed.
lemma filter_pred1 (a : 'a) (A : 'a fset):
filter (pred1 a) A = if mem A a then fset1 a else fset0.
proof.
apply/fsetP=> x; rewrite in_filter fun_if2 !inE.
by case (x = a)=> @/pred1 ->.
qed.
lemma filter_mem (A B : 'a fset): filter (mem A) B = A `&` B.
proof. by apply/fsetP=> x; rewrite in_fsetI in_filter. qed.
lemma filter_memC (A B : 'a fset): filter (predC (mem A)) B = B `\` A.
proof. by apply/fsetP=> x; rewrite in_fsetD in_filter andbC. qed.
(* -------------------------------------------------------------------- *)
op (\subset) (s1 s2 : 'a fset) = forall x, x \in s1 => x \in s2.
op (\proper) (s1 s2 : 'a fset) = s1 \subset s2 /\ s1 <> s2.
lemma nosmt subsetP (s1 s2 : 'a fset):
(s1 \subset s2) <=> (mem s1 <= mem s2).
proof. by []. qed.
lemma nosmt subset_trans (s1 s2 s3 : 'a fset):
s1 \subset s2 => s2 \subset s3 => s1 \subset s3.
proof. by move=> le1 le2 ? le3; apply/le2/le1. qed.
lemma properP (X Y : 'a fset) :
X \proper Y <=> X \subset Y /\ exists y, y \in Y /\ ! y \in X.
proof.
rewrite /(\proper) &(andb_id2l) fsetP negb_forall /= => le_XY.
apply/eqboolP/exists_eq => x /=; rewrite -negb_imply; congr.
by rewrite iffE eqboolP &(andb_idl) => _; apply/le_XY.
qed.
(* -------------------------------------------------------------------- *)
lemma nosmt eqEsubset (A B : 'a fset) : (A = B) <=> (A \subset B) /\ (B \subset A).
proof. by rewrite fsetP 2!subsetP subpred_eqP. qed.
(* -------------------------------------------------------------------- *)
lemma nosmt fset_ind (p : 'a fset -> bool):
p fset0 =>
(forall x s, !mem s x => p s => p (s `|` (fset1 x))) =>
(forall s, p s).
proof.
move=> p0 pa s; rewrite -elemsK.
elim (elems s) (uniq_elems s)=> {s} [|x s ih /cons_uniq []].
+ by rewrite -set0E.
rewrite -mem_oflist=> ^x_notin_s /pa + ^uniq_s /ih - h /h. (* FIXME: => h /h? *)
rewrite setUE elems_fset1.
rewrite (oflist_perm_eq (elems (oflist s) ++ [x]) (x::s)) //.
apply/perm_catCl=> /=; apply/perm_cons/perm_eq_sym.
by rewrite -{1}(undup_id _ uniq_s) oflistK.
qed.
(* ------------------------------------------------------------------ *)
lemma fsetUC (A B : 'a fset) : A `|` B = B `|` A.
proof. by apply/fsetP => x; rewrite !inE orbC. qed.
lemma fset0U (A : 'a fset) : fset0 `|` A = A.
proof. by apply/fsetP => x; rewrite !inE. qed.
lemma fsetU0 (A : 'a fset) : A `|` fset0 = A.
proof. by rewrite fsetUC fset0U. qed.
lemma fsetUA (A B C : 'a fset) : A `|` (B `|` C) = A `|` B `|` C.
proof. by apply/fsetP => x; rewrite !inE orbA. qed.
lemma fsetUCA (A B C : 'a fset) : A `|` (B `|` C) = B `|` (A `|` C).
proof. by rewrite !fsetUA (fsetUC B). qed.
lemma fsetUAC (A B C : 'a fset) : A `|` B `|` C = A `|` C `|` B.
proof. by rewrite -!fsetUA (fsetUC B). qed.
lemma fsetUACA (A B C D : 'a fset) : (A `|` B) `|` (C `|` D) = (A `|` C) `|` (B `|` D).
proof. by rewrite -!fsetUA (fsetUCA B). qed.
lemma fsetUid (A : 'a fset) : A `|` A = A.
proof. by apply/fsetP=> x; rewrite !inE orbb. qed.
lemma fsetUUl (A B C : 'a fset) : A `|` B `|` C = (A `|` C) `|` (B `|` C).
proof. by rewrite fsetUA (fsetUAC _ C) -(fsetUA _ C) fsetUid. qed.
lemma fsetUUr (A B C : 'a fset) : A `|` (B `|` C) = (A `|` B) `|` (A `|` C).
proof. by rewrite !(fsetUC A) fsetUUl. qed.
(* ------------------------------------------------------------------ *)
lemma fsetIC (A B : 'a fset) : A `&` B = B `&` A.
proof. by apply/fsetP => x; rewrite !inE andbC. qed.
lemma fset0I (A : 'a fset) : fset0 `&` A = fset0.
proof. by apply/fsetP => x; rewrite !inE andFb. qed.
lemma fsetI0 (A : 'a fset) : A `&` fset0 = fset0.
proof. by rewrite fsetIC fset0I. qed.
lemma fset1I (x : 'a) (D : 'a fset):
fset1 x `&` D = if mem D x then fset1 x else fset0.
proof.
by apply/fsetP=> y; rewrite fun_if2 !inE; case: (mem D x); case: (y = x).
qed.
lemma fsetI1 (x : 'a) (D : 'a fset):
D `&` fset1 x = if mem D x then fset1 x else fset0.
proof. by rewrite fsetIC fset1I. qed.
lemma fsetIA (A B C : 'a fset) : A `&` (B `&` C) = A `&` B `&` C.
proof. by apply/fsetP=> x; rewrite !inE andbA. qed.
lemma fsetICA (A B C : 'a fset) : A `&` (B `&` C) = B `&` (A `&` C).
proof. by rewrite !fsetIA (fsetIC A). qed.
lemma fsetIAC (A B C : 'a fset) : A `&` B `&` C = A `&` C `&` B.
proof. by rewrite -!fsetIA (fsetIC B). qed.
lemma fsetIACA (A B C D : 'a fset) : (A `&` B) `&` (C `&` D) = (A `&` C) `&` (B `&` D).
proof. by rewrite -!fsetIA (fsetICA B). qed.
lemma fsetIid (A : 'a fset) : A `&` A = A.
proof. by apply/fsetP=> x; rewrite !inE andbb. qed.
lemma fsetIIl (A B C : 'a fset) : A `&` B `&` C = (A `&` C) `&` (B `&` C).
proof. by rewrite fsetIA (fsetIAC _ C) -(fsetIA _ C) fsetIid. qed.
lemma fsetIIr (A B C : 'a fset) : A `&` (B `&` C) = (A `&` B) `&` (A `&` C).
proof. by rewrite !(fsetIC A) fsetIIl. qed.
(* ------------------------------------------------------------------ *)
lemma fsetIUr (A B C : 'a fset) : A `&` (B `|` C) = (A `&` B) `|` (A `&` C).
proof. by apply/fsetP=> x; rewrite !inE andb_orr. qed.
lemma fsetIUl (A B C : 'a fset) : (A `|` B) `&` C = (A `&` C) `|` (B `&` C).
proof. by apply/fsetP=> x; rewrite !inE andb_orl. qed.
lemma fsetUIr (A B C : 'a fset) : A `|` (B `&` C) = (A `|` B) `&` (A `|` C).
proof. by apply/fsetP=> x; rewrite !inE orb_andr. qed.
lemma fsetUIl (A B C : 'a fset) : (A `&` B) `|` C = (A `|` C) `&` (B `|` C).
proof. by apply/fsetP=> x; rewrite !inE orb_andl. qed.
lemma fsetUK (A B : 'a fset) : (A `|` B) `&` A = A.
proof. by apply/fsetP=> x; rewrite !inE orbK. qed.
lemma fsetKU (A B : 'a fset) : A `&` (B `|` A) = A.
proof. by apply/fsetP=> x; rewrite !inE orKb. qed.
lemma fsetIK (A B : 'a fset) : (A `&` B) `|` A = A.
proof. by apply/fsetP=> x; rewrite !inE andbK. qed.
lemma fsetKI (A B : 'a fset) : A `|` (B `&` A) = A.
proof. by apply/fsetP=> x; rewrite !inE andKb. qed.
(* ------------------------------------------------------------------ *)
lemma fsetD0 (A : 'a fset) : A `\` fset0 = A.
proof. by apply/fsetP=> x; rewrite !inE andbT. qed.
lemma fset0D (A : 'a fset) : fset0 `\` A = fset0.
proof. by apply/fsetP=> x; rewrite !inE. qed.
lemma fset1D (x : 'a) (D : 'a fset):
fset1 x `\` D = if mem D x then fset0 else fset1 x.
proof.
by apply/fsetP=> y; rewrite fun_if2 !inE; case: (mem D x); case: (y = x).
qed.
lemma fsetDv (A : 'a fset) : A `\` A = fset0.
proof. by apply/fsetP=> x; rewrite !inE andbN. qed.
lemma fsetID (A B : 'a fset) : A `&` B `|` A `\` B = A.
proof. by apply/fsetP=> x; rewrite !inE -andb_orr orbN andbT. qed.
lemma fsetII (A B : 'a fset) : (A `&` B) `&` (A `\` B) = fset0.
proof. by apply/fsetP=> x; rewrite !inE andbACA andbN andbF. qed.
lemma fsetDUl (A B C : 'a fset) : (A `|` B) `\` C = (A `\` C) `|` (B `\` C).
proof. by apply/fsetP=> x; rewrite !inE -andb_orl. qed.
lemma fsetDUr (A B C : 'a fset) : A `\` (B `|` C) = (A `\` B) `&` (A `\` C).
proof. by apply/fsetP=> x; rewrite !inE andbACA andbb negb_or. qed.
lemma fsetDIl (A B C : 'a fset) : (A `&` B) `\` C = (A `\` C) `&` (B `\` C).
proof. by apply/fsetP=> x; rewrite !inE andbACA andbb. qed.
lemma fsetIDA (A B C : 'a fset) : A `&` (B `\` C) = (A `&` B) `\` C.
proof. by apply/fsetP=> x; rewrite !inE !andbA. qed.
lemma fsetIDAC (A B C : 'a fset) : (A `\` B) `&` C = (A `&` C) `\` B.
proof. by apply/fsetP=> x; rewrite !inE andbAC. qed.
lemma fsetDIr (A B C : 'a fset) : A `\` (B `&` C) = (A `\` B) `|` (A `\` C).
proof. by apply/fsetP=> x; rewrite !inE -andb_orr negb_and. qed.
lemma fsetDDl (A B C : 'a fset) : (A `\` B) `\` C = A `\` (B `|` C).
proof. by apply/fsetP=> x; rewrite !inE !negb_or !andbA. qed.
lemma fsetDDr (A B C : 'a fset) : A `\` (B `\` C) = (A `\` B) `|` (A `&` C).
proof. by apply/fsetP=> x; rewrite !inE -andb_orr negb_and negbK. qed.
lemma fsetDK (A B : 'a fset) : (A `|` B) `\` B = A `\` B.
proof. by rewrite fsetDUl fsetDv fsetU0. qed.
lemma fsetDKv (A B : 'a fset) : (A `&` B) `\` B = fset0.
proof. by rewrite fsetDIl fsetDv fsetI0. qed.
(* -------------------------------------------------------------------- *)
lemma subsetIl (A B : 'a fset) : (A `&` B) \subset A.
proof. by apply/subsetP=> x; rewrite inE; case. qed.
lemma subsetIr (A B : 'a fset) : (A `&` B) \subset B.
proof. by apply/subsetP=> x; rewrite inE; case. qed.
(* -------------------------------------------------------------------- *)
lemma subsetDl (A B : 'a fset) : A `\` B \subset A.
proof. by apply/subsetP=> x; rewrite !inE; case. qed.
(* -------------------------------------------------------------------- *)
lemma sub0set (A : 'a fset) : fset0 \subset A.
proof. by apply/subsetP=> x; rewrite !inE. qed.
(* -------------------------------------------------------------------- *)
lemma fcards0: card fset0<:'a> = 0.
proof. by rewrite cardE set0E -(perm_eq_size (undup [])) 1:oflistK. qed.
lemma eq_fcards0 (A : 'a fset): A = fset0 => card A = 0.
proof. by move=> ->; apply/fcards0. qed.
lemma fcard_ge0 (A : 'a fset) : 0 <= card A.
proof. by rewrite cardE size_ge0. qed.
lemma fcard1 (x : 'a) : card (fset1 x) = 1.
proof. by rewrite cardE elems_fset1. qed.
(* -------------------------------------------------------------------- *)
lemma nosmt fcardUI_indep (A B : 'a fset) : A `&` B = fset0 =>
card (A `|` B) = card A + card B.
proof.
move/fsetP=> h; rewrite setUE !cardE; pose s := _ ++ _.
rewrite -(perm_eq_size _ _ (oflistK s)) undup_id /s 2:size_cat //.
rewrite cat_uniq ?uniq_elems /= -implybF => /hasP [x [Bx Ax]].
by have:= h x; rewrite in_fsetI in_fset0 !memE Bx Ax.
qed.
lemma fcardUI (A B : 'a fset) :
card (A `|` B) + card (A `&` B) = card A + card B.
proof.
rewrite -(fsetID (A `|` B) A) fsetUK (fsetUC A B) fsetDK.
rewrite fcardUI_indep.
+ by rewrite fsetIDA fsetDIl fsetDv fset0I.
by rewrite addzAC fsetIC -addzA -fcardUI_indep ?fsetID ?fsetII.
qed.
(* -------------------------------------------------------------------- *)
lemma nosmt fcardU (A B : 'a fset) :
card (A `|` B) = card A + card B - card (A `&` B).
proof. by rewrite -fcardUI Ring.IntID.addrK. qed.
lemma nosmt fcardI (A B : 'a fset) :
card (A `&` B) = card A + card B - card (A `|` B).
proof. by rewrite -fcardUI addzAC subzz. qed.
(* -------------------------------------------------------------------- *)
lemma nosmt fcardID (A B : 'a fset) :
card (A `&` B) + card (A `\` B) = card A.
proof. by rewrite -fcardUI_indep ?fsetID // fsetII. qed.
lemma nosmt fcardD (A B : 'a fset) :
card (A `\` B) = card A - card (A `&` B).
proof. by rewrite -(fcardID A B) addzAC subzz. qed.
(* -------------------------------------------------------------------- *)
lemma nosmt fcardD1 (A : 'a fset) (x : 'a) :
card A = card (A `\` fset1 x) + (if mem A x then 1 else 0).
proof.
(* FIXME: This feels like it wasn't thought about very deeply... *)
case: (mem A x) => Ax //=; last first.
+ congr; apply/fsetP=> y; rewrite !inE.
by move: Ax; case: (mem A y); case: (y = x).
rewrite -(fcard1 x) -fcardUI addzC eq_sym eq_fcards0 /=.
+ by apply/fsetP=> y; rewrite !inE; case: (y = x).
by congr; apply/fsetP=> y; rewrite !inE; case: (y = x).
qed.
(* -------------------------------------------------------------------- *)
lemma subset_fsetU_id (A B : 'a fset) :
A \subset B => A `|` B = B.
proof.
move=> A_le_B; apply/fsetP=> x; rewrite in_fsetU.
by split=> [[/A_le_B|->]|->].
qed.
lemma subset_fsetI_id (A B : 'a fset) :
B \subset A => A `&` B = B.
proof.
move=> B_le_A; apply/fsetP=> x; rewrite in_fsetI.
by split=> [[_ ->]|^x_in_B /B_le_A].
qed.
lemma subset_leq_fcard (A B : 'a fset) :
A \subset B => card A <= card B.
proof.
move=> /subsetP le_AB; rewrite -(fcardID B A).
have ->: B `&` A = A; 1: apply/fsetP=> x.
by rewrite in_fsetI andb_idl //; apply/le_AB.
by apply/ler_addl; apply/fcard_ge0.
qed.
(* -------------------------------------------------------------------- *)
lemma subset_cardP (A B : 'a fset) :
card A = card B => (A = B <=> A \subset B).
proof. (* FIXME: views *)
move=> eqcAB; split=> [->// |]; rewrite eqEsubset.
move=> le_AB; split=> // x Bx; case: (mem A x) => // Ax.
rewrite -(ltrr (card A)) {2}eqcAB (fcardD1 B x) Bx /=.
rewrite addzC -lez_add1r ler_add //; apply/subset_leq_fcard.
apply/subsetP=> y Ay; rewrite !inE le_AB //=; move: Ax.
by apply/absurd=> /= <-.
qed.
(* -------------------------------------------------------------------- *)
lemma nosmt eqEcard (A B : 'a fset) :
(A = B) <=> (A \subset B) /\ (card B <= card A).
proof.
split=> [->// |]; case=> le_AB le_cAB; rewrite subset_cardP //.
by rewrite eqr_le le_cAB /=; apply/subset_leq_fcard.
qed.
(* -------------------------------------------------------------------- *)
lemma fcard_eq0 (A : 'a fset) : (card A = 0) <=> (A = fset0).
proof.
split=> [z_cA|]; last by move=> ->; apply/fcards0.
rewrite eq_sym eqEcard z_cA fcards0 //=; apply/sub0set.
qed.
(* -------------------------------------------------------------------- *)
op image (f: 'a -> 'b) (A : 'a fset): 'b fset = oflist (map f (elems A))
axiomatized by imageE.
lemma imageP (f : 'a -> 'b) (A : 'a fset) (b : 'b):
mem (image f A) b <=> (exists a, mem A a /\ f a = b).
proof.
rewrite imageE mem_oflist mapP; split.
by move=> [a] [x_in_A ->]; exists a; rewrite memE.
by move=> [a] [x_in_A <-]; exists a; rewrite -memE.
qed.
lemma mem_image (f:'a->'b) (s:'a fset) x:
mem s x => mem (image f s) (f x).
proof. by rewrite imageP=> ?;exists x. qed.
lemma nosmt image0 (f : 'a -> 'b): image f fset0 = fset0.
proof.
by apply/fsetP=> b; rewrite imageP; split=> [[a]|]; rewrite in_fset0.
qed.
lemma nosmt image1 (f : 'a -> 'b) (a : 'a):
image f (fset1 a) = fset1 (f a).
proof.
apply/fsetP=> b; rewrite imageP in_fset1.
by split=> [[a']|->]; [|exists a]; rewrite in_fset1.
qed.
lemma nosmt imageU (f : 'a -> 'b) (A B : 'a fset):
image f (A `|` B) = image f A `|` image f B.
proof.
apply/fsetP=> x; rewrite in_fsetU !imageP; split.
by move=> [x']; rewrite in_fsetU=> -[[x'_in_A|x'_in_B] <-];
[left|right]; exists x'.
by move=> [[x'] [x'_in_X] <-|[x'] [x'_in_X] <-];
exists x'; rewrite in_fsetU x'_in_X.
qed.
lemma nosmt imageI (f : 'a -> 'b) (A B : 'a fset):
image f (A `&` B) \subset image f A `&` image f B.
proof.
move=> x; rewrite !inE !imageP=> -[a].
rewrite !inE=> -[[a_in_A a_in_B] <-].
by split; exists a.
qed.
lemma nosmt imageD (f : 'a -> 'b) (A B : 'a fset):
image f A `\` image f B \subset image f (A `\` B).
proof.
move=> x; rewrite !inE !imageP=> -[[a] [a_in_A <-]].
move=> h; exists a; rewrite !inE a_in_A /= -negP=> a_in_B.
by move: h=> /=; exists a.
qed.
(* -------------------------------------------------------------------- *)
lemma nosmt fcard_image_leq (f : 'a -> 'b) (A : 'a fset):
card (image f A) <= card A.
proof.
elim/fset_ind: A=> [|x A x_notin_A ih]; 1: by rewrite image0 !fcards0.
rewrite imageU image1 (lez_trans (card (image f A) + 1)).
by rewrite fcardU fcard1 ler_naddr 1:oppr_le0 1:fcard_ge0.
rewrite fcardU fsetI1 x_notin_A fcards0 fcard1 oppz0 addz0.
by rewrite ler_add2r.
qed.
(* -------------------------------------------------------------------- *)
op product (A : 'a fset) (B : 'b fset): ('a * 'b) fset =
oflist (flatten (map (fun a => map (fun b => (a,b)) (elems B)) (elems A)))
axiomatized by productE.
lemma productP (A : 'a fset) (B : 'b fset) (a : 'a) (b : 'b):
mem (product A B) (a,b) <=> mem A a /\ mem B b.
proof.
rewrite productE -{2}(elemsK A) -{2}(elemsK B) !mem_oflist /flatten.
elim (elems A) (elems B) a b=> {A B} [//=|].
move=> a' A ih B a b /=; rewrite mem_cat mapP ih /=.
case (a = a')=> [->|] //=.
split=> [[[b']|] //=|b_in_B].
by left; exists b.
qed.
(* -------------------------------------------------------------------- *)
op fold (f : 'a -> 'b -> 'b) (z : 'b) (A : 'a fset) : 'b =
foldr f z (elems A)
axiomatized by foldE.
lemma fold0 (f : 'a -> 'b -> 'b) (z : 'b): fold f z fset0 = z.
proof. by rewrite foldE elems_fset0. qed.
lemma fold1 (f : 'a -> 'b -> 'b) (z : 'b) (a : 'a):
fold f z (fset1 a) = f a z.
proof. by rewrite foldE elems_fset1. qed.
lemma foldC (a : 'a) (f : 'a -> 'b -> 'b) (z : 'b) (A : 'a fset):
(forall a a' b, f a (f a' b) = f a' (f a b)) =>
mem A a =>
fold f z A = f a (fold f z (A `\` fset1 a)).
proof.
move=> f_commutative a_in_A; rewrite !foldE (foldr_rem a)// 1:-memE//.
congr; apply/foldr_perm=> //.
rewrite setDE rem_filter 1:uniq_elems//.
have ->: predC (mem (fset1 a)) = predC1 a (* FIXME: views *)
by apply/fun_ext=> x; rewrite /predC /predC1 in_fset1.
rewrite -{1}(undup_id (filter (predC1 a) (elems A))) 2:oflistK//.
by apply/filter_uniq/uniq_elems.
qed.
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...