Global Instance : forall T, Equivalence (@set_eq T).
Definition set_incl {A} (m1 m2 : set A) :=
forall (a : A), m1 a -> m2 a.
Infix "\subset" := set_incl (at level 70, no associativity) : set_scope.
Notation "[ 'set' x : T | P ]" := (fun x : T => P)
(at level 0, x at level 99, only parsing) : set_scope.
Notation "[ 'set' x | P ]" := [set x : _ | P]
(at level 0, x, P at level 99, format "[ 'set'  x  |  P ]", only parsing) : set_scope.
Definition set0 {T} := [set _ : T | False].
Definition setT {T} := [set _ : T | True].
Notation "[ 'set' : T ]" := (@setT T)
(at level 0, format "[ 'set' :  T ]") : set_scope.
Section setOpsDef.
Context {T U : Type}.
Implicit Types (a x : T) (A B : set T).
Definition set1 a := eq a.
Definition setU A B := [set x | x \in A \/ x \in B].
Definition setI A B := [set x | x \in A /\ x \in B].
Definition codom (f : T -> U) := [set y | exists x, f x = y].
Definition bigcup A (F : T -> set U) := [set x | exists i, i \in A /\ x \in F i].
Definition bigcap (A : set T) (F : T -> set U) :=
[set x | forall (i : T), i \in A -> x \in F i].
End setOpsDef.
Definition imset {T U} (f : T -> U) A := bigcup A (fun x => set1 (f x)).
Definition setX T U (A : set T) (B : set U) := [set x | x.1 \in A /\ x.2 \in B].
Definition imset2 T U V (f : T -> U -> V) A1 A2 :=
imset (prod_curry f) (setX A1 A2).
Definition codom2 T U V (f : T -> U -> V) := codom (prod_curry f).
Notation "[ 'set' a ]" := (set1 a)
(at level 0, a at level 99, format "[ 'set'  a ]") : set_scope.
Notation "[ 'set' a : T ]" := [set (a : T)]
(at level 0, a at level 99, format "[ 'set'  a   :  T ]") : set_scope.
Notation "A :|: B" := (setU A B) (at level 52, left associativity) : set_scope.
Notation "a |: A" := ([set a] :|: A) (at level 52, left associativity) : set_scope.
Notation "A :&: B" := (setI A B) (at level 48, left associativity) : set_scope.
Notation "f @: A" := (imset f A) (at level 24) : set_scope.
Notation "f @2: ( A , B )" := (imset2 f A B)
(at level 24, format "f  @2:  ( A ,  B )") : set_scope.
Notation "\bigcup_ i F" := (bigcup setT (fun i => F))
(at level 41, F at level 41, i at level 0,
format "'[' \bigcup_ i '/  '  F ']'") : set_scope.
Notation "\bigcup_ ( i : t ) F" := (bigcup (@setT t) (fun i => F))
(at level 41, F at level 41, i at level 50,
format "'[' \bigcup_ ( i   :  t ) '/  '  F ']'", only parsing) : set_scope.
Notation "\bigcup_ ( i 'in' A ) F" := (bigcup A (fun i => F))
(at level 41, F at level 41, i, A at level 50,
format "'[' \bigcup_ ( i  'in'  A ) '/  '  F ']'") : set_scope.
Notation "\bigcap_ ( i 'in' A ) F" := (bigcap A (fun i => F))
(at level 41, F at level 41, i, A at level 50,
format "'[' \bigcap_ ( i  'in'  A ) '/  '  F ']'") : set_scope.
Definition lift {T} (S : set T) : set (option T) :=
Some @: S :|: [set None].

Lemma imsetT T U (f : T -> U) : f @: setT <--> codom f.