Theory Tree
theory Tree 
  imports Main
begin
subsection "Tree"
inductive_set
  tree :: "['a ⇒ 'a set,'a] ⇒ (nat * 'a) set"
  for subs :: "'a ⇒ 'a set" and γ :: 'a
    
  where
    tree0: "(0,γ) ∈ tree subs γ"
  | tree1: "⟦(n,delta) ∈ tree subs γ; sigma ∈ subs delta⟧
            ⟹ (Suc n,sigma) ∈ tree subs γ"
declare tree.cases [elim]
declare tree.intros [intro]
lemma tree0Eq: "(0,y) ∈ tree subs γ = (y = γ)"
  by auto
lemma tree1Eq:
    "(Suc n,Y) ∈ tree subs γ ⟷ (∃sigma ∈ subs γ . (n,Y) ∈ tree subs sigma)"
  by (induct n arbitrary: Y) force+
    
definition
  incLevel :: "nat * 'a ⇒ nat * 'a" where
  "incLevel = (% (n,a). (Suc n,a))"
lemma injIncLevel: "inj incLevel"
  by (simp add: incLevel_def inj_on_def)
lemma treeEquation: "tree subs γ = insert (0,γ) (⋃delta∈subs γ. incLevel ` tree subs delta)"
proof -
  have "a = 0 ∧ b = γ"
    if "(a, b) ∈ tree subs γ"
      and "∀x∈subs γ. ∀(n, x) ∈tree subs x. (a, b) ≠ (Suc n, x)"
    for a b
    using that Zero_not_Suc
    by (smt (verit) case_prod_conv tree.cases tree1Eq)
  then show ?thesis
    by (auto simp: incLevel_def image_iff tree1Eq case_prod_unfold)
qed
definition
  fans :: "['a ⇒ 'a set] ⇒ bool" where
  "fans subs ≡ (∀x. finite (subs x))"
subsection "Terminal"
definition
  terminal :: "['a ⇒ 'a set,'a] ⇒ bool" where
  "terminal subs delta ≡ subs(delta) = {}"
lemma terminalD: "terminal subs Γ ⟹ x ~: subs Γ"
  by(simp add: terminal_def)
  
lemma terminalI: "x ∈ subs Γ ⟹ ¬ terminal subs Γ"
  by(auto simp add: terminal_def)
  
