Theory Wellfounded_More

theory Wellfounded_More
imports Main
(* Title:       More about Relations
    Author:      Mathias Fleury <mathias.fleury at mpi-inf.mpg.de>
*)
section ‹Transitions›

text ‹This theory contains some facts about closure, the definition of full transformations, and
  well-foundedness.›

theory Wellfounded_More
imports Main

begin

subsection ‹More theorems about Closures›

text ‹This is the equivalent of the theorem @{thm [source] rtranclp_mono} for @{term tranclp}›
lemma tranclp_mono_explicit:
  ‹r++ a b ⟹ r ≤ s ⟹ s++ a b›
  using rtranclp_mono by (auto dest!: tranclpD intro: rtranclp_into_tranclp2)

lemma tranclp_mono:
  assumes mono: ‹r ≤ s›
  shows ‹r++ ≤ s++
  using rtranclp_mono[OF mono] mono by (auto dest!: tranclpD intro: rtranclp_into_tranclp2)

lemma tranclp_idemp_rel:
  ‹R++++ a b ⟷ R++ a b›
  apply (rule iffI)
    prefer 2 apply blast
  by (induction rule: tranclp_induct) auto

text ‹Equivalent of the theorem @{thm [source] rtranclp_idemp}›
lemma trancl_idemp: ‹(r+)+ = r+
  by simp

lemmas tranclp_idemp[simp] = trancl_idemp[to_pred]

text ‹This theorem already exists as theroem @{thm [source] Nitpick.rtranclp_unfold} (and
  sledgehammer uses it), but it makes sense to duplicate it, because it is unclear how stable the
  lemmas in the @{file ‹~~/src/HOL/Nitpick.thy›} theory are.›
lemma rtranclp_unfold: ‹rtranclp r a b ⟷ (a = b ∨ tranclp r a b)›
  by (meson rtranclp.simps rtranclpD tranclp_into_rtranclp)

