CubicPathwidth.Alg.Proofs.C4Switched
Source file CubicPathwidth/Alg/Proofs/C4Switched.lean of the Lean project (how it is built).
import CubicPathwidth.Alg.Spec
/-!
# C4: validity of the median-switched layout (`SwitchedLayoutValid`)
Membership-level mirror of `switchedLayoutF` (`layoutB`), the block lemmas, and the
proof that the layout is a valid path decomposition (plan task C4).
-/
namespace CubicPathwidth.Alg
open Graph
namespace C4
/-! ## Definitions (membership-level mirror of `switchedLayoutF`) -/
/-- Python `Wp`: `Wset \ D`. -/
def wpF (G : Graph) (Y : Labels) (x : Nat) : Bool := inW G Y x && !inD G Y x
/-- Python `P` (the connector items come from these). -/
def pSet (G : Graph) (Y : Labels) : List Nat :=
G.nodes.filter fun u => inU G Y u && !inD G Y u && (G.nbrs u).any (wpF G Y)
/-- Python `e u`. -/
def eSet (G : Graph) (Y : Labels) (u : Nat) : List Nat := (G.nbrs u).filter (wpF G Y)
/-- The number of low nodes (`ell`). -/
def nLow (G : Graph) (Y : Labels) : Nat := (G.nodes.filter (isLow Y)).length
/-- Inner bag `i` (`i < ell`). -/
def innerB (G : Graph) (order : List Nat) (i : Nat) : Bag :=
order.getD i 0 :: (order.take i).filter fun u =>
(G.nbrs u).any fun x => !decide (x ∈ order.take i)
/-- The bag `C_{-1}`. -/
def cm1B (G : Graph) (Y : Labels) : Bag :=
G.nodes.filter fun v => inU G Y v || (inD G Y v && inW G Y v)
/-- The bag `C_j`. -/
def csB (G : Graph) (Y : Labels) (q : List Nat) (j : Nat) : Bag :=
G.nodes.filter (inD G Y) ++ (pSet G Y).filter (fun u => !subsetB (eSet G Y u) (q.take (j - 1)))
++ q.take j
/-- Outer bag `k`. -/
def outB (G : Graph) (Y : Labels) (order : List Nat) (k : Nat) : Bag :=
order.getD (nLow G Y + k) 0 :: G.nodes.filter fun x =>
!decide (x ∈ G.nodes.filter (isLow Y) ++ (order.drop (nLow G Y)).take (k + 1)) &&
(G.nbrs x).any fun u =>
decide (u ∈ G.nodes.filter (isLow Y) ++ (order.drop (nLow G Y)).take (k + 1))
/-- The whole layout, block by block: inner, `C_{-1}`, `C_0 … C_m`, outer. -/
def layoutB (G : Graph) (Y : Labels) (order q : List Nat) : List Bag :=
(List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y] ++
(List.range (q.length + 1)).map (csB G Y q) ++
(List.range (order.length - nLow G Y)).map (outB G Y order)
/-- Hypotheses on the order and the connector list used by the proof. -/
structure OrdOK (G : Graph) (Y : Labels) (order q : List Nat) : Prop where
perm : order.Perm G.nodes
split : order = order.filter (isLow Y) ++ order.filter (fun x => !isLow Y x)
qmem : ∀ x, x ∈ q ↔ x ∈ G.nodes.filter (wpF G Y)
/-! ## Equality with `switchedLayout` -/
theorem hs_contains (T : List Nat) (x : Nat) :
(T.foldl (fun s y => s.insert y) (∅ : Std.HashSet Nat)).contains x = decide (x ∈ T) := by
have key : ∀ (T : List Nat) (s : Std.HashSet Nat),
(T.foldl (fun s y => s.insert y) s).contains x = (s.contains x || decide (x ∈ T)) := by
intro T
induction T with
| nil => intro s; simp
| cons a T ih =>
intro s
simp only [List.foldl_cons, ih, Std.HashSet.contains_insert, List.mem_cons]
grind
rw [key]
simp
/-! ## Order facts -/
/-- A list whose elements are "low before high" splits as `filter p ++ filter (not p)`. -/
theorem lows_first {α : Type} (p : α → Bool) : ∀ (l : List α),
l.Pairwise (fun a b => p b = true → p a = true) →
l = l.filter p ++ l.filter (fun x => !p x)
| [], _ => by simp
| a :: t, h => by
rw [List.pairwise_cons] at h
obtain ⟨ha, ht⟩ := h
have IH := lows_first p t ht
by_cases hpa : p a = true
· have h1 : (a :: t).filter p = a :: t.filter p := by simp [hpa]
have h2 : (a :: t).filter (fun x => !p x) = t.filter (fun x => !p x) := by
simp [hpa]
rw [h1, h2]
exact congrArg (a :: ·) IH
· have hT : ∀ b ∈ t, p b = false := fun b hb => by
cases hb' : p b with
| false => rfl
| true => exact absurd (ha b hb hb') hpa
have h1 : t.filter p = [] := List.filter_eq_nil_iff.2 (fun b hb => by simp [hT b hb])
have h2 : t.filter (fun x => !p x) = t := List.filter_eq_self.2 (fun b hb => by simp [hT b hb])
have h3 : (a :: t).filter p = [] := by simp [hpa, h1]
have h4 : (a :: t).filter (fun x => !p x) = a :: t := by
simp [hpa, h2]
rw [h3, h4]
simp
/-- Every element of `G.nodes` is in `order` (membership form of the permutation). -/
theorem OrdOK.mem {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
{v : Nat} : v ∈ order ↔ v ∈ G.nodes :=
h.perm.mem_iff
theorem OrdOK.nodup {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
(hnd : G.nodes.Nodup) : order.Nodup :=
h.perm.nodup_iff.2 hnd
theorem OrdOK.length {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q) :
order.length = G.nodes.length :=
h.perm.length_eq
theorem nLow_le {G : Graph} {Y : Labels} : nLow G Y ≤ G.nodes.length :=
List.length_filter_le _ _
/-- The first `nLow` entries of `order` are the low nodes. -/
theorem OrdOK.take_nLow {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q) :
order.take (nLow G Y) = order.filter (isLow Y) := by
have hlen : (order.filter (isLow Y)).length = nLow G Y :=
(h.perm.filter (isLow Y)).length_eq
have key := List.take_left' (l₁ := order.filter (isLow Y))
(l₂ := order.filter (fun x => !isLow Y x)) hlen
rw [← h.split] at key
exact key
/-- A node is low iff its position is below `nLow`. -/
theorem OrdOK.low_iff {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
{v : Nat} (hv : v ∈ G.nodes) : isLow Y v = true ↔ order.idxOf v < nLow G Y := by
have hvo : v ∈ order := h.mem.2 hv
rw [← List.mem_take_iff_idxOf_lt hvo, h.take_nLow, List.mem_filter]
simp [hvo]
/-- Position of a node in `order` (for nodup `order`). -/
theorem getD_idxOf {order : List Nat} {v : Nat} (hv : v ∈ order) :
order.getD (order.idxOf v) 0 = v := by
have hlt : order.idxOf v < order.length := List.idxOf_lt_length_iff.2 hv
rw [List.getD_eq_getElem?_getD, List.getElem?_eq_getElem hlt]
simp only [Option.getD_some]
exact List.getElem_idxOf hlt
theorem idxOf_getD {order : List Nat} (hnd : order.Nodup) {i : Nat} (hi : i < order.length) :
order.idxOf (order.getD i 0) = i := by
rw [List.getD_eq_getElem?_getD, List.getElem?_eq_getElem hi]
simp only [Option.getD_some]
exact hnd.idxOf_getElem i hi
theorem getD_eq_iff {order : List Nat} (hnd : order.Nodup) {i v : Nat}
(hi : i < order.length) (hv : v ∈ order) :
order.getD i 0 = v ↔ order.idxOf v = i := by
constructor
· intro e
rw [← e, idxOf_getD hnd hi]
· intro e
rw [← e]
exact getD_idxOf hv
/-- Membership in the `T` of the outer bags: the first `nLow + k + 1` positions. -/
theorem OrdOK.mem_T {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
{k x : Nat} (hx : x ∈ G.nodes) :
x ∈ G.nodes.filter (isLow Y) ++ (order.drop (nLow G Y)).take (k + 1) ↔
order.idxOf x < nLow G Y + k + 1 := by
have hxo : x ∈ order := h.mem.2 hx
have e : nLow G Y + k + 1 = nLow G Y + (k + 1) := by omega
rw [← List.mem_take_iff_idxOf_lt hxo, e, List.take_add (i := nLow G Y) (j := k + 1), h.take_nLow]
simp [List.mem_append, List.mem_filter, hxo, hx]
/-! ## Block membership -/
theorem inBag_append_lt {A B : List Bag} {g : Nat} {v : Nat} (hg : g < A.length) :
InBag (A ++ B) g v ↔ InBag A g v := by
unfold InBag
rw [List.getElem?_append_left hg]
theorem inBag_append_ge {A B : List Bag} {g : Nat} {v : Nat} (hg : A.length ≤ g) :
InBag (A ++ B) g v ↔ InBag B (g - A.length) v := by
unfold InBag
rw [List.getElem?_append_right hg]
theorem inBag_map_range (f : Nat → Bag) (k g v : Nat) :
InBag ((List.range k).map f) g v ↔ g < k ∧ v ∈ f g := by
unfold InBag
by_cases hg : g < k
· simp [hg]
· have : ((List.range k).map f)[g]? = none := by
rw [List.getElem?_eq_none]
simp only [List.length_map, List.length_range]
omega
simp [hg]
theorem inBag_singleton (B : Bag) (g v : Nat) : InBag [B] g v ↔ g = 0 ∧ v ∈ B := by
unfold InBag
cases g <;> simp
/-- Predicate form of `List.any` (pointwise on the list). -/
theorem any_iff_of {l : List Nat} {f : Nat → Bool} {P : Nat → Prop}
(h : ∀ x ∈ l, (f x = true ↔ P x)) : l.any f = true ↔ ∃ x ∈ l, P x := by
rw [List.any_eq_true]
constructor
· rintro ⟨x, hx, hx2⟩
exact ⟨x, hx, (h x hx).1 hx2⟩
· rintro ⟨x, hx, hx2⟩
exact ⟨x, hx, (h x hx).2 hx2⟩
/-- Membership in the inner bag `i`. -/
theorem mem_inner {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {i v : Nat} (hi : i < nLow G Y) (hv : v ∈ G.nodes) :
v ∈ innerB G order i ↔
(order.idxOf v = i ∨ (order.idxOf v < i ∧ ∃ x ∈ G.nbrs v, i ≤ order.idxOf x)) := by
have hnlen : nLow G Y ≤ order.length := by rw [h.length]; exact nLow_le
have hi' : i < order.length := by omega
have hvo : v ∈ order := h.mem.2 hv
have hnd : order.Nodup := h.nodup hG.nodup
have hnb : ∀ x ∈ G.nbrs v, (x ∈ order.take i ↔ order.idxOf x < i) := fun x hx =>
List.mem_take_iff_idxOf_lt (h.mem.2 (hG.nbrs_sub v x hx))
have hany : (G.nbrs v).any (fun x => !decide (x ∈ order.take i)) = true ↔
∃ x ∈ G.nbrs v, i ≤ order.idxOf x := by
refine any_iff_of (fun x hx => ?_)
have h1 := hnb x hx
simp only [Bool.not_eq_true', decide_eq_false_iff_not, h1, not_lt]
have hg : (v = order.getD i 0) ↔ order.idxOf v = i := by
rw [eq_comm]
exact getD_eq_iff hnd hi' hvo
unfold innerB
rw [List.mem_cons, List.mem_filter, hg, List.mem_take_iff_idxOf_lt hvo, hany]
theorem mem_cm1 {G : Graph} {Y : Labels} {v : Nat} :
v ∈ cm1B G Y ↔ v ∈ G.nodes ∧ (inU G Y v = true ∨ (inD G Y v = true ∧ inW G Y v = true)) := by
unfold cm1B
simp [List.mem_filter, Bool.or_eq_true, Bool.and_eq_true]
theorem mem_pSet {G : Graph} {Y : Labels} {v : Nat} :
v ∈ pSet G Y ↔ v ∈ G.nodes ∧ inU G Y v = true ∧ inD G Y v = false ∧
∃ x ∈ G.nbrs v, wpF G Y x = true := by
unfold pSet
simp [List.mem_filter, Bool.and_eq_true, List.any_eq_true, and_assoc]
/-- Membership in `C_j`. -/
theorem mem_cs {G : Graph} {Y : Labels} {q : List Nat} {j v : Nat} :
v ∈ csB G Y q j ↔ (v ∈ G.nodes ∧ inD G Y v = true) ∨
(v ∈ G.nodes ∧ inU G Y v = true ∧ inD G Y v = false ∧ (∃ x ∈ G.nbrs v, wpF G Y x = true) ∧
subsetB (eSet G Y v) (q.take (j - 1)) = false) ∨ v ∈ q.take j := by
unfold csB
rw [List.mem_append, List.mem_append, List.mem_filter, List.mem_filter, mem_pSet]
simp only [Bool.not_eq_true']
constructor
· rintro ((⟨h1, h2⟩ | ⟨⟨h1, h2, h3, h4⟩, h5⟩) | h6)
· exact Or.inl ⟨h1, h2⟩
· exact Or.inr (Or.inl ⟨h1, h2, h3, h4, h5⟩)
· exact Or.inr (Or.inr h6)
· rintro (⟨h1, h2⟩ | ⟨h1, h2, h3, h4, h5⟩ | h6)
· exact Or.inl (Or.inl ⟨h1, h2⟩)
· exact Or.inl (Or.inr ⟨⟨h1, h2, h3, h4⟩, h5⟩)
· exact Or.inr h6
/-- Membership in the outer bag `k` (the node itself at its own index, then the
neighbours of the first `nLow + k + 1` positions). -/
theorem mem_out {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {k v : Nat} (hk : k < order.length - nLow G Y) (hv : v ∈ G.nodes) :
v ∈ outB G Y order k ↔ order.idxOf v = nLow G Y + k ∨
(nLow G Y + k < order.idxOf v ∧ ∃ x ∈ G.nbrs v, order.idxOf x ≤ nLow G Y + k) := by
have hnlen : nLow G Y ≤ order.length := by rw [h.length]; exact nLow_le
have hi' : nLow G Y + k < order.length := by omega
have hvo : v ∈ order := h.mem.2 hv
have hnd : order.Nodup := h.nodup hG.nodup
have hT : ∀ x ∈ G.nodes, (x ∈ G.nodes.filter (isLow Y) ++ (order.drop (nLow G Y)).take (k + 1) ↔
order.idxOf x < nLow G Y + k + 1) := fun x hx => h.mem_T hx
have hany : (G.nbrs v).any (fun x => decide (x ∈ G.nodes.filter (isLow Y) ++
(order.drop (nLow G Y)).take (k + 1))) = true ↔
∃ x ∈ G.nbrs v, order.idxOf x < nLow G Y + k + 1 := by
refine any_iff_of (fun x hx => ?_)
rw [decide_eq_true_eq, hT x (hG.nbrs_sub v x hx)]
have hnot : ¬ (v ∈ G.nodes.filter (isLow Y) ++ (order.drop (nLow G Y)).take (k + 1)) ↔
nLow G Y + k < order.idxOf v := by
rw [hT v hv]
omega
unfold outB
have hg : (v = order.getD (nLow G Y + k) 0) ↔ order.idxOf v = nLow G Y + k := by
rw [eq_comm]
exact getD_eq_iff hnd hi' hvo
rw [List.mem_cons, List.mem_filter, hg]
simp only [Bool.and_eq_true, Bool.not_eq_true', decide_eq_false_iff_not, hany]
constructor
· rintro (h1 | ⟨_, h2, x, hx, hx2⟩)
· exact Or.inl h1
· exact Or.inr ⟨hnot.1 h2, x, hx, by omega⟩
· rintro (h1 | ⟨h2, x, hx, hx2⟩)
· exact Or.inl h1
· exact Or.inr ⟨hv, hnot.2 h2, x, hx, by omega⟩
/-- The block structure of `InBag` for the whole layout. -/
theorem inBag_layout {G : Graph} {Y : Labels} {order q : List Nat} (g v : Nat) :
InBag (layoutB G Y order q) g v ↔
(g < nLow G Y ∧ v ∈ innerB G order g) ∨ (g = nLow G Y ∧ v ∈ cm1B G Y) ∨
(nLow G Y + 1 ≤ g ∧ g ≤ nLow G Y + 1 + q.length ∧
v ∈ csB G Y q (g - (nLow G Y + 1))) ∨
(nLow G Y + 2 + q.length ≤ g ∧ g - (nLow G Y + 2 + q.length) < order.length - nLow G Y ∧
v ∈ outB G Y order (g - (nLow G Y + 2 + q.length))) := by
unfold layoutB
have hA1 : ((List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y]).length =
nLow G Y + 1 := by
simp
have hA2 : ((List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y] ++
(List.range (q.length + 1)).map (csB G Y q)).length = nLow G Y + 2 + q.length := by
simp only [List.length_append, List.length_map, List.length_range, List.length_singleton]
omega
by_cases h4 : nLow G Y + 2 + q.length ≤ g
· rw [inBag_append_ge (A := (List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y] ++
(List.range (q.length + 1)).map (csB G Y q)) (by rw [hA2]; exact h4), hA2, inBag_map_range]
constructor
· rintro ⟨h5, h6⟩
exact Or.inr (Or.inr (Or.inr ⟨h4, h5, h6⟩))
· rintro (⟨h5, _⟩ | ⟨h5, _⟩ | ⟨h5, _⟩ | ⟨_, h5, h6⟩)
· omega
· omega
· omega
· exact ⟨h5, h6⟩
· rw [inBag_append_lt (A := (List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y] ++
(List.range (q.length + 1)).map (csB G Y q)) (by rw [hA2]; omega)]
by_cases h3 : nLow G Y + 1 ≤ g
· rw [inBag_append_ge (A := (List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y])
(by rw [hA1]; exact h3), hA1]
by_cases h2 : g < nLow G Y + 1 + (q.length + 1)
· rw [inBag_map_range]
constructor
· rintro ⟨h5, h6⟩
exact Or.inr (Or.inr (Or.inl ⟨h3, by omega, by
have : g - (nLow G Y + 1) = g - (nLow G Y + 1) := rfl
exact h6⟩))
· rintro (⟨h5, _⟩ | ⟨h5, _⟩ | ⟨h5, h6, h7⟩ | ⟨h5, _⟩)
· omega
· omega
· exact ⟨by omega, h7⟩
· omega
· rw [inBag_map_range]
constructor
· rintro ⟨h5, _⟩
omega
· rintro (⟨h5, _⟩ | ⟨h5, _⟩ | ⟨h5, h6, h7⟩ | ⟨h5, _⟩)
· omega
· omega
· omega
· omega
· rw [inBag_append_lt (A := (List.range (nLow G Y)).map (innerB G order) ++ [cm1B G Y])
(by rw [hA1]; omega)]
by_cases h1 : g < nLow G Y
· rw [inBag_append_lt (A := (List.range (nLow G Y)).map (innerB G order))
(by simp only [List.length_map, List.length_range]; omega), inBag_map_range]
constructor
· rintro ⟨h5, h6⟩
exact Or.inl ⟨h5, h6⟩
· rintro (⟨h5, h6⟩ | ⟨h5, _⟩ | ⟨h5, _⟩ | ⟨h5, _⟩)
· exact ⟨h5, h6⟩
· omega
· omega
· omega
· rw [inBag_append_ge (A := (List.range (nLow G Y)).map (innerB G order))
(by simp only [List.length_map, List.length_range]; omega), inBag_singleton]
constructor
· rintro ⟨h5, h6⟩
exact Or.inr (Or.inl ⟨by simp only [List.length_map, List.length_range] at h5; omega, h6⟩)
· rintro (⟨h5, _⟩ | ⟨h5, h6⟩ | ⟨h5, _⟩ | ⟨h5, _⟩)
· omega
· simp only [List.length_map, List.length_range]
exact ⟨by omega, h6⟩
· omega
· omega
/-! ## Local facts about the classes -/
theorem inU_iff {G : Graph} {Y : Labels} {v : Nat} :
inU G Y v = true ↔ isLow Y v = true ∧ ∃ x ∈ G.nbrs v, isLow Y x = false := by
simp [inU, Bool.and_eq_true, List.any_eq_true]
theorem inW_iff {G : Graph} {Y : Labels} {v : Nat} :
inW G Y v = true ↔ isLow Y v = false ∧ ∃ x ∈ G.nbrs v, isLow Y x = true := by
simp [inW, Bool.and_eq_true, List.any_eq_true]
theorem inD_iff {G : Graph} {Y : Labels} {v : Nat} :
inD G Y v = true ↔ G.degree v = 3 ∧ ∀ x ∈ G.nbrs v, (isLow Y x != isLow Y v) = true := by
simp [inD, Bool.and_eq_true, List.all_eq_true, degree]
theorem wpF_iff {G : Graph} {Y : Labels} {v : Nat} :
wpF G Y v = true ↔ (isLow Y v = false ∧ ∃ x ∈ G.nbrs v, isLow Y x = true) ∧ inD G Y v = false := by
simp [wpF, Bool.and_eq_true, inW_iff]
/-- A degree-3 vertex has a neighbour. -/
theorem exists_nbr_of_degree3 {G : Graph} {v : Nat} (h : G.degree v = 3) :
∃ x, x ∈ G.nbrs v := by
unfold degree at h
cases hl : G.nbrs v with
| nil => rw [hl] at h; simp at h
| cons x t => exact ⟨x, by simp⟩
/-- A low degree-3 node with all neighbours high is in `U`. -/
theorem inU_of_inD_low {G : Graph} {Y : Labels} {v : Nat}
(hd : inD G Y v = true) (hl : isLow Y v = true) : inU G Y v = true := by
obtain ⟨hdeg, hall⟩ := inD_iff.1 hd
obtain ⟨x, hx⟩ := exists_nbr_of_degree3 hdeg
have hx2 := hall x hx
have hxh : isLow Y x = false := by
rw [hl] at hx2
cases hxl : isLow Y x <;> simp_all
exact inU_iff.2 ⟨hl, x, hx, hxh⟩
/-- A high degree-3 node is in `W`. -/
theorem inW_of_inD_high {G : Graph} {Y : Labels} {v : Nat}
(hd : inD G Y v = true) (hh : isLow Y v = false) : inW G Y v = true := by
obtain ⟨hdeg, hall⟩ := inD_iff.1 hd
obtain ⟨x, hx⟩ := exists_nbr_of_degree3 hdeg
have hx2 := hall x hx
have hxl : isLow Y x = true := by
rw [hh] at hx2
cases hxl : isLow Y x <;> simp_all
exact inW_iff.2 ⟨hh, x, hx, hxl⟩
/-! ## Existence of thresholds and extrema -/
/-- A downward closed predicate true at `0` is an initial segment of `[0, L]`. -/
theorem exists_thr (Q : Nat → Prop) (hdown : ∀ j k, j ≤ k → Q k → Q j) (h0 : Q 0) (L : Nat) :
∃ J, J ≤ L ∧ ∀ j, j ≤ L → (Q j ↔ j ≤ J) := by
induction L with
| zero => exact ⟨0, le_refl 0, fun j hj => by
have : j = 0 := by omega
subst this
simp [h0]⟩
| succ L ih =>
obtain ⟨J, hJL, hJ⟩ := ih
by_cases hQ : Q (L + 1)
· refine ⟨L + 1, le_refl _, fun j hj => ?_⟩
exact ⟨fun _ => hj, fun _ => hdown j (L + 1) hj hQ⟩
· refine ⟨J, by omega, fun j hj => ?_⟩
by_cases hjL : j ≤ L
· exact hJ j hjL
· have : j = L + 1 := by omega
subst this
exact ⟨fun h => absurd h hQ, fun h => by omega⟩
/-- The maximum of finitely many positions above a threshold `p`. -/
theorem exists_max (l : List Nat) (f : Nat → Nat) (p B : Nat) (hp : p < B)
(hf : ∀ x ∈ l, f x < B) :
∃ c, p ≤ c ∧ c < B ∧ ∀ i, p < i → ((∃ x ∈ l, i ≤ f x) ↔ i ≤ c) := by
induction l with
| nil => exact ⟨p, le_refl p, hp, fun i hi => by simp; omega⟩
| cons x t ih =>
obtain ⟨c', hpc', hc'B, hc'⟩ := ih (fun y hy => hf y (List.mem_cons_of_mem x hy))
refine ⟨max (f x) c', le_trans hpc' (le_max_right _ _), ?_, fun i hi => ?_⟩
· exact max_lt (hf x (by simp)) hc'B
· constructor
· rintro ⟨y, hy, hiy⟩
rcases List.mem_cons.1 hy with rfl | hy
· exact le_max_of_le_left hiy
· exact le_max_of_le_right ((hc' i hi).1 ⟨y, hy, hiy⟩)
· intro hm
rcases le_max_iff.1 hm with h1 | h1
· exact ⟨x, by simp, h1⟩
· obtain ⟨y, hy, hiy⟩ := (hc' i hi).2 h1
exact ⟨y, List.mem_cons_of_mem x hy, hiy⟩
/-- The minimum of positions of a list, capped at `B`: `∃ x, f x ≤ c` is `a ≤ c` for `c < B`. -/
theorem exists_lower (l : List Nat) (f : Nat → Nat) (B : Nat) :
∃ a, a ≤ B ∧ ∀ c, c < B → ((∃ x ∈ l, f x ≤ c) ↔ a ≤ c) := by
induction l with
| nil => exact ⟨B, le_refl B, fun c hc => by simp; omega⟩
| cons x t ih =>
obtain ⟨a', ha'B, ha'⟩ := ih
refine ⟨min (f x) a', le_trans (min_le_right _ _) ha'B, fun c hc => ?_⟩
constructor
· rintro ⟨y, hy, hyc⟩
rcases List.mem_cons.1 hy with rfl | hy
· exact le_trans (min_le_left _ _) hyc
· exact le_trans (min_le_right _ _) ((ha' c hc).1 ⟨y, hy, hyc⟩)
· intro hm
rcases min_le_iff.1 hm with h1 | h1
· exact ⟨x, by simp, h1⟩
· obtain ⟨y, hy, hyc⟩ := (ha' c hc).2 h1
exact ⟨y, List.mem_cons_of_mem x hy, hyc⟩
/-! ## Small helpers -/
theorem q_mem {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q) {x : Nat} :
x ∈ q ↔ x ∈ G.nodes ∧ wpF G Y x = true := by
rw [h.qmem, List.mem_filter]
theorem idx_of_low {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
{x : Nat} (hx : x ∈ G.nodes) (hl : isLow Y x = true) : order.idxOf x < nLow G Y :=
(h.low_iff hx).1 hl
theorem idx_of_high {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
{x : Nat} (hx : x ∈ G.nodes) (hl : isLow Y x = false) : nLow G Y ≤ order.idxOf x := by
by_contra hc
have h1 : isLow Y x = true := (h.low_iff hx).2 (by omega)
rw [hl] at h1
exact absurd h1 (by simp)
theorem idx_lt_length {G : Graph} {Y : Labels} {order q : List Nat} (h : OrdOK G Y order q)
{x : Nat} (hx : x ∈ G.nodes) : order.idxOf x < order.length :=
List.idxOf_lt_length_iff.2 (h.mem.2 hx)
theorem subsetB_iff {S B : List Nat} : subsetB S B = true ↔ ∀ x ∈ S, x ∈ B := by
simp [subsetB, List.all_eq_true]
theorem Qv_down (S q : List Nat) (j k : Nat) (hjk : j ≤ k)
(hk : subsetB S (q.take (k - 1)) = false) : subsetB S (q.take (j - 1)) = false := by
cases hj : subsetB S (q.take (j - 1))
· rfl
· exfalso
have hsub := subsetB_iff.1 hj
have hmono : q.take (j - 1) ⊆ q.take (k - 1) := List.take_subset_take_left q (by omega)
have h2 : subsetB S (q.take (k - 1)) = true := subsetB_iff.2 (fun x hx => hmono (hsub x hx))
rw [hk] at h2
exact absurd h2 (by simp)
theorem Qv_zero (S q : List Nat) (hS : ∃ x, x ∈ S) : subsetB S (q.take (0 - 1)) = false := by
obtain ⟨x, hx⟩ := hS
cases hc : subsetB S (q.take (0 - 1))
· rfl
· have := subsetB_iff.1 hc x hx
simp at this
/-- Outer blocks never contain a low node. -/
theorem not_out_low {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {k v : Nat} (hk : k < order.length - nLow G Y) (hv : v ∈ G.nodes)
(hl : isLow Y v = true) : v ∉ outB G Y order k := by
intro h3
have hlt := idx_of_low h hv hl
rcases (mem_out hG h hk hv).1 h3 with h4 | ⟨h4, _⟩ <;> omega
/-- The inner bag at `g` contains a low node `v` iff its position is at most `g`, when `v`
has a high neighbour. -/
theorem inner_of_high_nbr {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v x0 : Nat} (hv : v ∈ G.nodes) (hx0 : x0 ∈ G.nbrs v)
(hx0h : isLow Y x0 = false) {g : Nat} (hg : g < nLow G Y) :
v ∈ innerB G order g ↔ order.idxOf v ≤ g := by
rw [mem_inner hG h hg hv]
have hx0i : nLow G Y ≤ order.idxOf x0 := idx_of_high h (hG.nbrs_sub v x0 hx0) hx0h
constructor
· rintro (h1 | ⟨h1, _⟩) <;> omega
· intro hle
by_cases heq : order.idxOf v = g
· exact Or.inl heq
· exact Or.inr ⟨by omega, x0, hx0, by omega⟩
/-! ## Low nodes -/
/-- Low node in `D`: inner bags up to `nLow - 1`, `C_{-1}`, and all `C_j`. -/
theorem case_LA {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hl : isLow Y v = true)
(hd : inD G Y v = true) (g : Nat) :
InBag (layoutB G Y order q) g v ↔
order.idxOf v ≤ g ∧ g ≤ nLow G Y + 1 + q.length := by
obtain ⟨x0, hx0, hx0h⟩ := (inU_iff.1 (inU_of_inD_low hd hl)).2
have hpl := idx_of_low h hv hl
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, _⟩ | ⟨h1, h2, _⟩ | ⟨h1, h2, h3⟩)
· rw [inner_of_high_nbr hG h hv hx0 hx0h h1] at h2
omega
· omega
· omega
· exact absurd h3 (not_out_low hG h h2 hv hl)
· rintro ⟨hh1, hh2⟩
by_cases h1 : g < nLow G Y
· exact Or.inl ⟨h1, (inner_of_high_nbr hG h hv hx0 hx0h h1).2 hh1⟩
· by_cases h2 : g = nLow G Y
· exact Or.inr (Or.inl ⟨h2, mem_cm1.2 ⟨hv, Or.inl (inU_of_inD_low hd hl)⟩⟩)
· exact Or.inr (Or.inr (Or.inl ⟨by omega, hh2,
mem_cs.2 (Or.inl ⟨hv, hd⟩)⟩))
/-- Low node in `U \ D` with a neighbour in `W'`, threshold `J` for `C_j`. -/
theorem case_LB {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hl : isLow Y v = true)
(hnd : inD G Y v = false) (hu : inU G Y v = true)
(hw : ∃ x ∈ G.nbrs v, wpF G Y x = true) {J : Nat} (hJL : J ≤ q.length)
(hJ : ∀ j, j ≤ q.length → (subsetB (eSet G Y v) (q.take (j - 1)) = false ↔ j ≤ J))
(g : Nat) :
InBag (layoutB G Y order q) g v ↔
order.idxOf v ≤ g ∧ g ≤ nLow G Y + 1 + J := by
obtain ⟨x0, hx0, hx0h⟩ := (inU_iff.1 hu).2
have hpl := idx_of_low h hv hl
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, _⟩ | ⟨h1, h2, h3⟩ | ⟨h1, h2, h3⟩)
· rw [inner_of_high_nbr hG h hv hx0 hx0h h1] at h2
omega
· omega
· rcases (mem_cs).1 h3 with ⟨_, h4⟩ | ⟨_, _, h4, _, h5⟩ | h6
· rw [hnd] at h4
exact absurd h4 (by simp)
· have := (hJ _ (by omega)).1 h5
exact ⟨by omega, by omega⟩
· have hvq := (q_mem h).1 (List.mem_of_mem_take h6)
have h7 := (wpF_iff.1 hvq.2).1.1
rw [hl] at h7
exact absurd h7 (by simp)
· exact absurd h3 (not_out_low hG h h2 hv hl)
· rintro ⟨hh1, hh2⟩
by_cases h1 : g < nLow G Y
· exact Or.inl ⟨h1, (inner_of_high_nbr hG h hv hx0 hx0h h1).2 hh1⟩
· by_cases h2 : g = nLow G Y
· exact Or.inr (Or.inl ⟨h2, mem_cm1.2 ⟨hv, Or.inl hu⟩⟩)
· refine Or.inr (Or.inr (Or.inl ⟨by omega, by omega, mem_cs.2 (Or.inr (Or.inl ⟨hv, hu, hnd, hw, ?_⟩))⟩))
exact (hJ _ (by omega)).2 (by omega)
/-- Low node in `U \ D` without a neighbour in `W'`: inner bags and `C_{-1}` only. -/
theorem case_LC {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hl : isLow Y v = true)
(hnd : inD G Y v = false) (hu : inU G Y v = true)
(hw : ¬ ∃ x ∈ G.nbrs v, wpF G Y x = true) (g : Nat) :
InBag (layoutB G Y order q) g v ↔
order.idxOf v ≤ g ∧ g ≤ nLow G Y := by
obtain ⟨x0, hx0, hx0h⟩ := (inU_iff.1 hu).2
have hpl := idx_of_low h hv hl
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, _⟩ | ⟨h1, h2, h3⟩ | ⟨h1, h2, h3⟩)
· rw [inner_of_high_nbr hG h hv hx0 hx0h h1] at h2
omega
· omega
· rcases (mem_cs).1 h3 with ⟨_, h4⟩ | ⟨_, _, _, h4, _⟩ | h6
· rw [hnd] at h4
exact absurd h4 (by simp)
· exact absurd h4 hw
· have hvq := (q_mem h).1 (List.mem_of_mem_take h6)
have h7 := (wpF_iff.1 hvq.2).1.1
rw [hl] at h7
exact absurd h7 (by simp)
· exact absurd h3 (not_out_low hG h h2 hv hl)
· rintro ⟨hh1, hh2⟩
by_cases h1 : g < nLow G Y
· exact Or.inl ⟨h1, (inner_of_high_nbr hG h hv hx0 hx0h h1).2 hh1⟩
· have h2 : g = nLow G Y := by omega
exact Or.inr (Or.inl ⟨h2, mem_cm1.2 ⟨hv, Or.inl hu⟩⟩)
/-- Low node not in `U`: its inner bags reach up to a bound `c < nLow`. -/
theorem case_LD {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hl : isLow Y v = true)
(hnu : inU G Y v = false) {c : Nat} (hcl : c < nLow G Y) (hpc : order.idxOf v ≤ c)
(hc : ∀ i, order.idxOf v < i → ((∃ x ∈ G.nbrs v, i ≤ order.idxOf x) ↔ i ≤ c))
(g : Nat) :
InBag (layoutB G Y order q) g v ↔ order.idxOf v ≤ g ∧ g ≤ c := by
have hpl := idx_of_low h hv hl
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, h2⟩ | ⟨h1, h2, h3⟩ | ⟨h1, h2, h3⟩)
· rw [mem_inner hG h h1 hv] at h2
rcases h2 with h2 | ⟨h2, x, hx, hx2⟩
· omega
· exact ⟨by omega, (hc g h2).1 ⟨x, hx, hx2⟩⟩
· have := mem_cm1.1 h2
rcases this with ⟨_, h4 | ⟨h4, _⟩⟩
· rw [hnu] at h4
exact absurd h4 (by simp)
· have := inU_of_inD_low h4 hl
rw [hnu] at this
exact absurd this (by simp)
· rcases (mem_cs).1 h3 with ⟨_, h4⟩ | ⟨_, h4, _⟩ | h6
· have := inU_of_inD_low h4 hl
rw [hnu] at this
exact absurd this (by simp)
· rw [hnu] at h4
exact absurd h4 (by simp)
· have hvq := (q_mem h).1 (List.mem_of_mem_take h6)
have h7 := (wpF_iff.1 hvq.2).1.1
rw [hl] at h7
exact absurd h7 (by simp)
· exact absurd h3 (not_out_low hG h h2 hv hl)
· rintro ⟨hh1, hh2⟩
have h1 : g < nLow G Y := by omega
refine Or.inl ⟨h1, (mem_inner hG h h1 hv).2 ?_⟩
by_cases heq : order.idxOf v = g
· exact Or.inl heq
· exact Or.inr ⟨by omega, (hc g (by omega)).2 hh2⟩
/-! ## High nodes -/
/-- High node in `D`: `C_{-1}`, all `C_j`, and outer bags up to its own index. -/
theorem case_HA {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hh : isLow Y v = false)
(hd : inD G Y v = true) (g : Nat) :
InBag (layoutB G Y order q) g v ↔
nLow G Y ≤ g ∧ g ≤ order.idxOf v + 2 + q.length := by
have hpi := idx_of_high h hv hh
obtain ⟨x0, hx0, hx0h⟩ := (inW_iff.1 (inW_of_inD_high hd hh)).2
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, h2⟩ | ⟨h1, h2, _⟩ | ⟨h1, h2, h3⟩)
· have := (mem_inner hG h h1 hv).1 h2
omega
· omega
· omega
· have := (mem_out hG h h2 hv).1 h3
rcases this with h4 | ⟨h4, _⟩ <;> omega
· rintro ⟨hh1, hh2⟩
by_cases h1 : g ≤ nLow G Y
· have h2 : g = nLow G Y := by omega
exact Or.inr (Or.inl ⟨h2, mem_cm1.2 ⟨hv, Or.inr ⟨hd, inW_of_inD_high hd hh⟩⟩⟩)
· by_cases h3 : g ≤ nLow G Y + 1 + q.length
· exact Or.inr (Or.inr (Or.inl ⟨by omega, h3, mem_cs.2 (Or.inl ⟨hv, hd⟩)⟩))
· have hk : g - (nLow G Y + 2 + q.length) < order.length - nLow G Y := by
have := idx_lt_length h hv
omega
refine Or.inr (Or.inr (Or.inr ⟨by omega, hk, ?_⟩))
rw [mem_out hG h hk hv]
by_cases heq : nLow G Y + (g - (nLow G Y + 2 + q.length)) = order.idxOf v
· exact Or.inl (by omega)
· exact Or.inr ⟨by omega, x0, hx0, by have := idx_of_low h (hG.nbrs_sub v x0 hx0) hx0h; omega⟩
/-- High node in `W \ D` (so in `q`): `C_j` for `j` beyond its first position in `q`, and
outer bags up to its own index. -/
theorem case_HB {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hh : isLow Y v = false)
(hvq : v ∈ q) (g : Nat) :
InBag (layoutB G Y order q) g v ↔
nLow G Y + 2 + q.idxOf v ≤ g ∧ g ≤ order.idxOf v + 2 + q.length := by
have hwp := (q_mem h).1 hvq
have hwpi := wpF_iff.1 hwp.2
have hnd : inD G Y v = false := hwpi.2
obtain ⟨x0, hx0, hx0h⟩ := hwpi.1.2
have hpi := idx_of_high h hv hh
have hfq : q.idxOf v < q.length := List.idxOf_lt_length_iff.2 hvq
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, h2⟩ | ⟨h1, h2, h3⟩ | ⟨h1, h2, h3⟩)
· have := (mem_inner hG h h1 hv).1 h2
rcases this with h4 | ⟨h4, _⟩ <;> omega
· rcases mem_cm1.1 h2 with ⟨_, h4 | ⟨h4, _⟩⟩
· have h5 : isLow Y v = true := (inU_iff.1 h4).1
rw [hh] at h5
exact absurd h5 (by simp)
· rw [hnd] at h4
exact absurd h4 (by simp)
· rcases (mem_cs).1 h3 with ⟨_, h4⟩ | ⟨_, h4, _⟩ | h6
· rw [hnd] at h4
exact absurd h4 (by simp)
· have h5 : isLow Y v = true := (inU_iff.1 h4).1
rw [hh] at h5
exact absurd h5 (by simp)
· have h7 := (List.mem_take_iff_idxOf_lt hvq).1 h6
exact ⟨by omega, by omega⟩
· rcases (mem_out hG h h2 hv).1 h3 with h4 | ⟨h4, _⟩ <;> omega
· rintro ⟨hh1, hh2⟩
by_cases h1 : g ≤ nLow G Y + 1 + q.length
· exact Or.inr (Or.inr (Or.inl ⟨by omega, h1,
mem_cs.2 (Or.inr (Or.inr ((List.mem_take_iff_idxOf_lt hvq).2 (by omega))))⟩))
· have hk : g - (nLow G Y + 2 + q.length) < order.length - nLow G Y := by
have := idx_lt_length h hv
omega
refine Or.inr (Or.inr (Or.inr ⟨by omega, hk, ?_⟩))
rw [mem_out hG h hk hv]
by_cases heq : nLow G Y + (g - (nLow G Y + 2 + q.length)) = order.idxOf v
· exact Or.inl (by omega)
· refine Or.inr ⟨by omega, x0, hx0, ?_⟩
have := idx_of_low h (hG.nbrs_sub v x0 hx0) hx0h
omega
/-- High node not in `W` (so not in `q`, not in `D`): only outer bags, from the first
position of a neighbour (`a`) up to its own index. -/
theorem case_HC {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) (hh : isLow Y v = false)
(hw : ¬ inW G Y v = true) {a : Nat} (ha : a ≤ order.idxOf v)
(hac : ∀ c, c < order.idxOf v → ((∃ x ∈ G.nbrs v, order.idxOf x ≤ c) ↔ a ≤ c))
(g : Nat) :
InBag (layoutB G Y order q) g v ↔
a + 2 + q.length ≤ g ∧ g ≤ order.idxOf v + 2 + q.length := by
have hpi := idx_of_high h hv hh
have hnl : ∀ x ∈ G.nbrs v, nLow G Y ≤ order.idxOf x := by
intro x hx
by_contra hc
have hxl : isLow Y x = true := (h.low_iff (hG.nbrs_sub v x hx)).2 (by omega)
exact hw (inW_iff.2 ⟨hh, x, hx, hxl⟩)
have hanL : nLow G Y ≤ a := by
by_contra hc
obtain ⟨x, hx, hxa⟩ := (hac a (by omega)).2 le_rfl
have := hnl x hx
omega
rw [inBag_layout]
constructor
· rintro (⟨h1, h2⟩ | ⟨h1, h2⟩ | ⟨h1, h2, h3⟩ | ⟨h1, h2, h3⟩)
· rcases (mem_inner hG h h1 hv).1 h2 with h4 | ⟨h4, _⟩ <;> omega
· rcases mem_cm1.1 h2 with ⟨_, h4 | ⟨h4, _⟩⟩
· have h5 : isLow Y v = true := (inU_iff.1 h4).1
rw [hh] at h5
exact absurd h5 (by simp)
· exact absurd (inW_of_inD_high h4 hh) hw
· rcases (mem_cs).1 h3 with ⟨_, h4⟩ | ⟨_, h4, _⟩ | h6
· exact absurd (inW_of_inD_high h4 hh) hw
· have h5 : isLow Y v = true := (inU_iff.1 h4).1
rw [hh] at h5
exact absurd h5 (by simp)
· have hwp := (q_mem h).1 (List.mem_of_mem_take h6)
exact absurd (inW_iff.2 (wpF_iff.1 hwp.2).1) hw
· rcases (mem_out hG h h2 hv).1 h3 with h4 | ⟨h4, x, hx, hx2⟩
· omega
· have := (hac (nLow G Y + (g - (nLow G Y + 2 + q.length))) h4).1 ⟨x, hx, hx2⟩
omega
· rintro ⟨hh1, hh2⟩
have hk : g - (nLow G Y + 2 + q.length) < order.length - nLow G Y := by
have := idx_lt_length h hv
omega
refine Or.inr (Or.inr (Or.inr ⟨by omega, hk, ?_⟩))
rw [mem_out hG h hk hv]
by_cases heq : nLow G Y + (g - (nLow G Y + 2 + q.length)) = order.idxOf v
· exact Or.inl (by omega)
· obtain ⟨x, hx, hx2⟩ := (hac (nLow G Y + (g - (nLow G Y + 2 + q.length))) (by omega)).2
(by omega)
exact Or.inr ⟨by omega, x, hx, hx2⟩
/-- Every node occupies an interval of bag indices, with explicit ends. -/
theorem vertex_interval {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {v : Nat} (hv : v ∈ G.nodes) :
∃ a b, a ≤ b ∧ ∀ g, InBag (layoutB G Y order q) g v ↔ a ≤ g ∧ g ≤ b := by
by_cases hl : isLow Y v = true
· have hpl := idx_of_low h hv hl
by_cases hd : inD G Y v = true
· exact ⟨order.idxOf v, nLow G Y + 1 + q.length, by omega,
fun g => case_LA hG h hv hl hd g⟩
· have hd' : inD G Y v = false := by simpa using hd
by_cases hu : inU G Y v = true
· by_cases hw : ∃ x ∈ G.nbrs v, wpF G Y x = true
· have hdown : ∀ j k, j ≤ k → subsetB (eSet G Y v) (q.take (k - 1)) = false →
subsetB (eSet G Y v) (q.take (j - 1)) = false :=
fun j k hjk hk => Qv_down _ q j k hjk hk
have hz : subsetB (eSet G Y v) (q.take (0 - 1)) = false := by
obtain ⟨x, hx, hwx⟩ := hw
exact Qv_zero _ q ⟨x, List.mem_filter.2 ⟨hx, hwx⟩⟩
obtain ⟨J, hJL, hJ⟩ := exists_thr (fun j => subsetB (eSet G Y v) (q.take (j - 1)) = false)
hdown hz q.length
exact ⟨order.idxOf v, nLow G Y + 1 + J, by omega,
fun g => case_LB hG h hv hl hd' hu hw hJL (fun j hj => hJ j hj) g⟩
· have hw' : ¬ ∃ x ∈ G.nbrs v, wpF G Y x = true := hw
exact ⟨order.idxOf v, nLow G Y, by omega, fun g => case_LC hG h hv hl hd' hu hw' g⟩
· have hnu : inU G Y v = false := by simpa using hu
have hall : ∀ x ∈ G.nbrs v, order.idxOf x < nLow G Y := by
intro x hx
apply idx_of_low h (hG.nbrs_sub v x hx)
by_contra hc
have hx0 : isLow Y x = false := by simpa using hc
exact hu (inU_iff.2 ⟨hl, x, hx, hx0⟩)
obtain ⟨c, hpc, hcl, hc⟩ := exists_max (G.nbrs v) (fun x => order.idxOf x)
(order.idxOf v) (nLow G Y) hpl hall
exact ⟨order.idxOf v, c, hpc, fun g => case_LD hG h hv hl hnu hcl hpc hc g⟩
· have hh : isLow Y v = false := by simpa using hl
have hpi := idx_of_high h hv hh
by_cases hd : inD G Y v = true
· exact ⟨nLow G Y, order.idxOf v + 2 + q.length, by omega, fun g => case_HA hG h hv hh hd g⟩
· have hd' : inD G Y v = false := by simpa using hd
by_cases hw : inW G Y v = true
· have hvq : v ∈ q := (q_mem h).2 ⟨hv, wpF_iff.2 ⟨inW_iff.1 hw, hd'⟩⟩
have hfq : q.idxOf v < q.length := List.idxOf_lt_length_iff.2 hvq
exact ⟨nLow G Y + 2 + q.idxOf v, order.idxOf v + 2 + q.length, by omega,
fun g => case_HB hG h hv hh hvq g⟩
· obtain ⟨a, ha, hac⟩ := exists_lower (G.nbrs v) (fun x => order.idxOf x) (order.idxOf v)
exact ⟨a + 2 + q.length, order.idxOf v + 2 + q.length, by omega,
fun g => case_HC hG h hv hh hw ha hac g⟩
/-! ## Edges -/
/-- Two low nodes `a` (earlier) and `b` (later) adjacent: inner bag of `b`. -/
theorem edge_LL {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {a b : Nat} (ha : a ∈ G.nodes) (hb : b ∈ G.nodes)
(_hla : isLow Y a = true) (hlb : isLow Y b = true) (hab : b ∈ G.nbrs a)
(hlt : order.idxOf a < order.idxOf b) :
InBag (layoutB G Y order q) (order.idxOf b) a ∧
InBag (layoutB G Y order q) (order.idxOf b) b := by
have hbl := idx_of_low h hb hlb
constructor
· rw [inBag_layout]
exact Or.inl ⟨hbl, (mem_inner hG h hbl ha).2 (Or.inr ⟨hlt, b, hab, le_rfl⟩)⟩
· rw [inBag_layout]
exact Or.inl ⟨hbl, (mem_inner hG h hbl hb).2 (Or.inl rfl)⟩
/-- Two high nodes `a` (earlier) and `b` (later) adjacent: outer bag of `a`. -/
theorem edge_HH {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {a b : Nat} (ha : a ∈ G.nodes) (hb : b ∈ G.nodes)
(hha : isLow Y a = false) (_hhb : isLow Y b = false) (hab : a ∈ G.nbrs b)
(hlt : order.idxOf a < order.idxOf b) :
InBag (layoutB G Y order q) (order.idxOf a + 2 + q.length) a ∧
InBag (layoutB G Y order q) (order.idxOf a + 2 + q.length) b := by
have hpa := idx_of_high h ha hha
have hlen := idx_lt_length h ha
have hk : order.idxOf a + 2 + q.length - (nLow G Y + 2 + q.length) < order.length - nLow G Y := by
omega
constructor
· rw [inBag_layout]
exact Or.inr (Or.inr (Or.inr ⟨by omega, hk,
(mem_out hG h hk ha).2 (Or.inl (by omega))⟩))
· rw [inBag_layout]
exact Or.inr (Or.inr (Or.inr ⟨by omega, hk,
(mem_out hG h hk hb).2 (Or.inr ⟨by omega, a, hab, by omega⟩)⟩))
/-- A low node `u` adjacent to a high node `x`. -/
theorem edge_LH {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {u x : Nat} (hu : u ∈ G.nodes) (hx : x ∈ G.nodes)
(hlu : isLow Y u = true) (hhx : isLow Y x = false) (hux : x ∈ G.nbrs u) :
∃ g, InBag (layoutB G Y order q) g u ∧ InBag (layoutB G Y order q) g x := by
have hxu : u ∈ G.nbrs x := hG.symm u x hux
have hpx := idx_of_high h hx hhx
by_cases hdx : inD G Y x = true
· refine ⟨nLow G Y, ?_, ?_⟩
· rw [inBag_layout]
exact Or.inr (Or.inl ⟨rfl, mem_cm1.2 ⟨hu, Or.inl (inU_iff.2 ⟨hlu, x, hux, hhx⟩)⟩⟩)
· rw [inBag_layout]
exact Or.inr (Or.inl ⟨rfl, mem_cm1.2 ⟨hx, Or.inr ⟨hdx, inW_of_inD_high hdx hhx⟩⟩⟩)
· have hdx' : inD G Y x = false := by simpa using hdx
have hwpx : wpF G Y x = true := wpF_iff.2 ⟨⟨hhx, u, hxu, hlu⟩, hdx'⟩
have hxq : x ∈ q := (q_mem h).2 ⟨hx, hwpx⟩
have hfq : q.idxOf x < q.length := List.idxOf_lt_length_iff.2 hxq
by_cases hdu : inD G Y u = true
· refine ⟨nLow G Y + 1 + q.length, ?_, ?_⟩
· rw [inBag_layout]
refine Or.inr (Or.inr (Or.inl ⟨by omega, by omega, mem_cs.2 (Or.inl ⟨hu, hdu⟩)⟩))
· rw [inBag_layout]
refine Or.inr (Or.inr (Or.inl ⟨by omega, by omega, mem_cs.2 (Or.inr (Or.inr ?_))⟩))
exact (List.mem_take_iff_idxOf_lt hxq).2 (by omega)
· have hdu' : inD G Y u = false := by simpa using hdu
have hf : nLow G Y + 2 + q.idxOf x - (nLow G Y + 1) - 1 = q.idxOf x := by omega
refine ⟨nLow G Y + 2 + q.idxOf x, ?_, ?_⟩
· rw [inBag_layout]
refine Or.inr (Or.inr (Or.inl ⟨by omega, by omega, mem_cs.2 (Or.inr (Or.inl ?_))⟩))
refine ⟨hu, inU_iff.2 ⟨hlu, x, hux, hhx⟩, hdu', ⟨x, hux, hwpx⟩, ?_⟩
rw [hf]
cases hc : subsetB (eSet G Y u) (q.take (q.idxOf x)) with
| false => rfl
| true =>
have hm := subsetB_iff.1 hc x (List.mem_filter.2 ⟨hux, hwpx⟩)
rw [List.mem_take_iff_idxOf_lt hxq] at hm
omega
· rw [inBag_layout]
refine Or.inr (Or.inr (Or.inl ⟨by omega, by omega, mem_cs.2 (Or.inr (Or.inr ?_))⟩))
exact (List.mem_take_iff_idxOf_lt hxq).2 (by omega)
/-- Every edge lies in one block. -/
theorem edge_covered {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) {u x : Nat} (hu : u ∈ G.nodes) (hx : x ∈ G.nodes)
(hux : x ∈ G.nbrs u) :
∃ g, InBag (layoutB G Y order q) g u ∧ InBag (layoutB G Y order q) g x := by
have hxu : u ∈ G.nbrs x := hG.symm u x hux
have hne : u ≠ x := by
intro e
subst e
exact hG.loopless _ hux
by_cases hlu : isLow Y u = true
· by_cases hlx : isLow Y x = true
· rcases lt_trichotomy (order.idxOf u) (order.idxOf x) with hlt | heq | hgt
· obtain ⟨h1, h2⟩ := edge_LL hG h hu hx hlu hlx hux hlt
exact ⟨_, h1, h2⟩
· exfalso
apply hne
calc u = order.getD (order.idxOf u) 0 := (getD_idxOf (h.mem.2 hu)).symm
_ = order.getD (order.idxOf x) 0 := by rw [heq]
_ = x := getD_idxOf (h.mem.2 hx)
· obtain ⟨h1, h2⟩ := edge_LL hG h hx hu hlx hlu hxu hgt
exact ⟨_, h2, h1⟩
· have hhx : isLow Y x = false := by simpa using hlx
exact edge_LH hG h hu hx hlu hhx hux
· have hhu : isLow Y u = false := by simpa using hlu
by_cases hlx : isLow Y x = true
· obtain ⟨g, h1, h2⟩ := edge_LH hG h hx hu hlx hhu hxu
exact ⟨g, h2, h1⟩
· have hhx : isLow Y x = false := by simpa using hlx
rcases lt_trichotomy (order.idxOf u) (order.idxOf x) with hlt | heq | hgt
· obtain ⟨h1, h2⟩ := edge_HH hG h hu hx hhu hhx hxu hlt
exact ⟨_, h1, h2⟩
· exfalso
apply hne
calc u = order.getD (order.idxOf u) 0 := (getD_idxOf (h.mem.2 hu)).symm
_ = order.getD (order.idxOf x) 0 := by rw [heq]
_ = x := getD_idxOf (h.mem.2 hx)
· obtain ⟨h1, h2⟩ := edge_HH hG h hx hu hhx hhu hux hgt
exact ⟨_, h2, h1⟩
/-- Two bag indices holding both ends of a pair give a bag holding both. -/
theorem exists_bag_pair {bags : List Bag} {g : Nat} {u x : Nat}
(h1 : InBag bags g u) (h2 : InBag bags g x) : ∃ B ∈ bags, u ∈ B ∧ x ∈ B := by
obtain ⟨B1, hB1, hu⟩ := h1
obtain ⟨B2, hB2, hx⟩ := h2
rw [hB1] at hB2
cases hB2
exact ⟨B1, List.mem_of_getElem? hB1, hu, hx⟩
/-- Every vertex of a block of the layout is a node. -/
theorem getD_mem_order {order : List Nat} {i : Nat} (hi : i < order.length) :
order.getD i 0 ∈ order := by
rw [List.getD_eq_getElem?_getD, List.getElem?_eq_getElem hi]
simp only [Option.getD_some]
exact List.getElem_mem hi
theorem layout_valid {G : Graph} {Y : Labels} {order q : List Nat} (hG : G.WF)
(h : OrdOK G Y order q) :
ValidPD G (layoutB G Y order q) ∧ BagsWithin G (layoutB G Y order q) := by
constructor
· refine ⟨?_, ?_, ?_⟩
· intro v hv
obtain ⟨a, b, hab, hI⟩ := vertex_interval hG h hv
exact ⟨a, (hI a).2 ⟨le_rfl, hab⟩⟩
· intro v hv i j k hij hjk hi hk
obtain ⟨a, b, hab, hI⟩ := vertex_interval hG h hv
exact (hI j).2 ⟨by have := (hI i).1 hi; omega, by have := (hI k).1 hk; omega⟩
· intro u x hu hux
obtain ⟨g, h1, h2⟩ := edge_covered hG h hu (hG.nbrs_sub u x hux) hux
obtain ⟨B, hB, hu', hx'⟩ := exists_bag_pair h1 h2
exact ⟨B, hB, hu', hx'⟩
· intro B hB v hv
unfold layoutB at hB
simp only [List.mem_append, List.mem_map, List.mem_range, List.mem_singleton] at hB
rcases hB with ((⟨i, hi, rfl⟩ | rfl) | ⟨j, hj, rfl⟩) | ⟨k, hk, rfl⟩
· unfold innerB at hv
have hnl : nLow G Y ≤ order.length := by rw [h.length]; exact nLow_le
rcases List.mem_cons.1 hv with rfl | hv
· exact h.mem.1 (getD_mem_order (by omega))
· exact h.mem.1 (List.mem_of_mem_take (List.mem_of_mem_filter hv))
· exact (mem_cm1.1 hv).1
· rcases mem_cs.1 hv with ⟨h1, _⟩ | ⟨h1, _⟩ | h3
· exact h1
· exact h1
· exact ((q_mem h).1 (List.mem_of_mem_take h3)).1
· unfold outB at hv
have hnl : nLow G Y ≤ order.length := by rw [h.length]; exact nLow_le
rcases List.mem_cons.1 hv with rfl | hv
· exact h.mem.1 (getD_mem_order (by omega))
· exact (List.mem_filter.1 hv).1
/-! ## Sortedness and the link with `switchedLayout` -/
/-- The key comparator of `switchedOrder` is transitive and total. -/
theorem switchedOrder_pairwise (G : Graph) (Y : Labels) :
(switchedOrder G Y).Pairwise (fun a b => isLow Y b = true → isLow Y a = true) := by
have trans : ∀ a b c : Nat,
(decide (Y a < Y b) || (decide (Y a = Y b) && decide (a ≤ b))) = true →
(decide (Y b < Y c) || (decide (Y b = Y c) && decide (b ≤ c))) = true →
(decide (Y a < Y c) || (decide (Y a = Y c) && decide (a ≤ c))) = true := by
intro a b c h1 h2
simp only [Bool.or_eq_true, Bool.and_eq_true, decide_eq_true_eq] at h1 h2 ⊢
rcases h1 with h1 | ⟨h1, h1'⟩ <;> rcases h2 with h2 | ⟨h2, h2'⟩
· exact Or.inl (lt_trans h1 h2)
· exact Or.inl (by rw [← h2]; exact h1)
· exact Or.inl (by rw [h1]; exact h2)
· exact Or.inr ⟨h1.trans h2, by omega⟩
have total : ∀ a b : Nat,
((decide (Y a < Y b) || (decide (Y a = Y b) && decide (a ≤ b))) ||
(decide (Y b < Y a) || (decide (Y b = Y a) && decide (b ≤ a)))) = true := by
intro a b
simp only [Bool.or_eq_true, Bool.and_eq_true, decide_eq_true_eq]
rcases lt_trichotomy (Y a) (Y b) with h | h | h
· exact Or.inl (Or.inl h)
· rcases le_total a b with hab | hab
· exact Or.inl (Or.inr ⟨h, hab⟩)
· exact Or.inr (Or.inr ⟨h.symm, hab⟩)
· exact Or.inr (Or.inl h)
have hs := List.pairwise_mergeSort trans total G.nodes
unfold switchedOrder
refine hs.imp ?_
intro a b hab hb
simp only [Bool.or_eq_true, Bool.and_eq_true, decide_eq_true_eq] at hab
unfold isLow at hb ⊢
simp only [decide_eq_true_eq] at hb ⊢
rcases hab with h | ⟨h, _⟩
· exact lt_trans h hb
· rw [h]
exact hb
theorem switchedLayout_eq (G : Graph) (Y : Labels) :
switchedLayout G Y = layoutB G Y (switchedOrder G Y)
(connectorOrder (G.nodes.filter (wpF G Y)) ((pSet G Y).map (eSet G Y))) := by
unfold switchedLayout switchedLayoutF layoutB innerB outB cm1B csB nLow pSet eSet wpF
simp only [hs_contains]
rfl
end C4
/-- Main statement (plan C4): the median-switched layout is valid for every graph and
labeling. -/
theorem switchedLayoutValid_of (hWF : WFBasics) (hP : SwitchedOrderPerm)
(hC : ConnectorOrderMem) : SwitchedLayoutValid := by
intro G hG Y
have hperm : (switchedOrder G Y).Perm G.nodes := hP G Y
have hsplit : switchedOrder G Y = (switchedOrder G Y).filter (isLow Y) ++
(switchedOrder G Y).filter (fun x => !isLow Y x) :=
C4.lows_first (isLow Y) _ (C4.switchedOrder_pairwise G Y)
have hitems : ∀ e ∈ (C4.pSet G Y).map (C4.eSet G Y), ∀ z ∈ e,
z ∈ G.nodes.filter (C4.wpF G Y) := by
intro e he z hz
obtain ⟨u, _, rfl⟩ := List.mem_map.1 he
unfold C4.eSet at hz
obtain ⟨hz1, hz2⟩ := List.mem_filter.1 hz
exact List.mem_filter.2 ⟨hG.nbrs_sub u z hz1, hz2⟩
have hqmem : ∀ x, x ∈ connectorOrder (G.nodes.filter (C4.wpF G Y))
((C4.pSet G Y).map (C4.eSet G Y)) ↔ x ∈ G.nodes.filter (C4.wpF G Y) :=
fun x => hC _ _ hitems x
have hOK : C4.OrdOK G Y (switchedOrder G Y)
(connectorOrder (G.nodes.filter (C4.wpF G Y)) ((C4.pSet G Y).map (C4.eSet G Y))) :=
⟨hperm, hsplit, hqmem⟩
rw [C4.switchedLayout_eq]
exact C4.layout_valid hG hOK
end CubicPathwidth.Alg
#print axioms CubicPathwidth.Alg.switchedLayoutValid_of
Back to top