CubicPathwidth.Alg.Proofs2.R3Records
Source file CubicPathwidth/Alg/Proofs2/R3Records.lean of the Lean project (how it is built).
import CubicPathwidth.Alg.Plan2
import CubicPathwidth.Alg.Proofs.Targets
/-!
# R3: records respect `SameGraph`; records compose
Task R3 of the formalisation (§6.2). Proves `opsRecordCongr : OpsRecordCongr`
and `opsRecordAppend : OpsRecordAppend` (`Plan2.lean`), using only the Stage 1 contracts
`addEdgeSpec` and `removeNodeSpec` (`Proofs/Targets.lean`) and the statements of
`Spec2.lean`.
Reusable helpers (namespace `CubicPathwidth.Alg.R3`):
* `sameGraph_refl`, `sameGraph_symm`, `sameGraph_trans`;
* `removeNode_congr`, `addEdge_congr`, `addEdge_comm` (for WF graphs);
* `numNodes_eq_of_mem_iff`, `numNodes_removeNode` (`G.removeNode v` has one node less);
* `stepL` (the graph part of `redStep`), `stepL_props` (WF and node count of one
reduction step), `redStep_eq`, `redStep_wf_numNodes`, `redStep_congr`.
-/
noncomputable section
namespace CubicPathwidth.Alg
open Graph
namespace R3
theorem sameGraph_refl (G : Graph) : SameGraph G G :=
⟨fun _ => Iff.rfl, fun _ _ => Iff.rfl⟩
theorem sameGraph_symm {G H : Graph} (h : SameGraph G H) : SameGraph H G :=
⟨fun v => (h.1 v).symm, fun u v => (h.2 u v).symm⟩
theorem sameGraph_trans {G H K : Graph} (h : SameGraph G H) (h' : SameGraph H K) :
SameGraph G K :=
⟨fun v => (h.1 v).trans (h'.1 v), fun u v => (h.2 u v).trans (h'.2 u v)⟩
/-- Removing the same vertex from two graphs with the same nodes and edges. -/
theorem removeNode_congr {G H : Graph} (hG : G.WF) (hH : H.WF) (h : SameGraph G H)
(v : Nat) : SameGraph (G.removeNode v) (H.removeNode v) := by
obtain ⟨_, hn1, ha1⟩ := removeNodeSpec G v hG
obtain ⟨_, hn2, ha2⟩ := removeNodeSpec H v hH
refine ⟨fun x => ?_, fun x y => ?_⟩
· rw [hn1 x, hn2 x, h.1 x]
· rw [ha1 x y, ha2 x y, h.2 x y]
/-- Adding the same edge to two graphs with the same nodes and edges. -/
theorem addEdge_congr {G H : Graph} (hG : G.WF) (hH : H.WF) (h : SameGraph G H)
{a b : Nat} (hab : a ≠ b) : SameGraph (G.addEdge a b) (H.addEdge a b) := by
obtain ⟨_, hn1, ha1⟩ := addEdgeSpec G a b hG hab
obtain ⟨_, hn2, ha2⟩ := addEdgeSpec H a b hH hab
refine ⟨fun x => ?_, fun x y => ?_⟩
· rw [hn1 x, hn2 x, h.1 x]
· rw [ha1 x y, ha2 x y, h.2 x y]
/-- The order of the two endpoints of an added edge does not matter. -/
theorem addEdge_comm {G : Graph} (hG : G.WF) {a b : Nat} (hab : a ≠ b) :
SameGraph (G.addEdge a b) (G.addEdge b a) := by
obtain ⟨_, hn1, ha1⟩ := addEdgeSpec G a b hG hab
obtain ⟨_, hn2, ha2⟩ := addEdgeSpec G b a hG (Ne.symm hab)
refine ⟨fun x => ?_, fun x y => ?_⟩
· rw [hn1 x, hn2 x]
tauto
· rw [ha1 x y, ha2 x y]
tauto
/-- Two lists without repeats and with the same members have the same length. -/
theorem length_eq_of_mem_iff {l l' : List Nat} (hl : l.Nodup) (hl' : l'.Nodup)
(h : ∀ x, x ∈ l ↔ x ∈ l') : l.length = l'.length :=
((List.perm_ext_iff_of_nodup hl hl').2 h).length_eq
/-- Two well-formed graphs with the same nodes have the same number of nodes. -/
theorem numNodes_eq_of_mem_iff {G H : Graph} (hG : G.WF) (hH : H.WF)
(h : ∀ x, x ∈ G.nodes ↔ x ∈ H.nodes) : G.numNodes = H.numNodes :=
length_eq_of_mem_iff hG.nodup hH.nodup h
/-- Removing a node lowers the node count by one. -/
theorem numNodes_removeNode {G : Graph} (hG : G.WF) {v : Nat} (hv : v ∈ G.nodes) :
(G.removeNode v).numNodes + 1 = G.numNodes := by
have hR := removeNodeSpec G v hG
have hperm : (G.removeNode v).nodes.length = (G.nodes.erase v).length :=
length_eq_of_mem_iff hR.1.nodup (hG.nodup.erase v) (fun x => by
rw [hR.2.1 x, hG.nodup.mem_erase_iff]
tauto)
simp only [Graph.numNodes]
rw [hperm, List.length_erase_of_mem hv]
have := List.length_pos_of_mem hv
omega
/-- The graph part of one step of `reduceLoop` (`G1` = `G` after `removeNode v`, `nb`
= the neighbour list of `v`). Same as `C5.stepG`. -/
def stepL (G1 : Graph) (nb : List Nat) : Graph :=
match nb with
| [a, b] => G1.addEdge a b
| _ => G1
theorem redStep_eq (G : Graph) (v : Nat) :
redStep G v = stepL (G.removeNode v) (G.nbrs v) := rfl
/-- A reduction step on a well-formed graph keeps well-formedness and the node count
drops by one (if the neighbours are nodes of `G1`, distinct). -/
theorem stepL_props {G1 : Graph} (hG1 : G1.WF) {nb : List Nat} (hnd : nb.Nodup)
(hl : ∀ a ∈ nb, a ∈ G1.nodes) :
(stepL G1 nb).WF ∧ (stepL G1 nb).numNodes = G1.numNodes := by
rcases nb with _ | ⟨a, _ | ⟨b, _ | ⟨c, t⟩⟩⟩
· exact ⟨hG1, rfl⟩
· exact ⟨hG1, rfl⟩
· have hab : a ≠ b := by
intro h
subst h
simp at hnd
have ha : a ∈ G1.nodes := hl a (by simp)
have hb : b ∈ G1.nodes := hl b (by simp)
obtain ⟨hw, hn, _⟩ := addEdgeSpec G1 a b hG1 hab
have hcount : (G1.addEdge a b).numNodes = G1.numNodes := by
apply numNodes_eq_of_mem_iff hw hG1
intro x
rw [hn x]
constructor
· rintro (h | rfl | rfl)
· exact h
· exact ha
· exact hb
· intro h
exact Or.inl h
exact ⟨hw, hcount⟩
· exact ⟨hG1, rfl⟩
/-- `redStep` keeps well-formedness and removes exactly one node, for `v` a node. -/
theorem redStep_wf_numNodes {G : Graph} (hG : G.WF) {v : Nat} (hv : v ∈ G.nodes) :
(redStep G v).WF ∧ (redStep G v).numNodes + 1 = G.numNodes := by
have hRem := removeNodeSpec G v hG
have hl : ∀ a ∈ G.nbrs v, a ∈ (G.removeNode v).nodes := by
intro a ha
have hav : a ≠ v := fun h => hG.loopless v (h ▸ ha)
exact (hRem.2.1 a).2 ⟨hG.nbrs_sub v a ha, hav⟩
obtain ⟨hw, hcount⟩ := stepL_props hRem.1 (hG.nbrs_nodup v) hl
refine ⟨?_, ?_⟩
· rw [redStep_eq]
exact hw
· rw [redStep_eq, hcount]
exact numNodes_removeNode hG hv
theorem stepL_pair (G1 : Graph) (a b : Nat) : stepL G1 [a, b] = G1.addEdge a b := rfl
theorem stepL_of_ne {G1 : Graph} {nb : List Nat} (h : ∀ a b, nb ≠ [a, b]) :
stepL G1 nb = G1 := by
rcases nb with _ | ⟨a, _ | ⟨b, _ | ⟨c, t⟩⟩⟩
· rfl
· rfl
· exact absurd rfl (h a b)
· rfl
theorem exists_pair_of_length_two : ∀ l : List Nat, l.length = 2 → ∃ a b, l = [a, b]
| [a, b], _ => ⟨a, b, rfl⟩
| [], h => by simp at h
| [_], h => by simp at h
| _ :: _ :: _ :: _, h => by simp at h
/-- Two reduction steps on the same node set with the same neighbour sets give
`SameGraph` results (the lists may be reversed; then the edge is added in the other
order, which `addEdge_comm` handles). -/
theorem stepL_congr {G1 G1' : Graph} (h1 : G1.WF) (h1' : G1'.WF) (hS : SameGraph G1 G1')
{l l' : List Nat} (hnd : l.Nodup) (hnd' : l'.Nodup) (hmem : ∀ x, x ∈ l ↔ x ∈ l') :
SameGraph (stepL G1 l) (stepL G1' l') := by
have hlen : l.length = l'.length := length_eq_of_mem_iff hnd hnd' hmem
by_cases hp : ∃ a b, l = [a, b]
· obtain ⟨a, b, rfl⟩ := hp
have hl'2 : l'.length = 2 := by simpa using hlen.symm
obtain ⟨a', b', rfl⟩ := exists_pair_of_length_two l' hl'2
have hab : a ≠ b := by
intro h
subst h
simp at hnd
have hab' : a' ≠ b' := by
intro h
subst h
simp at hnd'
have h1m : a ∈ [a', b'] := (hmem a).1 (by simp)
have h2m : b ∈ [a', b'] := (hmem b).1 (by simp)
have h3m : a' ∈ [a, b] := (hmem a').2 (by simp)
have h4m : b' ∈ [a, b] := (hmem b').2 (by simp)
simp only [List.mem_cons, List.not_mem_nil, or_false] at h1m h2m h3m h4m
have key : (a' = a ∧ b' = b) ∨ (a' = b ∧ b' = a) := by omega
rw [stepL_pair, stepL_pair]
rcases key with ⟨h5, h6⟩ | ⟨h5, h6⟩
· rw [h5, h6]
exact addEdge_congr h1 h1' hS hab
· rw [h5, h6]
exact sameGraph_trans (addEdge_congr h1 h1' hS hab) (addEdge_comm h1' hab)
· have hne : ∀ a b, l ≠ [a, b] := fun a b h => hp ⟨a, b, h⟩
have hp' : ¬ ∃ a' b', l' = [a', b'] := by
rintro ⟨a', b', rfl⟩
exact hp (exists_pair_of_length_two l (by simpa using hlen))
have hne' : ∀ a' b', l' ≠ [a', b'] := fun a' b' h => hp' ⟨a', b', h⟩
rw [stepL_of_ne hne, stepL_of_ne hne']
exact hS
/-- `redStep` respects `SameGraph` (for well-formed graphs; no degree or membership
assumption is needed, since the neighbour lists have the same members). -/
theorem redStep_congr {F F' : Graph} (hF : F.WF) (hF' : F'.WF) (hS : SameGraph F F')
(v : Nat) : SameGraph (redStep F v) (redStep F' v) := by
have hRem := removeNode_congr hF hF' hS v
have hmem : ∀ x, x ∈ F.nbrs v ↔ x ∈ F'.nbrs v := fun x => hS.2 v x
rw [redStep_eq, redStep_eq]
exact stepL_congr (removeNodeSpec F v hF).1 (removeNodeSpec F' v hF').1 hRem
(hF.nbrs_nodup v) (hF'.nbrs_nodup v) hmem
end R3
open R3 in
/-- Records only depend on the graph up to `SameGraph`. -/
theorem opsRecordCongr : OpsRecordCongr := by
intro F F' R ops
induction ops generalizing F F' with
| nil =>
intro hF hF' hS hR
exact sameGraph_trans (sameGraph_symm hS) hR
| cons o ops ih =>
intro hF hF' hS hR
cases o with
| red v nb =>
obtain ⟨hv, hnd, hlen, hadj, hrest⟩ := hR
have hv' : v ∈ F'.nodes := (hS.1 v).1 hv
refine ⟨hv', hnd, hlen, fun x => (hadj x).trans (hS.2 v x), ?_⟩
exact ih (redStep F v) (redStep F' v) (redStep_wf_numNodes hF hv).1
(redStep_wf_numNodes hF' hv').1 (redStep_congr hF hF' hS v) hrest
| del w =>
obtain ⟨hw, hrest⟩ := hR
have hw' : w ∈ F'.nodes := (hS.1 w).1 hw
refine ⟨hw', ?_⟩
exact ih (F.removeNode w) (F'.removeNode w) (removeNodeSpec F w hF).1
(removeNodeSpec F' w hF').1 (removeNode_congr hF hF' hS w) hrest
open R3 in
/-- Records compose. -/
theorem opsRecordAppend : OpsRecordAppend := by
intro F M R ops₁ ops₂
induction ops₁ generalizing F with
| nil =>
intro hF hM h1 h2
exact opsRecordCongr M F R ops₂ hM hF (sameGraph_symm h1) h2
| cons o ops₁ ih =>
intro hF hM h1 h2
cases o with
| red v nb =>
obtain ⟨hv, hnd, hlen, hadj, hrest⟩ := h1
exact ⟨hv, hnd, hlen, hadj, ih (redStep F v) (redStep_wf_numNodes hF hv).1 hM hrest h2⟩
| del w =>
obtain ⟨hw, hrest⟩ := h1
exact ⟨hw, ih (F.removeNode w) (removeNodeSpec F w hF).1 hM hrest h2⟩
#print axioms opsRecordCongr
#print axioms opsRecordAppend
end CubicPathwidth.Alg
Back to top