(* TODO destruction rule instead of simp rule *)
lemma tranclp_unfold_end: ‹tranclp r a b ⟷ (∃a'. rtranclp r a a' ∧ r a' b)›
  by (metis rtranclp.rtrancl_refl rtranclp_into_tranclp1 tranclp.cases tranclp_into_rtranclp)

text ‹Near duplicate of theorem @{thm [source] tranclpD}:›
lemma tranclp_unfold_begin: ‹tranclp r a b ⟷ (∃a'. r a a' ∧ rtranclp r a' b)›
  by (meson rtranclp_into_tranclp2 tranclpD)

lemma trancl_set_tranclp: ‹(a, b) ∈ {(b,a). P a b}+ ⟷ P++ b a›
  apply (rule iffI)
    apply (induction rule: trancl_induct; simp)
  apply (induction rule: tranclp_induct; auto simp: trancl_into_trancl2)
  done

lemma tranclp_rtranclp_rtranclp_rel: ‹R++** a b ⟷ R** a b›
  by (simp add: rtranclp_unfold)

lemma tranclp_rtranclp_rtranclp[simp]: ‹R++** = R**
  by (fastforce simp: rtranclp_unfold)

lemma rtranclp_exists_last_with_prop:
  assumes ‹R x z› and ‹R** z z'› and ‹P x z›
  shows ‹∃y y'. R** x y ∧ R y y' ∧ P y y' ∧ (λa b. R a b ∧ ¬P a b)** y' z'›
  using assms(2,1,3)
proof induction
  case base
  then show ?case by auto
next
  case (step z' z'') note z = this(2) and IH = this(3)[OF this(4-5)]
  show ?case
    apply (cases ‹P z' z''›)
      apply (rule exI[of _ z'], rule exI[of _ z''])
      using z assms(1) step.hyps(1) step.prems(2) apply (auto; fail)[1]
    using IH z by (fastforce intro: rtranclp.rtrancl_into_rtrancl)
qed

lemma rtranclp_and_rtranclp_left: ‹(λ a b. P a b ∧ Q a b)** S T ⟹ P** S T›
  by (induction rule: rtranclp_induct) auto


subsection ‹Full Transitions›

paragraph ‹Definition›

text ‹We define here predicates to define properties after all possible transitions.›

abbreviation (input) no_step :: "('a ⇒ 'b ⇒ bool) ⇒ 'a ⇒ bool" where
"no_step step S ≡ ∀S'. ¬step S S'"

definition full1 :: "('a ⇒ 'a ⇒ bool) ⇒ 'a ⇒ 'a ⇒ bool" (*"_+"*) where
"full1 transf = (λS S'. tranclp transf S S' ∧ no_step transf S')"

definition full:: "('a ⇒ 'a ⇒ bool) ⇒ 'a ⇒ 'a ⇒ bool" (*"_"*) where
"full transf = (λS S'. rtranclp transf S S' ∧ no_step transf S')"

text ‹We define output notations only for printing (to ease reading):›
notation (output) full1 ("_+")
notation (output) full ("_")


paragraph ‹Some Properties›

lemma rtranclp_full1I:
  ‹R** a b ⟹ full1 R b c ⟹ full1 R a c›
  unfolding full1_def by auto

lemma tranclp_full1I:
  ‹R++ a b ⟹ full1 R b c ⟹ full1 R a c›
  unfolding full1_def by auto

lemma rtranclp_fullI:
  ‹R** a b ⟹ full R b c ⟹ full R a c›
  unfolding full_def by auto

lemma tranclp_full_full1I:
  ‹R++ a b ⟹ full R b c ⟹ full1 R a c›
  unfolding full_def full1_def by auto

lemma full_fullI:
  ‹R a b ⟹ full R b c ⟹ full1 R a c›
  unfolding full_def full1_def by auto

lemma full_unfold:
  ‹full r S S' ⟷ ((S = S' ∧ no_step r S') ∨ full1 r S S')›
  unfolding full_def full1_def by (auto simp add: rtranclp_unfold)

lemma full1_is_full[intro]: ‹full1 R S T ⟹ full R S T›
  by (simp add: full_unfold)

lemma not_full1_rtranclp_relation: "¬full1 R** a b"
  by (auto simp: full1_def)

lemma not_full_rtranclp_relation: "¬full R** a b"
  by (auto simp: full_def)


lemma full1_tranclp_relation_full:
  ‹full1 R++ a b ⟷ full1 R a b›
  by (metis converse_tranclpE full1_def reflclp_tranclp rtranclpD rtranclp_idemp rtranclp_reflclp
    tranclp.r_into_trancl tranclp_into_rtranclp)

lemma full_tranclp_relation_full:
  ‹full R++ a b ⟷ full R a b›
  by (metis full_unfold full1_tranclp_relation_full tranclp.r_into_trancl tranclpD)

lemma tranclp_full1_full1:
  ‹(full1 R)++ a b ⟷ full1 R a b›
  by (metis (mono_tags) full1_def predicate2I tranclp.r_into_trancl tranclp_idemp
      tranclp_mono_explicit tranclp_unfold_end)

lemma rtranclp_full1_eq_or_full1:
  ‹(full1 R)** a b ⟷ (a = b ∨ full1 R a b)›
  unfolding rtranclp_unfold tranclp_full1_full1 by simp

lemma no_step_full_iff_eq:
  ‹no_step R S ⟹ full R S T ⟷ S = T›
  unfolding full_def
  by (meson rtranclp.rtrancl_refl rtranclpD tranclpD)


subsection ‹Well-Foundedness and Full Transitions›

lemma wf_exists_normal_form:
  assumes wf: ‹wf {(x, y). R y x}›
  shows ‹∃b. R** a b ∧ no_step R b›
proof (rule ccontr)
  assume ‹¬ ?thesis›
  then have H: ‹⋀b. ¬ R** a b ∨ ¬no_step R b›
    by blast
  define F where ‹F = rec_nat a (λi b. SOME c. R b c)›
  have [simp]: ‹F 0 = a›
    unfolding F_def by auto
  have [simp]: ‹⋀i. F (Suc i) = (SOME b. R (F i) b)›
    unfolding F_def by simp
  { fix i
    have ‹∀j<i. R (F j) (F (Suc j))›
    proof (induction i)
      case 0
      then show ?case by auto
    next
      case (Suc i)
      then have ‹R** a (F i)›
        by (induction i) auto
      then have ‹R (F i) (SOME b. R (F i) b)›
        using H by (simp add: someI_ex)
      then have ‹∀j < Suc i. R (F j) (F (Suc j))›
        using H Suc by (simp add: less_Suc_eq)
      then show ?case by fast
    qed
  }
  then have ‹∀j. R (F j) (F (Suc j))› by blast
  then show False
    using wf unfolding wfP_def wf_iff_no_infinite_down_chain by blast
qed

lemma wf_exists_normal_form_full:
  assumes wf: ‹wf {(x, y). R y x}›
  shows ‹∃b. full R a b›
  using wf_exists_normal_form[OF assms] unfolding full_def by blast


subsection ‹More Well-Foundedness›

text ‹A little list of theorems that could be useful, but are hidden:
  ▪ link between @{term wf} and infinite chains: theorems
  @{thm [source] wf_iff_no_infinite_down_chain} and @{thm [source] wf_no_infinite_down_chainE}.›

lemma wf_if_measure_in_wf:
  ‹wf R ⟹ (⋀a b. (a, b) ∈ S ⟹ (ν a, ν b)∈R) ⟹ wf S›
  by (metis in_inv_image wfE_min wfI_min wf_inv_image)

lemma wfP_if_measure: fixes f :: ‹'a ⇒ nat›
  shows ‹(⋀x y. P x ⟹ g x y ⟹ f y < f x) ⟹ wf {(y,x). P x ∧ g x y}›
  apply (insert wf_measure[of f])
  apply (simp only: measure_def inv_image_def less_than_def less_eq)
  apply (erule wf_subset)
  apply auto
  done

lemma wf_if_measure_f:
  assumes ‹wf r›
  shows ‹wf {(b, a). (f b, f a) ∈ r}›
  using assms by (metis inv_image_def wf_inv_image)

lemma wf_wf_if_measure':
  assumes ‹wf r› and H: ‹⋀x y. P x ⟹ g x y ⟹ (f y, f x) ∈ r›
  shows ‹wf {(y,x). P x ∧ g x y}›
proof -
  have ‹wf {(b, a). (f b, f a) ∈ r}› using assms(1) wf_if_measure_f by auto
  then have ‹wf {(b, a). P a ∧ g a b ∧ (f b, f a) ∈ r}›
    using wf_subset[of _ ‹{(b, a). P a ∧ g a b ∧ (f b, f a) ∈ r}›] by auto
  moreover have ‹{(b, a). P a ∧ g a b ∧ (f b, f a) ∈ r} ⊆ {(b, a). (f b, f a) ∈ r}› by auto
  moreover have ‹{(b, a). P a ∧ g a b ∧ (f b, f a) ∈ r} = {(b, a). P a ∧ g a b}› using H by auto
  ultimately show ?thesis using wf_subset by simp
qed

lemma wf_lex_less: ‹wf (lex less_than)›
  by (auto simp: wf_less)

lemma wfP_if_measure2: fixes f :: ‹'a ⇒ nat›
  shows ‹(⋀x y. P x y ⟹ g x y ⟹ f x < f y) ⟹ wf {(x,y). P x y ∧ g x y}›
  apply (insert wf_measure[of f])
  apply (simp only: measure_def inv_image_def less_than_def less_eq)
  apply (erule wf_subset)
  apply auto
  done

lemma lexord_on_finite_set_is_wf:
  assumes
    P_finite: ‹⋀U. P U ⟶ U ∈ A› and
    finite: ‹finite A› and
    wf: ‹wf R› and
    trans: ‹trans R›
  shows ‹wf {(T, S). (P S ∧ P T) ∧ (T, S) ∈ lexord R}›
proof (rule wfP_if_measure2)
  fix T S
  assume P: ‹P S ∧ P T› and
  s_le_t: ‹(T, S) ∈ lexord R›
  let ?f = ‹λS. {U. (U, S) ∈ lexord R ∧ P U ∧ P S}›
  have ‹?f T ⊆ ?f S›
     using s_le_t P lexord_trans trans by auto
  moreover have ‹T ∈ ?f S›
    using s_le_t P by auto
  moreover have ‹T ∉ ?f T›
    using s_le_t by (auto simp add: lexord_irreflexive local.wf)
  ultimately have ‹{U. (U, T) ∈ lexord R ∧ P U ∧ P T} ⊂ {U. (U, S) ∈ lexord R ∧ P U ∧ P S}›
    by auto
  moreover have ‹finite {U. (U, S) ∈ lexord R ∧ P U ∧ P S}›
    using finite by (metis (no_types, lifting) P_finite finite_subset mem_Collect_eq subsetI)
  ultimately show ‹card (?f T) < card (?f S)› by (simp add: psubset_card_mono)
qed


lemma wf_fst_wf_pair:
  assumes ‹wf {(M', M). R M' M} ›
  shows ‹wf {((M', N'), (M, N)). R M' M}›
proof -
  have ‹wf ({(M', M). R M' M} <*lex*> {})›
    using assms by auto
  then show ?thesis
    by (rule wf_subset) auto
qed

lemma wf_snd_wf_pair:
  assumes ‹wf {(M', M). R M' M} ›
  shows ‹wf {((M', N'), (M, N)). R N' N}›
proof -
  have wf: ‹wf {((M', N'), (M, N)). R M' M}›
    using assms wf_fst_wf_pair by auto
  then have wf: ‹⋀P. (∀x. (∀y. (y, x) ∈ {((M', N'), M, N). R M' M} ⟶ P y) ⟶ P x) ⟹ All P›
    unfolding wf_def by auto
  show ?thesis
    unfolding wf_def
    proof (intro allI impI)
      fix P :: ‹'c × 'a ⇒ bool› and x :: ‹'c × 'a›
      assume H: ‹∀x. (∀y. (y, x) ∈ {((M', N'), M, y). R N' y} ⟶ P y) ⟶ P x›
      obtain a b where x: ‹x = (a, b)› by (cases x)
      have P: ‹P x = (P ∘ (λ(a, b). (b, a))) (b, a)›
        unfolding x by auto
      show ‹P x›
        using wf[of ‹P o (λ(a, b). (b, a))›] apply rule
          using H apply simp
        unfolding P by blast
    qed
qed

lemma wf_if_measure_f_notation2:
  assumes ‹wf r›
  shows ‹wf {(b, h a)|b a. (f b, f (h a)) ∈ r}›
  apply (rule wf_subset)
  using wf_if_measure_f[OF assms, of f] by auto

lemma wf_wf_if_measure'_notation2:
  assumes ‹wf r› and H: ‹⋀x y. P x ⟹ g x y ⟹ (f y, f (h x)) ∈ r›
  shows ‹wf {(y,h x)| y x. P x ∧ g x y}›
proof -
  have ‹wf {(b, h a)|b a. (f b, f (h a)) ∈ r}› using assms(1) wf_if_measure_f_notation2 by auto
  then have ‹wf {(b, h a)|b a. P a ∧ g a b ∧ (f b, f (h a)) ∈ r}›
    using wf_subset[of _ ‹{(b, h a)| b a. P a ∧ g a b ∧ (f b, f (h a)) ∈ r}›] by auto
  moreover have ‹{(b, h a)|b a. P a ∧ g a b ∧ (f b, f (h a)) ∈ r}
    ⊆ {(b, h a)|b a. (f b, f (h a)) ∈ r}› by auto
  moreover have ‹{(b, h a)|b a. P a ∧ g a b ∧ (f b, f (h a)) ∈ r} = {(b, h a)|b a. P a ∧ g a b}›
    using H by auto
  ultimately show ?thesis using wf_subset by simp
qed

lemma power_ex_decomp:
  assumes ‹(R^^n) S T›
  shows
    ‹∃f. f 0 = S ∧ f n = T ∧ (∀i. i < n ⟶ R (f i) (f (Suc i)))›
  using assms
proof (induction n arbitrary: T)
  case 0
  then show ‹?case› by auto
next
  case (Suc n) note IH = this(1) and R = this(2)
  from R obtain T' where
    ST: ‹(R^^n) S T'› and
    T'T: ‹R T' T›
    by auto
  obtain f where
    [simp]: ‹f 0 = S› and
    [simp]: ‹f n = T'› and
    H: ‹⋀i. i < n ⟹ R (f i) (f (Suc i))›
    using IH[OF ST] by fast
  let ?f = ‹f(Suc n := T)›
  show ?case
    by (rule exI[of _ ?f])
      (use H ST T'T in auto)
qed


text ‹The following lemma gives a bound on the maximal number of transitions of a sequence that is well-founded
  under the lexicographic ordering \<^term>‹lexn› on natural numbers.
›
lemma lexn_number_of_transition:
  assumes
    le: ‹⋀i. i < n ⟹ ((f (Suc i)), (f i)) ∈ lexn less_than m› and
    upper: ‹⋀i j. i ≤ n ⟹ j < m ⟹ (f i) ! j ∈ {0..<k}› and
    ‹finite A› and
    k: ‹k > 1›
  shows ‹n < k ^ Suc m›
proof -
  define r where
    ‹r x = zip x (map (λi. k ^ (length x -i)) [0..<length x])› for x :: ‹nat list›

  define s where
    ‹s x = foldr (λa b. a + b) (map (λ(a, b). a * b) x) 0› for x :: ‹(nat × nat) list›

  have [simp]: ‹r [] = []› ‹s [] = 0›
    by (auto simp: r_def s_def)

  have upt': ‹m > 0 ⟹ [0..< m] = 0 # map Suc [0..< m - 1]› for m
    by (auto simp: map_Suc_upt upt_conv_Cons)

  have upt'': ‹m > 0 ⟹ [0..< m] = [0..< m - 1] @ [m-1]› for m
    by (cases m) (auto simp: )

  have Cons: ‹r (x # xs) = (x, k^(Suc (length xs))) # (r xs)› for x xs
   unfolding r_def
   apply (subst upt')
   apply (clarsimp simp add: upt'' comp_def nth_append Suc_diff_le simp flip: zip_map2)
   apply (clarsimp simp add: upt'' comp_def nth_append Suc_diff_le simp flip: zip_map2)
   done

  have [simp]: ‹s (ab # xs) = fst ab * snd ab + s xs› for ab xs
    unfolding s_def by (cases ab) auto

  have le2: ‹(∀a ∈ set b. a < k) ⟹ (k ^ (Suc (length b))) > s ((r b))› for b
    apply (induction b arbitrary: f)
    using k apply (auto simp: Cons)
    apply (rule order.strict_trans1)
    apply (rule_tac j = ‹(k - 1) * k *k ^ length b› in Nat.add_le_mono1)
    subgoal for a b
      by auto
    apply (rule order.strict_trans2)
    apply (rule_tac b = ‹(k - 1) * k * k ^ length b› and d = ‹(k * k ^ length b)› in add_le_less_mono)
    apply (auto simp: mult.assoc comm_semiring_1_class.semiring_normalization_rules(2))
    done

  have ‹s (r (f (Suc i))) < s (r (f i))› if ‹i < n› for i
  proof -
    have i_n: ‹Suc i ≤ n› ‹i ≤ n›
      using that by auto
    have length: ‹length (f i) = m›  ‹length (f (Suc i)) = m›
     using le[OF that] by (auto dest: lexn_length)
    define xs and ys where ‹xs = f i› and ‹ys = f (Suc i)›

    show ?thesis
      using le[OF that] upper[OF i_n(2)] upper[OF i_n(1)] length Cons
      unfolding xs_def[symmetric] ys_def[symmetric]
    proof (induction m arbitrary: xs ys)
      case 0 then show ?case by auto
    next
      case (Suc m) note IH = this(1) and H = this(2) and p = this(3-)
      have IH: ‹(tl ys, tl xs) ∈ lexn less_than m ⟹ s (r (tl ys)) < s (r (tl xs))›
        apply (rule IH)
        subgoal by auto
        subgoal for i using p(1)[of ‹Suc i›] p by (cases xs; auto)
        subgoal for i using p(2)[of ‹Suc i›] p by (cases ys; auto)
        subgoal using p by (cases xs) auto
        subgoal using p by auto
        subgoal using p by auto
        done
     have ‹s (r (tl ys)) < k ^ (Suc (length (tl ys)))›
       apply (rule le2)
       unfolding all_set_conv_all_nth
       using p by (simp add: nth_tl)
     then have ‹ab * (k * k ^ length (tl ys)) + s (r (tl ys)) <
               ab * (k * k ^ length (tl ys)) + (k * k ^ length (tl ys))› for ab
       by auto
     also have ‹… ab  ≤ (ab + 1) * (k * k ^ length (tl ys))› for ab
       by auto
     finally have less: ‹ab < ac ⟹ ab * (k * k ^ length (tl ys)) + s (r (tl ys)) <
                                    ac * (k * k ^ length (tl ys))› for ab ac
     proof -
       assume a1: "⋀ab. ab * (k * k ^ length (tl ys)) + s (r (tl ys)) <
                   (ab + 1) * (k * k ^ length (tl ys))"
       assume "ab < ac"
       then have "¬ ac * (k * k ^ length (tl ys)) < (ab + 1) * (k * k ^ length (tl ys))"
         by (metis (no_types) One_nat_def Suc_leI add.right_neutral add_Suc_right
            mult_less_cancel2 not_less)
       then show ?thesis
         using a1 by (meson le_less_trans not_less)
     qed

    have ‹ab < ac ⟹
        ab * (k * k ^ length (tl ys)) + s (r (tl ys))
        < ac * (k * k ^ length (tl xs)) + s (r (tl xs))› for ab ac
        using less[of ab ac] p by auto
    then show ?case
         apply (cases xs; cases ys)
        using IH H p(3-5) by auto
    qed
  qed
  then have ‹i≤n ⟹ s (r (f i)) + i ≤ s (r (f 0))› for i
    apply (induction i)
    subgoal by auto
    subgoal premises p for i
       using p(3)[of ‹i-1›] p(1,2)
      apply auto
      by (meson Nat.le_diff_conv2 Suc_leI Suc_le_lessD add_leD2 less_diff_conv less_le_trans p(3))
    done
  from this[of n] show ‹n < k ^ Suc m›
    using le2[of ‹f 0›] upper[of 0] k
    using le[of 0] apply (cases ‹n = 0›)
    by (auto dest!: lexn_length simp: all_set_conv_all_nth eq_commute[of _ m])
qed

end