Module WP := WProperties_fun E M.  (* More useful stuff about maps *)
Print Module WF.
Print Module WP.
Check E.lt. (*   : positive -> positive -> Prop *)
(** [E.lt] is a comparison predicate on [positive] numbers.  It is _not_ the usual less-than operator; it is a different ordering that is more compatible with the order that a Positive Trie arranges its keys.  In the application of certain lemmas about maps and sets, we will need the facts that [E.lt] is a [StrictOrder] (irreflexive and transitive) and respects a congruence over equality (is [Proper] for [eq ==> eq ==> iff]).   As shown here, we just have to dig up these facts from a submodule of a submodule of a submodule of [M]. *)
(* ================================================================= *)
(** ** SortA_equivlistA_eqlistA  Suppose two lists [al,bl] are "equivalent:" they contain the same set of elements (modulo an equivalence relation [eqA] on elements, perhaps in different orders, and perhaps with different numbers of repetitions).  That is, suppose [equivlistA eqA al bl].  And suppose list [al] is sorted, in some strict total order (respecting the same equivalence relation [eqA]).  And suppose list [bl] is sorted.  Then the lists must be _equal_ (modulo [eqA]).  Just to make this easier to think about, suppose [eqA] is just ordinary equality. Then if [al] and [bl] contain the same set of elements (perhaps reordered), and each list is sorted (by _less-than_, not by _less-or-equal_), then they must be equal.  Obviously.  That's what the theorem [SortA_equivlistA_eqlistA] says, in the Coq library: *)
Check SortA_equivlistA_eqlistA.    (*
: forall (A : Type) (eqA : A -> A -> Prop),
Equivalence eqA ->
forall ltA : A -> A -> Prop,
StrictOrder ltA ->
Proper (eqA ==> eqA ==> iff) ltA ->
forall l l' : list A,
Sorted ltA l ->
Sorted ltA l' -> equivlistA eqA l l' -> eqlistA eqA l l'  *)
(** That is, suppose [eqA] is an equivalence relation on type [A], that is, [eqA] is reflexive, symmetric, and transitive.  And suppose [ltA] is a strict order, that is, irreflexive and transitive.   And suppose [ltA] respects the equivalence relation, that is, if [eqA x x'] and [eqA y y'], then [ltA x y <-> ltA x' y']. THEN, if [l] is sorted (using the comparison [ltA]), and l' is sorted, and [l,l'] contain equivalent sets of elements, then [l,l'] must be equal lists, modulo the equivalence relation.  To make this easier to think about, let's use ordinary equality for eqA. We will be making sets and maps over the "node" type, [E.t], but that's just type [positive].  Therefore, the equivalence [E.eq: E.t -> E.t -> Prop] is just the same as [eq]. *)
Goal E.t = positive.  Proof. reflexivity. Qed.
Goal E.eq = @eq positive.  Proof. reflexivity. Qed.
(** And therefore, [eqlistA E.eq al bl] means the same as [al=bl]. *)
(** So now, the theorem:  if [al] and [bl] are sorted, and contain "the same" elements, then they are equal: *)
(** If list [l] is sorted, and you apply [List.filter] to remove the elements on which [f] is [false], then the result is still sorted.  Obviously.  *)
(* ================================================================= *)
(** ** S.remove and S.elements  The [FSets] interface (and therefore our [Module S]) provides these two functions: *)
Check S.remove.  (* : S.elt -> S.t -> S.t *)
Check S.elements. (* : S.t -> list S.elt *)
(** In module [S], of course, [S.elt=positive], as these are sets of positive numbers.  Now, this relationship between [S.remove] and [S.elements] will soon be useful: *)
Abort.  (* Before we prove that, there is some preliminary work to do. *)
(** That is, if [i] is in the set [s], then the elements of [S.remove i s] is the list that you get by filtering [i] out of [S.elements s].  Go ahead and prove it! *)
(** [] *)
(* ================================================================= *)
(** ** Lists of (key,value) Pairs *)
(** The elements of a finite map from positives to type A (that is, the [M.elements] of a [M.t A]) is a list of pairs [(positive*A)]. *)
Check M.elements. (*  : forall A : Type, M.t A -> list (positive * A) *)
(** Let's start with a little lemma about lists of pairs:  Suppose [l: list (positive*A)]. Then [j] is in [map fst l]   iff   there is some e such that (j,e) is in l. *)
(** [] *)
(** **** Exercise: 3 stars, standard (Sorted_lt_key)  The function [M.lt_key] compares two elements of an [M.elements] list, that is, two pairs of type [positive*A], by just comparing their first elements using [E.lt].  Therefore, an elements list (of type [list(positive*A)] is [Sorted] by [M.lt_key] iff its list-of-first-elements is [Sorted] by [E.lt]. *)
(** [] *)
(* ================================================================= *)
(** ** Cardinality *)
(** The _cardinality_ of a set is the number of distinct elements. The cardinality of a finite map is, essentially, the cardinality of its domain set. *)
(** [] *)
(** [] *)
(** We have a lemma [SortA_equivlistA_eqlistA] that talks about arbitrary equivalence relations and arbitrary total-order relations (as long as they are compatible.  Here is a specialization to a particular equivalence ([M.eq_key_elt]) and order ([M.lt_key]). *)
(* Hints: *)
Check specialize_SortA_equivlistA_eqlistA.
Check M.elements_1.
Check M.elements_2.
Check M.elements_3.
Check M.remove_1.
Check M.eqke_equiv.
Check M.ltk_strorder.
Check Proper_eq_key_elt.
Check filter_InA.
(* FILL IN HERE *) Admitted. (** [] *)
(** [] *)
(** [] *)
(* ################################################################# *)
(** * Now Begins the Graph Coloring Program *)
Definition node := E.t.
Definition nodeset := S.t.
Definition nodemap: Type -> Type := M.t.
Definition graph := nodemap nodeset.
Definition adj (g: graph) (i: node) : nodeset :=
match M.find i g with Some a => a | None => S.empty end.
Definition undirected (g: graph) :=
forall i j, S.In j (adj g i) -> S.In i (adj g j).
Definition no_selfloop (g: graph) := forall i, ~ S.In i (adj g i).
Definition nodes (g: graph) := Mdomain g.
Definition subset_nodes
(P: node -> nodeset -> bool)
(g: graph) := Mdomain (WP.filter P g).
(** A node has "low degree" if the cardinality of its adjacency set is less than [K] *)
Definition low_deg (K: nat) (n: node) (adj: nodeset) : bool := S.cardinal adj <? K.
Definition remove_node (n: node) (g: graph) : graph :=
M.map (S.remove n) (M.remove n g).
(* ================================================================= *)
(** ** Some Proofs in Support of Termination  We need to prove some lemmas related to the termination of the algorithm before we can actually define the [Function]. *)
(** [] *)

(** **** Exercise: 3 stars, standard (select_terminates)  *)
Lemma select_terminates:
forall (K: nat) (g : graph) (n : S.elt),
S.choose (subset_nodes (low_deg K) g) = Some n ->
M.cardinal (remove_node n g) < M.cardinal g.