Local Open Scope nat.
(** * Properties of subgraphs and degrees *)
(** ** Subgraph predicate [g'] is a subgraph of [g] if: - the vertex set of [g'] is a subset of the vertex set of [g] - the adjacency set of every [v] in [g'] is a subset of adjacency set of every [v] in [g] *)
Definition is_subgraph (g' g : graph) :=
S.Subset (nodes g') (nodes g) /\ forall v, S.Subset (adj g' v) (adj g v).
(** * Induced subgraphs *)
(** ** Definition *)
Definition subgraph_of (g : graph) (s : S.t) :=
M.fold (fun v adj g' => if S.mem v s then M.add v (S.inter s adj) g' else g') g empty_graph.
(** ** Edges of an induced subgraph are a subset of the original graph *)
(** Note that this is defined pointwise: the adjacency set is a subset for every vertex. *)
(** ** Induced subgraph is subgraph *)
(** * Removal of nodes *)
(** ** Removing a distinct vertex from a graph *)
(** If [i] and [j] are distinct vertices then removing [j] from the graph doesn't affect [i]'s membership. *)
(** If [i] is in the graph with [j] removed then [i] is not equal to [j]. *)
(** ** Removing a node results in a subgraph *)
(** ** Remove a set of vertices from a graph *)
(** To make it easier to prove things about it, - first restrict the graph by [S.diff (Mdomain g) s] - then map subtracting s from every adj set *)
Definition remove_nodes (g : graph) (s : nodeset) :=
M.map (fun ve => S.diff ve s) (restrict g (S.diff (nodes g) s)).
(** ** Every vertex in the removing set is not in the resulting graph *)
(** ** Removing a non-empty set of vertices decreases the size of the graph *)
(** ** Removing a subgraph preserves undirectedness *)
(** ** Removing a subgraph preserves irreflexivity *)
(** ** Removing a node preserves undirectedness *)
(** ** Removing a node preserves irreflexivity *)
(** * Neighborhood of a vertex *)
(** ** Definition of neighbors *)
Definition neighbors (g : graph) v := adj g v.
(** ** Definition of neighborhood*)
(** The (open) neighborhood of a vertex v in a graph consists of the subgraph induced by the vertices adjacent to v.  It does not include v itself. *)
Definition neighborhood (g : graph) v := remove_node v (subgraph_of g (neighbors g v)).
(** ** Neighborhoods do not include the vertex *)
(** ** Neighborhood is a subgraph *)
(** ** Vertices of an induced subgraph are a subset *)
(** If i is in the induced subgraph then i is in the set of inducing vertices. *)
(** ** The adjacency set of any vertex of in an induced subgraph is a subset of the vertex set  *)
(** ** In neighborhood implies in adjacency set *)
(** When is an edge in the induced subgraph? - if [i], [j] in [S] and [(i,j)] in [G] then [(i,j)] in $G|_S$ - if [(i,j)] in $G|_S$ then [(i,j)] in [G] - if [v] in $G|_S$ then [v] in [S] - if [v] in [S] and [v] in [G] then [v] in $G|_S$ *)
(** * Degrees and maximum degrees *)
(** Note that this is a partial function because if the vertex is not in the graph and we return 0, we can't tell whether it's actually in the graph or not. *)
(** ** Degree of a vertex *)
Definition degree (v : node) (g : graph) :=
match M.find v g with
| None => None
| Some a => Some (S.cardinal a)
end.
(** ** Maximum degree of a graph *)
Definition max_deg (g : graph) := list_max (map (fun p => S.cardinal (snd p)) (M.elements g)).
(** ** Inversion lemma for degree *)
(** ** The maximum degree of an empty graph is 0 *)
(** ** Max degree being 0 implies non-adjacency of all vertices **)
(** ** Non-zero max degree implies non-empty graph *)
(** ** Removing vertex decreases degree of neighbors *)
(** ** S.InL and In agree *)
(** ** Subset respects list inclusion of elements *)
(** ** Subgraph relation respects maximum degree *)
(** * Vertex extraction *)
(** ** Definition for a given degree *)
Definition extract_deg_vert (g : graph) (d : nat) :=
find (fun p => Nat.eqb (S.cardinal (snd p)) d) (M.elements g).

(* Annoying lemma *)
Lemma InA_in_iff {A} : forall p (l : list (M.key * A)), (InA (@M.eq_key_elt A) p l) <-> In p l.