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).
(** * Subgraph series *)
(** A subgraph series is a list of subgraphs such that later elements are subgraphs of former elements.  *)
Inductive subgraph_series : list graph -> Prop :=
| sg_nil : subgraph_series []
| sg_single : forall g, subgraph_series [g]
| sg_cons : forall g g' l, is_subgraph g' g -> subgraph_series (g' :: l) -> subgraph_series (g :: g' :: l).
(** The subgraphs created by the extraction are a subgraph series *)
(** ** The final graph returned by the vertex extraction is a subgraph. *)
(** ** Max degree 0 implies all vertices have degree 0 *)
(** ** Extracting degree 0 vertices from a max degree 0 graph empties it *)
(** ** Extracting all max degree vertices strictly decreases max degree *)
(** ** Subgraph respects degree of vertices *)
(** ** Non-adjacency of max degree vertices after one step *)
(** If a vertex of max degree is removed from a graph then any vertex with max degree in the new graph cannot be adjacent to it. *)
(** The same as above, but for non-zero degree graphs *)
(** * Independent sets *)
(** An independent set is a set of vertices such that no two are adjacent. *)
Definition independent_set (g : graph) (s : nodeset) :=
forall i j, S.In i s -> S.In j s -> ~ S.In i (adj g j).

(* we would like to have if and only if in the conclusion but unfortunately it's not true while the function is iterating *)
Lemma max_degree_extraction_independent_set0 : forall (g : graph) d,
no_selfloop g ->
d = max_deg g ->
d = 0 ->
independent_set g (fst (extract_vertices_degs g d)) /\
(forall k, S.In k (fst (extract_vertices_degs g d)) -> degree k g = Some d).