(*************************************************************************)
(* Copyright (C) 2013 - 2015                                             *)
(* Author C. Cohen                                                       *)
(* DRAFT - PLEASE USE WITH CAUTION                                       *)
(* License CeCILL-B                                                      *)
(*************************************************************************)
From mathcomp
From mathcomp
From mathcomp
(*****************************************************************************)
(* This file provides representations for finite sets over a choiceType K,   *)
(* finite maps with keys in a choiceType K and the values in an arbitrary    *)
(* type V, and total functions from K to V with finite support.              *)
(* The domain (resp. support) of a finite map (resp. fintely supported       *)
(* function) is a finite set, and so is the codomain (resp. image) when V    *)
(* is a choice type.                                                         *)
(*                                                                           *)
(*                {fset K} == finite sets of elements of K                   *)
(*           {fmap K -> V} == finitely supported maps from K to V.           *)
(* {fsfun K -> T for dflt} == finitely supported functions                   *)
(*                     with default value dflt : K -> V outside the support  *)
(*                                                                           *)
(********* finite sets *******************************************************)
(*                                                                           *)
(* In the remainder, A and B are of type {fset K}.                           *)
(*                                                                           *)
(* - {fset K} is provided with a canonical structure of predType, in order   *)
(*   to enable the notation "a \in A"                                        *)
(* - There is a coercion from {fset K} to Type in order to interpret any     *)
(*   finset A as the subType of elements a : K such that a \in A.            *)
(*   Because of this coercion, writing a : A makes sense.                    *)
(*                                                                           *)
(* The following notations are in the %fset scope                            *)
(*            fset0 == the empty finite set                                  *)
(*         [fset k] == the singleton finite set {k}                          *)
(*          A `&` B == the intersection of A and B                           *)
(*          A `|` B == the union of A and B                                  *)
(*           a |` B == the union of singleton a and B                        *)
(*          A `\` B == the complement of B in A                              *)
(*           A `\ b == A without b                                           *)
(*          A `*` B == the cartesian product of A and B                      *)
(* [disjoint A & B] := A `&` B == 0                                          *)
(*         A `<=` B == A is a subset of B                                    *)
(*          A `<` B == A is a proper subset of B                             *)
(*            #|`A| == cardinal of A                                         *)
(*    fincl AsubB a == turns a : A  into an element of B                     *)
(*                     using a proof AsubB of A \fsubset B                   *)
(*         fsub B A == turns A : {fset K} into a {set B}                     *)
(*           f @` A == the image set of the collective predicate A by f.     *)
(*      f @2`(A, B) == the image set of A x B by the binary function f.      *)
(*                                                                           *)
(* In order to support the following notations, we introduce three canonical *)
(* structure that reflect the finiteness of a predicate, in the following    *)
(* notations, p (resp q) are such finite predicates, which are ultimately    *)
(* represented by elements A (resp B) from {fset K}.                         *)
(*                                                                           *)
(*    [fset x in p | P] == the set of all x of type K, such that             *)
(*                         x \in p and P x where P is a predicate on K       *)
(*  [fset x in p | P & Q] := [set x in p | P && Q].                          *)
(*                                                                           *)
(* [fset E | x in p] == the set of all the values of the expression E, for x *)
(*                     drawn from the collective finite predicate p.         *)
(* [fset E | x in p & P] == the set of values of E for x drawn from p, such  *)
(*                     that P is true.                                       *)
(* [fset E | x in p, y in q] == the set of values of E for x drawn from p and*)
(*                     and y drawn from q; q may depend on x.                *)
(* [fset E | x in p, y in q & P] == the set of values of E for x drawn from  *)
(*                    p and y drawn from q; such that P is true.             *)
(* [fsetval x in p] == the set of (val x) for x in the finite predicate p    *)
(* [fsetval x in p | P ] == the set of (val x) for x in p, such that P       *)
(* [fsetval x in p | P & Q] := [fsetval x in p | P && Q]                     *)
(*                                                                           *)
(* For each notation above, there is an additional one with ':' instead of   *)
(* 'in' which is used to range over the finite type A instead of the finite  *)
(* set A, and the optional predicate is over A instead of K                  *)
(* For example:                                                              *)
(*    [fset x : A | P] := [fset x in {: A} | P]                              *)
(*                     == the set of all x of type A, such that P x          *)
(* [fset E | x : A] == the set of all the values of the expression E, for x  *)
(*                     drawn from the finite type A                          *)
(*                                                                           *)
(* For each [fset ...] or [fsetval ...] notation, there is a keyed variant   *)
(* written [fset[key] ...] or [fsetval[key] ...] for locking                 *)
(******* finite maps *********************************************************)
(*                                                                           *)
(* Operations on finmap:                                                     *)
(* The following notations are in the %fmap scope                            *)
(*                                                                           *)
(*           f.[? k] == returns Some v if k maps to v, otherwise None        *)
(*             f.[p] == returns v if p has type k \in f, and k maps to v     *)
(*        f.[k <- v] == f extended with the mapping k -> v                   *)
(*            domf f == finite set (of type {fset K}) of keys of f           *)
(*          codomf f == finite set (of type {fset V}) of values of f         *)
(*           k \in f == k is a key of f                                      *)
(*                   := k \in domf f                                         *)
(*            [fmap] == the empty finite map                                 *)
(* [fmap x : S => E] == the finmap defined by E on the support S             *)
(*           f.[& A] == f restricted to A (intersected with domf f)          *)
(*           f.[\ A] := f.[& domf `\` A]                                     *)
(*                   == f where all the keys in A have been removed          *)
(*           f.[~ k] := f.[\ [fset k]]                                       *)
(*             f + g == concatenation of f and g,                            *)
(*                      the keys of g override the keys of f                 *)
(*                                                                           *)
(******* finitely supported functions ****************************************)
(*                                                                           *)
(* Operation on function with finite support, i.e. finmap with default value *)
(* for elements outside of the support. Contrarly to finmap, these are total *)
(* function, so we provide a coercion to Funclass                            *)
(*                                                                           *)
(* {fsfun K -> T for dflt} == finitely supported functions with default      *)
(*                            value dflt : K -> V outside the support        *)
(* {fsfun K -> T of x => dflt} :=  {fsfun K -> T for fun x => dflt}          *)
(*    {fsfun K -> T with dflt} :=  {fsfun K -> T for fun=> dflt}             *)
(*              {fsfun K -> K} :=  {fsfun K -> T for fun x => x}             *)
(*                                                                           *)
(*             [fsfun for dflt] == the default fsfun                         *)
(*         [fsfun of x => dflt] == the default fsfun                         *)
(* [fsfun x : A => F | default] == the fsfun which takes value F on A        *)
(*                                    x has type A : {fset T}                *)
(* [fsfun x in A => F | default] == the fsfun which takes value F on A       *)
(*                                     x has type T, where A : {fset T}      *)
(* we also provide untyped variants and variants where default is ommitted   *)
(* e.g.  [fsfun x : A => F] [fsfun x => F | default] [fsfun]...              *)
(* and many variants to give the possibility to insert a key : unit          *)
(* to prevent conversion from diverging, e.g.                                *)
(* [fsfun[key] x : A => F | default] and [fsfun[key] x in A => F | default]  *)
(*                ...                                                        *)
(*     (f \o g)%fsfun == composition of fsfun                                *)
(*     fsinjectiveb f == boolean predicate of injectivity of f               *)
(*****************************************************************************)
Set Implicit Arguments.
Unset Strict Implicit.
Reserved Notation "{fset K }" (at level 0, format "{fset  K }").
Reserved Notation "A `&` B"  (at level 48, left associativity).
Reserved Notation "A `*` B"  (at level 46, left associativity).
Reserved Notation "A `+` B"  (at level 54, left associativity).
Reserved Notation "A +` B"  (at level 54, left associativity).
Reserved Notation "A `|` B" (at level 52, left associativity).
Reserved Notation "a |` A" (at level 52, left associativity).
Reserved Notation "A `\` B" (at level 50, left associativity).
Reserved Notation "A `\ b" (at level 50, left associativity).
Reserved Notation "{fmap T }" (at level 0, format "{fmap  T }").
Reserved Notation "x .[ k <- v ]"
(at level 2, k at level 200, v at level 200, format "x .[ k  <-  v ]").
Reserved Notation "x .[~ k ]" (at level 2, k at level 200, format "x .[~  k ]").
Reserved Notation "x .[& k ]" (at level 2, k at level 200, format "x .[&  k ]").
Reserved Notation "x .[\ k ]" (at level 2, k at level 200, format "x .[\  k ]").
Reserved Notation "x .[? k ]" (at level 2, k at level 200, format "x .[?  k ]").
Reserved Infix "`~`" (at level 52).
Reserved Notation "[ 'fset' k ]" (at level 0, k at level 99, format "[ 'fset'  k ]").
Local Notation predOfType T := (sort_of_simpl_pred (@pred_of_argType T)).
Section extra.

Lemma allsigs_uniq R (f : forall x, T x -> R) s t :
uniq s -> (forall x, x \in s -> uniq (t x)) ->
{in [seq Tagged T y | x <- s & y <- t x] &,
injective (fun p : sigT T => f (tag p) (tagged p))} ->
uniq (allsigs f s t).