Theory Min_Max_Least_Greatest.Relation_Reachability
theory Relation_Reachability
  imports Main
begin
section ‹Definitions›
text ‹When a binary relation hold for two values, i.e., \<^term>‹R x y›, we say that \<^term>‹x› reaches
\<^term>‹y› and, conversely, that \<^term>‹y› is reachable by \<^term>‹x›.›
definition non_reachable_wrt where
  "non_reachable_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X - {x}. ¬ (R y x))"
definition non_reaching_wrt where
  "non_reaching_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X - {x}. ¬ (R x y))"
definition reaching_all_wrt where
  "reaching_all_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X - {x}. R x y)"
definition reachable_by_all_wrt where
  "reachable_by_all_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X - {x}. R y x)"
section ‹Conversions›
lemma non_reachable_wrt_iff:
  "non_reachable_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X. y ≠ x ⟶ ¬ R y x)"
  unfolding non_reachable_wrt_def by blast
lemma non_reaching_wrt_iff:
  "non_reaching_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X. y ≠ x ⟶ ¬ R x y)"
  unfolding non_reaching_wrt_def by blast
lemma reaching_all_wrt_iff:
  "reaching_all_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X. y ≠ x ⟶ R x y)"
  unfolding reaching_all_wrt_def by blast
lemma reachable_by_all_wrt_iff:
  "reachable_by_all_wrt R X x ⟷ x ∈ X ∧ (∀y ∈ X. y ≠ x ⟶ R y x)"
  unfolding reachable_by_all_wrt_def by blast
lemma non_reachable_wrt_filter_iff:
  "non_reachable_wrt R {y ∈ X. P y} x ⟷ x ∈ X ∧ P x ∧ (∀y ∈ X - {x}. P y ⟶ ¬ R y x)"
  by (auto simp: non_reachable_wrt_def)
lemma non_reachable_wrt_conversep[simp]:
  "non_reachable_wrt R¯¯ = non_reaching_wrt R"
  unfolding non_reaching_wrt_def non_reachable_wrt_def by simp
lemma non_reaching_wrt_conversep[simp]:
  "non_reaching_wrt R¯¯ = non_reachable_wrt R"
  unfolding non_reaching_wrt_def non_reachable_wrt_def by simp
lemma reaching_all_wrt_conversep[simp]:
  "reaching_all_wrt R¯¯ = reachable_by_all_wrt R"
  unfolding reaching_all_wrt_def reachable_by_all_wrt_def by simp
lemma reachable_by_all_wrt_conversep[simp]:
  "reachable_by_all_wrt R¯¯ = reaching_all_wrt R"
  unfolding reaching_all_wrt_def reachable_by_all_wrt_def by simp
lemma non_reachable_wrt_eq_reaching_all_wrt:
  assumes asym: "asymp_on X R" and tot: "totalp_on X R"
  shows "non_reachable_wrt R X = reaching_all_wrt R X"
proof (intro ext iffI)
  fix x
  from tot show "non_reachable_wrt R X x ⟹ reaching_all_wrt R X x"
    unfolding non_reachable_wrt_def reaching_all_wrt_def
    by (metis Diff_iff insertCI totalp_onD)
next
  fix x
  from asym show "reaching_all_wrt R X x ⟹ non_reachable_wrt R X x"
    unfolding reaching_all_wrt_def non_reachable_wrt_def
    by (metis Diff_iff asymp_onD)
qed
lemma non_reaching_wrt_eq_reachable_by_all_wrt:
  assumes asym: "asymp_on X R" and tot: "totalp_on X R"
  shows "non_reaching_wrt R X = reachable_by_all_wrt R X"
proof (intro ext iffI)
  fix x
  from tot show "non_reaching_wrt R X x ⟹ reachable_by_all_wrt R X x"
    unfolding non_reaching_wrt_def reachable_by_all_wrt_def
    by (metis Diff_iff insertCI totalp_onD)
next
  fix x
  from asym show "reachable_by_all_wrt R X x ⟹ non_reaching_wrt R X x"
    unfolding reachable_by_all_wrt_def non_reaching_wrt_def
    by (metis Diff_iff asymp_onD)
qed
lemma non_reachable_wrt_reflclp[simp]:
  "non_reachable_wrt R⇧=⇧= = non_reachable_wrt R"
  by (intro ext iffI) (simp_all add: non_reachable_wrt_iff)
lemma non_reaching_wrt_reflclp[simp]:
  "non_reaching_wrt R⇧=⇧= = non_reaching_wrt R"
  by (intro ext iffI) (simp_all add: non_reaching_wrt_iff)
lemma reaching_all_wrt_reflclp[simp]:
  "reaching_all_wrt R⇧=⇧= = reaching_all_wrt R"
  by (intro ext iffI) (simp_all add: reaching_all_wrt_iff)
lemma reachable_by_all_wrt_reflclp[simp]:
  "reachable_by_all_wrt R⇧=⇧= = reachable_by_all_wrt R"
  by (intro ext iffI) (simp_all add: reachable_by_all_wrt_iff)