subsection "Inherited"
definition
  inherited :: "['a ⇒ 'a set,(nat * 'a) set ⇒ bool] ⇒ bool" where
  "inherited subs P ≡ (∀A B. (P A ∧ P B) = P (A Un B))
                    ∧ (∀A. P A = P (incLevel ` A))
                    ∧ (∀n Γ A. ¬(terminal subs Γ) ⟶ P A = P (insert (n,Γ) A))
                    ∧ (P {})"
    
  
lemma inheritedUn[rule_format]:"inherited subs P ⟶ P A ⟶ P B ⟶ P (A Un B)"
  by (auto simp add: inherited_def)
lemma inheritedIncLevel[rule_format]: "inherited subs P ⟶ P A ⟶ P (incLevel ` A)"
  by (auto simp add: inherited_def)
lemma inheritedEmpty[rule_format]: "inherited subs P ⟶ P {}"
  by (auto simp add: inherited_def)
lemma inheritedInsert[rule_format]:
  "inherited subs P ⟶ ~(terminal subs Γ) ⟶ P A ⟶ P (insert (n,Γ) A)"
  by (auto simp add: inherited_def)
lemma inheritedI[rule_format]: "⟦∀A B . (P A ∧ P B) = P (A Un B);
  ∀A . P A = P (incLevel ` A);
  ∀n Γ A . ~(terminal subs Γ) ⟶ P A = P (insert (n,Γ) A);
  P {}⟧ ⟹ inherited subs P"
  by (simp add: inherited_def)
lemma inheritedUnEq[rule_format, symmetric]: "inherited subs P ⟶ (P A ∧ P B) = P (A Un B)"
  by (auto simp add: inherited_def)
lemma inheritedIncLevelEq[rule_format, symmetric]: "inherited subs P ⟶ P A = P (incLevel ` A)"
  by (auto simp add: inherited_def)
lemma inheritedInsertEq[rule_format, symmetric]: "inherited subs P ⟶ ~(terminal subs Γ) ⟶ P A = P (insert (n,Γ) A)"
  by (auto simp add: inherited_def)
lemmas inheritedUnD = iffD1[OF inheritedUnEq]
lemmas inheritedInsertD = inheritedInsertEq[THEN iffD1]
lemmas inheritedIncLevelD = inheritedIncLevelEq[THEN iffD1]
lemma inheritedUNEq:
  "finite A ⟹ inherited subs P ⟹ (∀x∈A. P (B x)) = P (⋃ a∈A. B a)"
  by (induction rule: finite_induct) (simp_all add: inherited_def)
lemmas inheritedUN  = inheritedUNEq[THEN iffD1]
lemmas inheritedUND[rule_format] = inheritedUNEq[THEN iffD2]
lemma inheritedPropagateEq: 
  assumes "inherited subs P"
  and "fans subs"
  and "¬ (terminal subs delta)"
shows "P(tree subs delta) = (∀sigma∈subs delta. P(tree subs sigma))"
  using assms unfolding fans_def
  by (metis (mono_tags, lifting) inheritedIncLevelEq inheritedInsertEq inheritedUNEq treeEquation)
lemma inheritedPropagate:
 " ⟦¬ P (tree subs delta); inherited subs P; fans subs; ¬ terminal subs delta⟧
    ⟹ ∃sigma∈subs delta. ¬ P (tree subs sigma)"
  by (simp add: inheritedPropagateEq)
lemma inheritedViaSub:
  "⟦inherited subs P; fans subs; P (tree subs delta); sigma ∈ subs delta⟧ ⟹ P (tree subs sigma)"
  by (simp add: inheritedPropagateEq terminalI)
lemma inheritedJoin:
    "⟦inherited subs P; inherited subs Q⟧ ⟹ inherited subs (λx. P x ∧ Q x)"
  by (smt (verit, best) inherited_def)
lemma inheritedJoinI:
  "⟦inherited subs P; inherited subs Q; R = (λx. P x ∧ Q x)⟧
    ⟹ inherited subs R"
  by (simp add: inheritedJoin)
subsection "bounded, boundedBy"
definition
  boundedBy :: "nat ⇒ (nat * 'a) set ⇒ bool" where
  "boundedBy N A ≡ (∀(n,delta) ∈ A. n < N)"
definition
  bounded :: "(nat * 'a) set ⇒ bool" where
  "bounded A ≡ (∃N . boundedBy N A)"
lemma boundedByEmpty[simp]: "boundedBy N {}"
  by(simp add: boundedBy_def)
lemma boundedByInsert: "boundedBy N (insert (n,delta) B)     = (n < N ∧ boundedBy N B)"
  by(simp add: boundedBy_def)
lemma boundedByUn: "boundedBy N (A Un B) = (boundedBy N A ∧ boundedBy N B)"
  by(auto simp add: boundedBy_def)
lemma boundedByIncLevel': "boundedBy (Suc N) (incLevel ` A) = boundedBy N A"
  by(auto simp add: incLevel_def boundedBy_def)
lemma boundedByAdd1: "boundedBy N B ⟹ boundedBy (N+M) B"
  by(auto simp add: boundedBy_def)
lemma boundedByAdd2: "boundedBy M B ⟹ boundedBy (N+M) B"
  by(auto simp add: boundedBy_def)
lemma boundedByMono: "boundedBy m B ⟹ m < M ⟹ boundedBy M B"
  by(auto simp: boundedBy_def)
lemmas boundedByMonoD  = boundedByMono
lemma boundedBy0: "boundedBy 0 A = (A = {})"
  by (auto simp add: boundedBy_def)
lemma boundedBySuc': "boundedBy N A ⟹ boundedBy (Suc N) A"
  by (auto simp add: boundedBy_def)
lemma boundedByIncLevel: "boundedBy n (incLevel ` (tree subs γ)) ⟷ (∃m . n = Suc m ∧ boundedBy m (tree subs γ))"
  by (metis boundedBy0 boundedByIncLevel' boundedBySuc' emptyE old.nat.exhaust
      tree.tree0)
lemma boundedByUN: "boundedBy N (UN x:A. B x) = (!x:A. boundedBy N (B x))"
  by(simp add: boundedBy_def)
lemma boundedBySuc[rule_format]: "sigma ∈ subs Γ ⟹ boundedBy (Suc n) (tree subs Γ) ⟹ boundedBy n (tree subs sigma)"
  by (metis boundedByIncLevel' boundedByInsert boundedByUN treeEquation)
subsection "Inherited Properties- bounded"
lemma boundedEmpty: "bounded {}"
  by(simp add: bounded_def)
lemma boundedUn: "bounded (A Un B) ⟷ (bounded A ∧ bounded B)"
  by (metis boundedByAdd1 boundedByAdd2 boundedByUn bounded_def)
lemma boundedIncLevel: "bounded (incLevel` A) ⟷ (bounded A)"
  by (meson boundedByIncLevel' boundedBySuc' bounded_def)
lemma boundedInsert: "bounded (insert a B) ⟷ (bounded B)"
proof (cases a)
  case (Pair a b)
  then show ?thesis
  by (metis Un_insert_left Un_insert_right boundedByEmpty boundedByInsert boundedUn
      bounded_def lessI)
qed
lemma inheritedBounded: "inherited subs bounded"
  by(blast intro!: inheritedI boundedUn[symmetric] boundedIncLevel[symmetric]
    boundedInsert[symmetric] boundedEmpty)
subsection "founded"
definition
  founded :: "['a ⇒ 'a set,'a ⇒ bool,(nat * 'a) set] ⇒ bool" where
  "founded subs Pred = (%A. !(n,delta):A. terminal subs delta ⟶ Pred delta)"
lemma foundedD: "founded subs P (tree subs delta) ⟹ terminal subs delta ⟹ P delta"
  by(simp add: treeEquation [of _ delta] founded_def)
lemma foundedMono: "⟦founded subs P A; ∀x. P x ⟶ Q x⟧ ⟹ founded subs Q A"
  by (auto simp: founded_def)
lemma foundedSubs: "founded subs P (tree subs Γ) ⟹ sigma ∈ subs Γ ⟹ founded subs P (tree subs sigma)"
  using tree1Eq by (fastforce simp: founded_def)
subsection "Inherited Properties- founded"
lemma foundedInsert: "¬ terminal subs delta ⟹ founded subs P (insert (n,delta) B) = (founded subs P B)"
  by (simp add: terminal_def founded_def) 
lemma foundedUn: "(founded subs P (A Un B)) = (founded subs P A ∧ founded subs P B)"
  by(force simp add: founded_def)
lemma foundedIncLevel: "founded subs P (incLevel ` A) = (founded subs P A)"
  by (simp add: case_prod_unfold founded_def incLevel_def)
lemma foundedEmpty: "founded subs P {}"
  by(auto simp add: founded_def)
lemma inheritedFounded: "inherited subs (founded subs P)"
  by (simp add: foundedEmpty foundedIncLevel foundedInsert foundedUn inherited_def)
subsection "Inherited Properties- finite"
lemma finiteUn: "finite (A Un B) = (finite A ∧ finite B)"
  by simp
lemma finiteIncLevel: "finite (incLevel ` A) = finite A"
  by (meson finite_imageD finite_imageI injIncLevel inj_on_subset subset_UNIV)
lemma inheritedFinite: "inherited subs finite"
  by (simp add: finiteIncLevel inherited_def)
subsection "path: follows a failing inherited property through tree"
definition
  failingSub :: "['a ⇒ 'a set,(nat * 'a) set ⇒ bool,'a] ⇒ 'a" where
  "failingSub subs P γ ≡ (SOME sigma. (sigma:subs γ ∧ ~P(tree subs sigma)))"
lemma failingSubProps: 
  "⟦inherited subs P; ¬ P (tree subs γ); ¬ terminal subs γ; fans subs⟧
   ⟹ failingSub subs P γ ∈ subs γ ∧ ¬ P (tree subs (failingSub subs P γ))"
  unfolding failingSub_def
  by (metis (mono_tags, lifting) inheritedPropagateEq some_eq_ex)
lemma failingSubFailsI: 
  "⟦inherited subs P; ¬ P (tree subs γ); ¬ terminal subs γ; fans subs⟧
   ⟹ ¬ P (tree subs (failingSub subs P γ))"
  by (simp add: failingSubProps)
lemmas failingSubFailsE = failingSubFailsI[THEN notE]
lemma failingSubSubs: 
  "⟦inherited subs P; ¬ P (tree subs γ); ¬ terminal subs γ; fans subs⟧
    ⟹ failingSub subs P γ ∈ subs γ"
  by (simp add: failingSubProps)
primrec path :: "['a ⇒ 'a set,'a,(nat * 'a) set ⇒ bool,nat] ⇒ 'a"
where
  path0:   "path subs γ P 0       = γ"
| pathSuc: "path subs γ P (Suc n) = (if terminal subs (path subs γ P n)
                                          then path subs γ P n
                                          else failingSub subs P (path subs γ P n))"
lemma pathFailsP: 
  "⟦inherited subs P; fans subs; ¬ P (tree subs γ)⟧
    ⟹ ¬ P (tree subs (path subs γ P n))"
  by (induction n) (simp_all add: failingSubProps)
lemmas PpathE = pathFailsP[THEN notE]
lemma pathTerminal:
  "⟦inherited subs P; fans subs; terminal subs γ⟧
   ⟹ terminal subs (path subs γ P n)"
  by (induct n, simp_all)
lemma pathStarts:  "path subs γ P 0 = γ"
  by simp
lemma pathSubs: 
  "⟦inherited subs P; fans subs; ¬ P (tree subs γ); ¬ terminal subs (path subs γ P n)⟧
    ⟹ path subs γ P (Suc n) ∈ subs (path subs γ P n)"
  by (metis PpathE failingSubSubs pathSuc)
lemma pathStops: "terminal subs (path subs γ P n) ⟹ path subs γ P (Suc n) = path subs γ P n"
  by simp
subsection "Branch"
definition
  branch :: "['a ⇒ 'a set,'a,nat ⇒ 'a] ⇒ bool" where
  "branch subs Γ f ⟷ f 0 = Γ
    ∧ (!n . terminal subs (f n) ⟶ f (Suc n) = f n)
    ∧ (!n . ¬ terminal subs (f n) ⟶ f (Suc n) ∈ subs (f n))"
lemma branch0: "branch subs Γ f ⟹ f 0 = Γ"
  by (simp add: branch_def)
lemma branchStops: "branch subs Γ f ⟹ terminal subs (f n) ⟹ f (Suc n) = f n"
  by (simp add: branch_def)
lemma branchSubs: "branch subs Γ f ⟹ ¬ terminal subs (f n) ⟹ f (Suc n) ∈ subs (f n)"
  by (simp add: branch_def)
lemma branchI: "⟦f 0 = Γ;
  ∀n . terminal subs (f n) ⟶ f (Suc n) = f n;
  ∀n . ¬ terminal subs (f n) ⟶ f (Suc n) ∈ subs (f n)⟧ ⟹ branch subs Γ f"
  by (simp add: branch_def)
lemma branchTerminalPropagates: "branch subs Γ f ⟹ terminal subs (f m) ⟹ terminal subs (f (m + n))"
  by (induct n, simp_all add: branchStops)
lemma branchTerminalMono: 
  "branch subs Γ f ⟹ m < n ⟹ terminal subs (f m) ⟹ terminal subs (f n)"
  by (metis branchTerminalPropagates
      canonically_ordered_monoid_add_class.lessE)
lemma branchPath:
      "⟦inherited subs P; fans subs; ¬ P(tree subs γ)⟧
       ⟹ branch subs γ (path subs γ P)"
  by(auto intro!: branchI pathStarts pathSubs pathStops)
subsection "failing branch property: abstracts path defn"
lemma failingBranchExistence:  
  "⟦inherited subs P; fans subs; ~P(tree subs γ)⟧
  ⟹ ∃f . branch subs γ f ∧ (∀n . ¬ P(tree subs (f n)))"
  by (metis PpathE branchPath)
definition
  infBranch :: "['a ⇒ 'a set,'a,nat ⇒ 'a] ⇒ bool" where
  "infBranch subs Γ f ⟷ f 0 = Γ ∧ (∀n. f (Suc n) ∈ subs (f n))"
lemma infBranchI: "⟦f 0 = Γ; ∀n . f (Suc n) ∈ subs (f n)⟧ ⟹ infBranch subs Γ f"
  by (simp add: infBranch_def)
subsection "Tree induction principles"
  
lemma boundedTreeInduction':
 "⟦ fans subs;
    ∀delta. ¬ terminal subs delta ⟶ (∀sigma ∈ subs delta. P sigma) ⟶ P delta ⟧
  ⟹ ∀Γ. boundedBy m (tree subs Γ) ⟶  founded subs P (tree subs Γ) ⟶ P Γ"
proof (induction m)
  case 0
  then show ?case by (metis boundedBy0 empty_iff tree.tree0)
next
  case (Suc m)
  then show ?case by (metis boundedBySuc foundedD foundedSubs)
qed
  
 
  
lemma boundedTreeInduction:
   "⟦fans subs;
     bounded (tree subs Γ); founded subs P (tree subs Γ);
  ⋀delta. ⟦¬ terminal subs delta; (∀sigma ∈ subs delta. P sigma)⟧ ⟹ P delta
  ⟧ ⟹ P Γ"
  by (metis boundedTreeInduction' bounded_def)
lemma boundedTreeInduction2:
 "⟦fans subs;
    ∀delta. (∀sigma ∈ subs delta. P sigma) ⟶ P delta⟧
  ⟹ boundedBy m (tree subs Γ) ⟶ P Γ"
proof (induction m arbitrary: Γ)
  case 0
  then show ?case by (metis boundedBy0 empty_iff tree.tree0)
next
  case (Suc m)
  then show ?case by (metis boundedBySuc)
qed
end