MathClasses.interfaces.finite_sets

Require Import
  abstract_algebra interfaces.orders.


Class SetType (A : Type) := set_type: Type.
Arguments set_type _ {SetType}.

Notation EmptySet A := (Bottom (set_type A)).
Notation "∅" := (@bottom (set_type _) _) : mc_scope.
Notation SetEquiv A := (Equiv (set_type A)).
Notation SetJoin A := (Join (set_type A)).
Notation SetMeet A := (Meet (set_type A)).
Notation SetDifference A := (Difference (set_type A)).
Notation SetSingleton A := (Singleton A (set_type A)).
Notation SetLe A := (Le (set_type A)).
Notation SetContains A := (Contains A (set_type A)).

Class FSetExtend A `{t : SetType A} :=
  fset_extend `{Join B} `{Bottom B} : (A B) set_type A B.

Class FSet A `{At : SetType A} `{Ae : Equiv A} `{Ate : SetEquiv A}
   `{Aempty : EmptySet A} `{Ajoin : SetJoin A} `{Asingle : SetSingleton A}
   `{ a₁ a₂ : A, Decision (a₁ = a₂)} `{U : !FSetExtend A} :=
 { fset_bounded_sl :> BoundedJoinSemiLattice (set_type A)
  ; singleton_mor :> Setoid_Morphism singleton
  ; fset_extend_mor `{BoundedJoinSemiLattice B} `{!Setoid_Morphism (f : A B)} :>
      BoundedJoinSemiLattice_Morphism (fset_extend f)
  ; fset_extend_correct `{BoundedJoinSemiLattice B} (f : A B) `{!Setoid_Morphism f} :
      f = fset_extend f singleton
  ; fset_extend_unique `{Equiv B} `{Join B} `{Bottom B} (f : A B) `{!Setoid_Morphism f}
      (h : set_type A B) `{!BoundedJoinSemiLattice_Morphism h} : f = h singleton h = fset_extend f }.

Definition fset_map `(f : A B) `{SetType A} `{SetType B} `{EmptySet B} `{SetJoin B} `{SetSingleton B}
  `{U : !FSetExtend A} : set_type A set_type B := fset_extend (singleton f).


Class FSetContainsSpec A `{At : SetType A} `{Ae : Equiv A} `{Ate : SetEquiv A}
     `{SetLe A} `{SetContains A} `{Ajoin : SetJoin A} `{Asingle : SetSingleton A} :=
  { fset_join_sl_order :> JoinSemiLatticeOrder (≤)
  ; fset_in_singleton_le : x X, x X {{ x }} X }.

Class FullFSet A {car Ae conAe conAle Acontains Aempty Ajoin Asingle U Adec} `{Adiff : SetDifference A} `{Ameet : SetMeet A} :=
  { full_fset_fset :> @FSet A car Ae conAe Aempty Ajoin Asingle U Adec
  ; full_fset_contains :> @FSetContainsSpec A car Ae conAe conAle Acontains Ajoin Asingle
  ; fset_in_meet : X Y x, x X Y (x X x Y)
  ; fset_in_difference : X Y x, x X Y (x X x Y) }.