From VLSM.Lib Require Import Itauto.
From stdpp Require Import prelude.

Utility: Std++ List Sets


Section sec_fst_defs.

Context `{EqDecision A}.

Definition set list A.

Definition empty_set : set [].

Fixpoint set_add (a : A) (x : set) : set
  match x with
  | [] [a]
  | if decide (a = ) then else set_add a
  end.

Fixpoint set_remove (a : A) (x : set) : set
  match x with
  | [] empty_set
  | if decide (a = ) then else set_remove a
  end.

Fixpoint set_union (x y : set) : set
  match y with
  | [] x
  | set_add (set_union x )
  end.

Fixpoint set_diff (x y : set) : set
  match x with
  | [] []
  | if decide ( y) then set_diff y else set_add (set_diff y)
  end.

Lemma set_add_intro1 :
   (a b : A) (x : set), a x a set_add b x.
Proof.
  induction x; cbn.
  - by inversion 1.
  - by destruct (decide (b = )); rewrite !elem_of_cons; itauto.
Qed.


Lemma set_add_intro2 :
   (a b : A) (x : set), a = b a set_add b x.
Proof.
  induction x; cbn.
  - by rewrite elem_of_cons; left.
  - by intros ; destruct (decide (b = )); rewrite !elem_of_cons; itauto.
Qed.


#[local] Hint Resolve set_add_intro1 set_add_intro2 : core.

Lemma set_add_intro :
   (a b : A) (x : set), a = b a x a set_add b x.
Proof.
  by intros a b x [ | ]; auto.
Qed.


Lemma set_add_elim :
   (a b : A) (x : set), a set_add b x a = b a x.
Proof.
  induction x; cbn.
  - by rewrite elem_of_cons.
  - by destruct (decide (b = )); rewrite !elem_of_cons; itauto.
Qed.


Lemma set_add_not_empty :
   (a : A) (x : set), set_add a x empty_set.
Proof.
  by induction x as [| a' x']; cbn; [| destruct (decide (a = a'))].
Qed.


Lemma set_add_iff a b l :
  a set_add b l a = b a l.
Proof.
  split.
  - by apply set_add_elim.
  - by apply set_add_intro.
Qed.


Lemma set_add_nodup a l :
  NoDup l NoDup (set_add a l).
Proof.
  induction 1 as [| x l H H' IH]; cbn.
  - by constructor; [inversion 1 | apply NoDup_nil].
  - by destruct (decide (a = x)) as [ | Hax]; constructor
    ; rewrite ?set_add_iff; itauto.
Qed.


Lemma set_remove_1 (a b : A) (l : set) :
  a set_remove b l a l.
Proof.
  induction l as [| x xs Hrec]; cbn; [done |].
  by destruct (decide (b = x)); rewrite !elem_of_cons; itauto.
Qed.


Lemma set_remove_2 (a b : A) (l : set) :
  NoDup l a set_remove b l a b.
Proof.
  induction l as [| x l IH]; intro Hnd; cbn; [by inversion 1 |].
  inversion_clear Hnd.
  destruct (decide (b = x)) as [ | Hbx].
  - by intros Ha .
  - by rewrite elem_of_cons; firstorder subst.
Qed.


Lemma set_remove_3 (a b : A) (l : set) :
  a l a b a set_remove b l.
Proof.
  induction l as [| x xs Hrec]; cbn.
  - by inversion 1.
  - by destruct (decide (b = x)) as [ | Hbx]; rewrite !elem_of_cons; itauto.
Qed.


Lemma set_remove_iff (a b : A) (l : set) :
  NoDup l a set_remove b l a l a b.
Proof.
  repeat split.
  - by eapply set_remove_1.
  - by eapply set_remove_2.
  - by destruct 1; apply set_remove_3.
Qed.


Lemma set_remove_nodup a l
  : NoDup l NoDup (set_remove a l).
Proof.
  induction 1 as [| x l H H' IH]; cbn; [by constructor |].
  destruct (decide (a = x)) as [ | Hax]; [done |].
  constructor; [| done].
  by rewrite set_remove_iff; itauto.
Qed.


Lemma set_union_intro :
   (a : A) (x y : set),
    a x a y a set_union x y.
Proof.
  induction y; cbn.
  - by rewrite elem_of_nil; itauto.
  - by rewrite elem_of_cons, set_add_iff; itauto.
Qed.


Lemma set_union_elim :
   (a : A) (x y : set),
    a set_union x y a x a y.
Proof.
  by induction y; cbn; rewrite ?elem_of_cons, ?set_add_iff; itauto.
Qed.


Lemma set_union_iff a l l' :
  a set_union l l' a l a l'.
Proof.
  split.
  - by apply set_union_elim.
  - by apply set_union_intro.
Qed.


Lemma set_union_nodup l l' :
  NoDup l NoDup l' NoDup (set_union l l').
Proof.
  by induction 2 as [| x' l' ? ? IH]; cbn; [| apply set_add_nodup].
Qed.


Lemma set_diff_intro :
   (a : A) (x y : set),
    a x a y a set_diff x y.
Proof.
  induction x; cbn; [by inversion 1 |].
  by intros y; destruct (decide ( y));
    rewrite elem_of_cons, ?set_add_iff; firstorder congruence.
Qed.


Lemma set_diff_elim1 :
   (a : A) (x y : set),
    a set_diff x y a x.
Proof.
  induction x; cbn; [done |]; intros y.
  by destruct (decide ( y)); rewrite elem_of_cons, ?set_add_iff; firstorder.
Qed.


Lemma set_diff_elim2 :
   (a : A) (x y : set), a set_diff x y a y.
Proof.
  induction x; cbn; [by inversion 1 |].
  by intros y; destruct (decide ( y)); rewrite ?set_add_iff; firstorder congruence.
Qed.


Lemma set_diff_iff a l l' :
  a set_diff l l' a l a l'.
Proof.
  split.
  - by eauto using set_diff_elim1, set_diff_elim2.
  - by destruct 1; apply set_diff_intro.
Qed.


Lemma set_diff_nodup l l' :
  NoDup l NoDup (set_diff l l').
Proof.
  induction 1 as [| x l H H' IH]; cbn.
  - by constructor.
  - by case_decide; [| apply set_add_nodup].
Qed.


End sec_fst_defs.

Arguments set : clear implicits.

Section sec_other_defs.

Definition set_prod : {A B : Type}, set A set B set (A B)
  list_prod.

Definition set_fold_right {A B : Type} (f : A B B) (x : set A) (b : B) : B
  fold_right f b x.

Definition set_map {A B : Type} `{EqDecision B} (f : A B) (x : set A) : set B
  set_fold_right (fun a set_add (f a)) x empty_set.

End sec_other_defs.