# Theory Kruskal

```(*  Title:      Well-Quasi-Orders
Author:     Christian Sternagel <c.sternagel@gmail.com>
Maintainer: Christian Sternagel
*)

section ‹Kruskal's Tree Theorem›

theory Kruskal
imports Well_Quasi_Orders
begin

locale kruskal_tree =
fixes F :: "('b × nat) set"
and mk :: "'b ⇒ 'a list ⇒ ('a::size)"
and root :: "'a ⇒ 'b × nat"
and args :: "'a ⇒ 'a list"
and trees :: "'a set"
assumes size_arg: "t ∈ trees ⟹ s ∈ set (args t) ⟹ size s < size t"
and root_mk: "(f, length ts) ∈ F ⟹ root (mk f ts) = (f, length ts)"
and args_mk: "(f, length ts) ∈ F ⟹ args (mk f ts) = ts"
and mk_root_args: "t ∈ trees ⟹ mk (fst (root t)) (args t) = t"
and trees_root: "t ∈ trees ⟹ root t ∈ F"
and trees_arity: "t ∈ trees ⟹ length (args t) = snd (root t)"
and trees_args: "⋀s. t ∈ trees ⟹ s ∈ set (args t) ⟹ s ∈ trees"
begin

lemma mk_inject [iff]:
assumes "(f, length ss) ∈ F" and "(g, length ts) ∈ F"
shows "mk f ss = mk g ts ⟷ f = g ∧ ss = ts"
proof -
{ assume "mk f ss = mk g ts"
then have "root (mk f ss) = root (mk g ts)"
and "args (mk f ss) = args (mk g ts)" by auto }
show ?thesis
using root_mk [OF assms(1)] and root_mk [OF assms(2)]
and args_mk [OF assms(1)] and args_mk [OF assms(2)] by auto
qed

inductive emb for P
where
arg: "⟦(f, m) ∈ F; length ts = m; ∀t∈set ts. t ∈ trees;
t ∈ set ts; emb P s t⟧ ⟹ emb P s (mk f ts)" |
list_emb: "⟦(f, m) ∈ F; (g, n) ∈ F; length ss = m; length ts = n;
∀s ∈ set ss. s ∈ trees; ∀t ∈ set ts. t ∈ trees;
P (f, m) (g, n); list_emb (emb P) ss ts⟧ ⟹ emb P (mk f ss) (mk g ts)"
monos list_emb_mono

lemma almost_full_on_trees:
assumes "almost_full_on P F"
shows "almost_full_on (emb P) trees" (is "almost_full_on ?P ?A")
proof (rule ccontr)
interpret mbs ?A .
assume "¬ ?thesis"
from mbs' [OF this] obtain m
and min: "∀g. (m, g) ∈ gseq ⟶ good ?P g" ..
then have trees: "⋀i. m i ∈ trees" by auto

define r where "r i = root (m i)" for i
define a where "a i = args (m i)" for i
define S where "S = ⋃{set (a i) | i. True}"

have m: "⋀i. m i = mk (fst (r i)) (a i)"
by (simp add: r_def a_def mk_root_args [OF trees])
have lists: "∀i. a i ∈ lists S" by (auto simp: a_def S_def)
have arity: "⋀i. length (a i) = snd (r i)"
using trees_arity [OF trees] by (auto simp: r_def a_def)
then have sig: "⋀i. (fst (r i), length (a i)) ∈ F"
using trees_root [OF trees] by (auto simp: a_def r_def)
have a_trees: "⋀i. ∀t ∈ set (a i). t ∈ trees" by (auto simp: a_def trees_args [OF trees])

have "almost_full_on ?P S"
proof (rule ccontr)
assume "¬ ?thesis"
then obtain s :: "nat ⇒ 'a"
where S: "⋀i. s i ∈ S" and bad_s: "bad ?P s" by (auto simp: almost_full_on_def)

define n where "n = (LEAST n. ∃k. s k ∈ set (a n))"
have "∃n. ∃k. s k ∈ set (a n)" using S by (force simp: S_def)
from LeastI_ex [OF this] obtain k
where sk: "s k ∈ set (a n)" by (auto simp: n_def)
have args: "⋀k. ∃m ≥ n. s k ∈ set (a m)"
using S by (auto simp: S_def) (metis Least_le n_def)

define m' where "m' i = (if i < n then m i else s (k + (i - n)))" for i

have m'_less: "⋀i. i < n ⟹ m' i = m i" by (simp add: m'_def)
have m'_geq: "⋀i. i ≥ n ⟹ m' i = s (k + (i - n))" by (simp add: m'_def)

proof
assume "good ?P m'"
then obtain i j where "i < j" and emb: "?P (m' i) (m' j)" by auto
{ assume "j < n"
with ‹i < j› and emb have "?P (m i) (m j)" by (auto simp: m'_less)
with ‹i < j› and bad have False by blast }
moreover
{ assume "n ≤ i"
with ‹i < j› and emb have "?P (s (k + (i - n))) (s (k + (j - n)))"
and "k + (i - n) < k + (j - n)" by (auto simp: m'_geq)
with bad_s have False by auto }
moreover
{ assume "i < n" and "n ≤ j"
with ‹i < j› and emb have *: "?P (m i) (s (k + (j - n)))" by (auto simp: m'_less m'_geq)
with args obtain l where "l ≥ n" and **: "s (k + (j - n)) ∈ set (a l)" by blast
from emb.arg [OF sig [of l] _ a_trees [of l] ** *]
have "?P (m i) (m l)" by (simp add: m)
moreover have "i < l" using ‹i < n› and ‹n ≤ l› by auto
ultimately have False using bad by blast }
ultimately show False using ‹i < j› by arith
qed
moreover have "(m, m') ∈ gseq"
proof -
have "m ∈ SEQ ?A" using trees by auto
moreover have "m' ∈ SEQ ?A"
using trees and S and trees_args [OF trees] by (auto simp: m'_def a_def S_def)
moreover have "∀i < n. m i = m' i" by (auto simp: m'_less)
moreover have "size (m' n) < size (m n)"
using sk and size_arg [OF trees, unfolded m]
by (auto simp: m m'_geq root_mk [OF sig] args_mk [OF sig])
ultimately show ?thesis by (auto simp: gseq_def)
qed
ultimately show False using min by blast
qed
from almost_full_on_lists [OF this, THEN almost_full_on_imp_homogeneous_subseq, OF lists]
obtain φ :: "nat ⇒ nat"
where less: "⋀i j. i < j ⟹ φ i < φ j"
and lemb: "⋀i j. i < j ⟹ list_emb ?P (a (φ i)) (a (φ j))" by blast
have roots: "⋀i. r (φ i) ∈ F" using trees [THEN trees_root] by (auto simp: r_def)
then have "r ∘ φ ∈ SEQ F" by auto
with assms have "good P (r ∘ φ)" by (auto simp: almost_full_on_def)
then obtain i j
where "i < j" and "P (r (φ i)) (r (φ j))" by auto
with lemb [OF ‹i < j›] have "?P (m (φ i)) (m (φ j))"
using sig and arity and a_trees by (auto simp: m intro!: emb.list_emb)
with less [OF ‹i < j›] and bad show False by blast
qed

inductive_cases
emb_mk2 [consumes 1, case_names arg list_emb]: "emb P s (mk g ts)"

inductive_cases
list_emb_Nil2_cases: "list_emb P xs []" and
list_emb_Cons_cases: "list_emb P xs (y#ys)"

lemma list_emb_trans_right:
assumes "list_emb P xs ys" and "list_emb (λy z. P y z ∧ (∀x. P x y ⟶ P x z)) ys zs"
shows "list_emb P xs zs"
using assms(2, 1) by (induct arbitrary: xs) (auto elim!: list_emb_Nil2_cases list_emb_Cons_cases)

lemma emb_trans:
assumes trans: "⋀f g h. f ∈ F ⟹ g ∈ F ⟹ h ∈ F ⟹ P f g ⟹ P g h ⟹ P f h"
assumes "emb P s t" and "emb P t u"
shows "emb P s u"
using assms(3, 2)
proof (induct arbitrary: s)
case (arg f m ts v)
then show ?case by (auto intro: emb.arg)
next
case (list_emb f m g n ss ts)
note IH = this
from ‹emb P s (mk f ss)›
show ?case
proof (cases rule: emb_mk2)
case arg
then show ?thesis using IH by (auto elim!: list_emb_set intro: emb.arg)
next
case list_emb
then show ?thesis using IH by (auto intro: emb.intros dest: trans list_emb_trans_right)
qed
qed

lemma transp_on_emb:
assumes "transp_on F P"
shows "transp_on trees (emb P)"
using assms and emb_trans [of P] unfolding transp_on_def by blast

lemma kruskal:
assumes "wqo_on P F"
shows "wqo_on (emb P) trees"
using almost_full_on_trees [of P] and assms by (metis transp_on_emb wqo_on_def)

end

end

```