CubicPathwidth.Alg.Proofs.G2AddEdge
Source file CubicPathwidth/Alg/Proofs/G2AddEdge.lean of the Lean project (how it is built).
import CubicPathwidth.Alg.Spec
/-!
# G2: `addEdge` preserves well-formedness and adjacency (task G2)
Proves `AddEdgeSpec` for `Graph.addEdge`. Helpers live in `CubicPathwidth.Alg.G2`.
-/
namespace CubicPathwidth.Alg
open Graph
namespace G2
/-- `addNode` does not change any neighbour list (a fresh node has list `[]`). -/
theorem nbrs_addNode (G : Graph) (w x : Nat) : (G.addNode w).nbrs x = G.nbrs x := by
unfold addNode
split
· rfl
· rename_i hw
have hw' : G.adj.contains w = false := by simpa [Graph.mem] using hw
unfold Graph.nbrs
rw [Std.HashMap.getD_insert]
by_cases hx : w = x
· subst hx
simp [Std.HashMap.getD_eq_fallback_of_contains_eq_false hw']
· have h2 : (w == x) = false := by simpa using hx
simp [h2]
theorem mem_addNode_iff (G : Graph) (w x : Nat) :
(G.addNode w).mem x = true ↔ G.mem x = true ∨ x = w := by
unfold addNode
split
· rename_i hw
constructor
· intro h; exact Or.inl h
· rintro (h | h)
· exact h
· subst h; exact hw
· simp only [Graph.mem, Std.HashMap.contains_insert, Bool.or_eq_true, beq_iff_eq]
constructor
· rintro (h | h)
· exact Or.inr h.symm
· exact Or.inl h
· rintro (h | h)
· exact Or.inr h
· exact Or.inl h.symm
theorem nodes_addNode_iff (G : Graph) (hG : G.WF) (w x : Nat) :
x ∈ (G.addNode w).nodes ↔ x ∈ G.nodes ∨ x = w := by
unfold addNode
split
· rename_i hw
have hwn : w ∈ G.nodes := (hG.mem_iff w).1 hw
constructor
· exact Or.inl
· rintro (h | h)
· exact h
· subst h; exact hwn
· simp
theorem nodup_addNode (G : Graph) (hG : G.WF) (w : Nat) : (G.addNode w).nodes.Nodup := by
unfold addNode
split
· exact hG.nodup
· rename_i hw
have hw' : w ∉ G.nodes := fun h => by
have := (hG.mem_iff w).2 h
simp_all
show (G.nodes ++ [w]).Nodup
rw [List.nodup_append]
refine ⟨hG.nodup, by simp, ?_⟩
intro a ha b hb
simp only [List.mem_singleton] at hb
subst hb
intro h
exact hw' (h ▸ ha)
theorem wf_addNode (G : Graph) (hG : G.WF) (w : Nat) : (G.addNode w).WF := by
refine ⟨nodup_addNode G hG w, ?_, ?_, ?_, ?_, ?_⟩
· intro x
rw [mem_addNode_iff, nodes_addNode_iff G hG, hG.mem_iff x]
· intro x
rw [nbrs_addNode]
exact hG.nbrs_nodup x
· intro u v h
rw [nbrs_addNode] at h
rw [nodes_addNode_iff G hG]
exact Or.inl (hG.nbrs_sub u v h)
· intro u v h
rw [nbrs_addNode] at h ⊢
exact hG.symm u v h
· intro v
rw [nbrs_addNode]
exact hG.loopless v
/-- `appendNbr` leaves the node list unchanged. -/
theorem nodes_appendNbr (G : Graph) (u v : Nat) : (G.appendNbr u v).nodes = G.nodes := by
dsimp only [appendNbr]
split <;> rfl
/-- `appendNbr` changes only the list of `u`, by appending `v` if absent. -/
theorem nbrs_appendNbr (G : Graph) (u v x : Nat) :
(G.appendNbr u v).nbrs x =
if x = u then (if v ∈ G.nbrs u then G.nbrs u else G.nbrs u ++ [v]) else G.nbrs x := by
dsimp only [appendNbr]
by_cases hc : (G.nbrs u).contains v = true
· have hm : v ∈ G.nbrs u := by simpa using hc
simp only [hc, ite_true, hm]
by_cases hx : x = u
· simp [hx]
· simp [hx]
· have hc' : (G.nbrs u).contains v = false := by simpa using hc
have hm : v ∉ G.nbrs u := fun h => hc (by simpa using h)
simp only [hc', Bool.false_eq_true, ite_false, hm]
unfold Graph.nbrs
by_cases hx : x = u
· subst hx
simp [Std.HashMap.getD_insert]
· have h2 : (u == x) = false := by simpa using (Ne.symm hx)
simp [Std.HashMap.getD_insert, h2, hx]
/-- Membership in a neighbour list after appending `a` if absent. -/
theorem mem_ins (L : List Nat) (a y : Nat) :
y ∈ (if a ∈ L then L else L ++ [a]) ↔ (y ∈ L ∨ y = a) := by
split_ifs with h
· constructor
· exact Or.inl
· rintro (h' | rfl)
· exact h'
· exact h
· simp
theorem nodup_ins (L : List Nat) (a : Nat) (h : L.Nodup) :
(if a ∈ L then L else L ++ [a]).Nodup := by
split_ifs with ha
· exact h
· rw [List.nodup_append]
refine ⟨h, by simp, ?_⟩
intro x hx y hy
simp only [List.mem_singleton] at hy
subst hy
intro e
exact ha (e ▸ hx)
/-- The neighbour lists of `addEdge u v` for distinct `u v`. -/
theorem nbrs_addEdge (G : Graph) (u v : Nat) (huv : u ≠ v) (x : Nat) :
(G.addEdge u v).nbrs x =
if x = u then (if v ∈ G.nbrs u then G.nbrs u else G.nbrs u ++ [v])
else if x = v then (if u ∈ G.nbrs v then G.nbrs v else G.nbrs v ++ [u])
else G.nbrs x := by
have huv' : v ≠ u := fun h => huv h.symm
unfold addEdge
simp only [nbrs_appendNbr, nbrs_addNode]
by_cases hxu : x = u
· simp [hxu, huv, huv']
· by_cases hxv : x = v
· simp [hxv, hxu, huv, huv']
· simp [hxu, hxv]
theorem adj_addEdge (G : Graph) (u v : Nat) (huv : u ≠ v) (x y : Nat) :
(G.addEdge u v).Adj x y ↔ G.Adj x y ∨ (x = u ∧ y = v) ∨ (x = v ∧ y = u) := by
unfold Graph.Adj
rw [nbrs_addEdge G u v huv x]
by_cases hxu : x = u
· rw [if_pos hxu, mem_ins]
simp [hxu, huv]
· by_cases hxv : x = v
· rw [if_neg hxu, if_pos hxv, mem_ins]
simp [hxv, huv.symm]
· rw [if_neg hxu, if_neg hxv]
simp [hxu, hxv]
theorem nodes_addEdge_iff (G : Graph) (hG : G.WF) (u v : Nat) (x : Nat) :
x ∈ (G.addEdge u v).nodes ↔ x ∈ G.nodes ∨ x = u ∨ x = v := by
unfold addEdge
rw [nodes_appendNbr, nodes_appendNbr, nodes_addNode_iff _ (wf_addNode G hG u) v,
nodes_addNode_iff G hG u, or_assoc]
theorem mem_appendNbr (G : Graph) (u v x : Nat) (hu : G.mem u = true) :
(G.appendNbr u v).mem x = G.mem x := by
dsimp only [appendNbr]
split
· rfl
· simp only [Graph.mem, Std.HashMap.contains_insert]
by_cases hx : u = x
· subst hx; simp [Graph.mem] at hu ⊢; simp [hu]
· have h2 : (u == x) = false := by simpa using hx
simp [h2]
theorem mem_addEdge_iff (G : Graph) (u v x : Nat) :
(G.addEdge u v).mem x = true ↔ G.mem x = true ∨ x = u ∨ x = v := by
have h1 : (G.addNode u).mem u = true := (mem_addNode_iff _ _ _).2 (Or.inr rfl)
have h2 : ((G.addNode u).addNode v).mem u = true :=
(mem_addNode_iff _ _ _).2 (Or.inl h1)
have h3 : ((G.addNode u).addNode v).mem v = true := (mem_addNode_iff _ _ _).2 (Or.inr rfl)
have h4 : ((G.addNode u).addNode v |>.appendNbr u v).mem v = true := by
rw [mem_appendNbr _ _ _ _ h2]; exact h3
unfold addEdge
rw [mem_appendNbr _ _ _ _ h4, mem_appendNbr _ _ _ _ h2, mem_addNode_iff, mem_addNode_iff,
or_assoc]
theorem addEdge_WF (G : Graph) (hG : G.WF) (u v : Nat) (huv : u ≠ v) :
(G.addEdge u v).WF := by
refine ⟨?_, ?_, ?_, ?_, ?_, ?_⟩
· unfold addEdge
simp only [nodes_appendNbr]
exact nodup_addNode _ (wf_addNode G hG u) v
· intro x
rw [mem_addEdge_iff, nodes_addEdge_iff G hG u v x, hG.mem_iff x]
· intro x
rw [nbrs_addEdge G u v huv x]
by_cases h1 : x = u
· rw [if_pos h1]; exact nodup_ins _ _ (hG.nbrs_nodup u)
· rw [if_neg h1]
by_cases h2 : x = v
· rw [if_pos h2]; exact nodup_ins _ _ (hG.nbrs_nodup v)
· rw [if_neg h2]; exact hG.nbrs_nodup x
· intro x y h
change (G.addEdge u v).Adj x y at h
rw [adj_addEdge G u v huv] at h
rw [nodes_addEdge_iff G hG u v y]
rcases h with h | ⟨rfl, rfl⟩ | ⟨rfl, rfl⟩
· exact Or.inl (hG.nbrs_sub x y h)
· exact Or.inr (Or.inr rfl)
· exact Or.inr (Or.inl rfl)
· intro x y h
change (G.addEdge u v).Adj x y at h
show (G.addEdge u v).Adj y x
rw [adj_addEdge G u v huv] at h ⊢
rcases h with h | ⟨h1, h2⟩ | ⟨h1, h2⟩
· exact Or.inl (hG.symm x y h)
· exact Or.inr (Or.inr ⟨h2, h1⟩)
· exact Or.inr (Or.inl ⟨h2, h1⟩)
· intro x h
change (G.addEdge u v).Adj x x at h
rw [adj_addEdge G u v huv] at h
rcases h with h | ⟨h1, h2⟩ | ⟨h1, h2⟩
· exact hG.loopless x h
· exact huv (h1.symm.trans h2)
· exact huv (h2.symm.trans h1)
end G2
/-- `addEdge` of two distinct vertices (Spec `AddEdgeSpec`). -/
theorem addEdgeSpec : AddEdgeSpec := by
intro G u v hG huv
exact ⟨G2.addEdge_WF G hG u v huv,
fun x => G2.nodes_addEdge_iff G hG u v x,
fun x y => G2.adj_addEdge G u v huv x y⟩
#print axioms CubicPathwidth.Alg.addEdgeSpec
end CubicPathwidth.Alg
Back to top