section ‹Existence›
lemma ex_non_reachable_wrt:
  "transp_on A R ⟹ asymp_on A R ⟹ finite A ⟹ A ≠ {} ⟹ ∃m. non_reachable_wrt R A m"
  using Finite_Set.bex_min_element
  by (metis non_reachable_wrt_iff)
lemma ex_non_reaching_wrt:
  "transp_on A R ⟹ asymp_on A R ⟹ finite A ⟹ A ≠ {} ⟹ ∃m. non_reaching_wrt R A m"
  using Finite_Set.bex_max_element
  by (metis non_reaching_wrt_iff)
lemma ex_reaching_all_wrt:
  "transp_on A R ⟹ totalp_on A R ⟹ finite A ⟹ A ≠ {} ⟹ ∃g. reaching_all_wrt R A g"
  using Finite_Set.bex_least_element[of A R]
  by (metis reaching_all_wrt_iff)
lemma ex_reachable_by_all_wrt:
  "transp_on A R ⟹ totalp_on A R ⟹ finite A ⟹ A ≠ {} ⟹ ∃g. reachable_by_all_wrt R A g"
  using Finite_Set.bex_greatest_element[of A R]
  by (metis reachable_by_all_wrt_iff)
lemma not_ex_greatest_element_doubleton_if:
  assumes "x ≠ y" and "¬ R x y" and "¬ R y x"
  shows "∄g. reachable_by_all_wrt R {x, y} g"
proof (rule notI)
  assume "∃g. reachable_by_all_wrt R {x, y} g"
  then obtain g where "reachable_by_all_wrt R {x, y} g" ..
  then show False
    unfolding reachable_by_all_wrt_def
    using assms(1) assms(2) assms(3) by blast
qed
section ‹Uniqueness›
lemma Uniq_non_reachable_wrt:
  "totalp_on X R ⟹ ∃⇩≤⇩1x. non_reachable_wrt R X x"
  by (rule Uniq_I) (metis insert_Diff insert_iff non_reachable_wrt_def totalp_onD)
lemma Uniq_non_reaching_wrt:
  "totalp_on X R ⟹ ∃⇩≤⇩1x. non_reaching_wrt R X x"
  by (rule Uniq_I) (metis insert_Diff insert_iff non_reaching_wrt_def totalp_onD)
lemma Uniq_reaching_all_wrt:
  "asymp_on X R ⟹ ∃⇩≤⇩1x. reaching_all_wrt R X x"
  by (rule Uniq_I)
    (metis antisymp_onD antisymp_on_if_asymp_on insertE insert_Diff reaching_all_wrt_def)
lemma Uniq_reachable_by_all_wrt:
  "asymp_on X R ⟹ ∃⇩≤⇩1x. reachable_by_all_wrt R X x"
  by (rule Uniq_I)
    (metis antisymp_onD antisymp_on_if_asymp_on insertE insert_Diff reachable_by_all_wrt_def)
section ‹Existence of unique element›
lemma ex1_reaching_all_wrt:
  "transp_on X R ⟹ asymp_on X R ⟹ totalp_on X R ⟹ finite X ⟹ X ≠ {} ⟹
    ∃!x. reaching_all_wrt R X x"
  using ex1_iff_ex_Uniq ex_reaching_all_wrt Uniq_reaching_all_wrt by metis
lemma ex1_reachable_by_all_wrt:
  "transp_on X R ⟹ asymp_on X R ⟹ totalp_on X R ⟹ finite X ⟹ X ≠ {} ⟹
    ∃!x. reachable_by_all_wrt R X x"
  using ex1_iff_ex_Uniq ex_reachable_by_all_wrt Uniq_reachable_by_all_wrt by metis
section ‹Transformations›
lemma non_reachable_wrt_insert_wrtI:
  assumes
    trans: "transp_on (insert y X) R" and
    asym: "asymp_on (insert y X) R" and
    "R y x" and
    x_non_reachable: "non_reachable_wrt R X x"
  shows "non_reachable_wrt R (insert y X) y"
proof -
  from x_non_reachable have x_in: "x ∈ X" and x_min': "∀y∈X - {x}. ¬ R y x"
    by (simp_all add: non_reachable_wrt_iff)
  have "¬ R z y" if "z ∈ insert y X - {y}" for z
  proof -
    from that have "z ∈ X" and "z ≠ y"
      by simp_all
    show "¬ R z y"
    proof (cases "z = x")
      case True
      thus ?thesis
        using ‹R y x› asym x_in
        by (metis asymp_onD insertI1 insertI2)
    next
      case False
      hence "¬ R z x"
        using x_min'[rule_format, of z, simplified] ‹z ∈ X› by metis
      then show ?thesis
        using ‹R y x› trans ‹z ∈ X› x_in
        by (meson insertCI transp_onD)
    qed
  qed
  thus ?thesis
    by (simp add: non_reachable_wrt_def)
qed
end