Theory Common
section ‹Commonly used Lemmas›
theory Common
imports 
  Main
  "HOL-Library.Extended_Nat" 
  "HOL-Eisbach.Eisbach"
begin
declare [[coercion_enabled = false]]
subsection ‹Miscellaneous›
lemma split_sym_rel: 
  fixes G :: "'a rel"
  assumes "sym G" "irrefl G"
  obtains E where "E∩E¯ = {}" "G = E ∪ E¯"  
proof -
  obtain R :: "'a rel" 
  where WO: "well_order_on UNIV R" using Zorn.well_order_on ..
  let ?E = "G ∩ R"
  
  from ‹irrefl G› have [simp, intro!]: "(x,x)∉G" for x 
    by (auto simp: irrefl_def)
  
  have "?E ∩ ?E¯ = {}"
    using WO 
    unfolding well_order_on_def linear_order_on_def 
      partial_order_on_def antisym_def
    by fastforce 
  moreover  
  have "G = ?E ∪ ?E¯" 
    apply safe
    apply (simp_all add: symD[OF ‹sym G›])
    using WO unfolding well_order_on_def linear_order_on_def total_on_def
    by force
  ultimately show ?thesis by (rule that)  
qed
lemma least_antimono: "X≠{} ⟹ X⊆Y ⟹ (LEAST y::_::wellorder. y∈Y) ≤ (LEAST x. x∈X)"
  by (metis LeastI_ex Least_le equals0I rev_subsetD)
  
lemma distinct_map_snd_inj: "distinct (map snd l) ⟹ (a,b)∈set l ⟹ (a',b)∈set l ⟹ a=a'"
  by (metis distinct_map inj_onD prod.sel(2) prod.simps(1))
  
lemma map_add_apply: "(m⇩1 ++ m⇩2) k = (case m⇩2 k of None ⇒ m⇩1 k | Some x ⇒ Some x)"
  by (auto simp: map_add_def)
lemma map_eq_append_conv: "map f xs = ys⇩1@ys⇩2 
  ⟷ (∃xs⇩1 xs⇩2. xs = xs⇩1@xs⇩2 ∧ map f xs⇩1 = ys⇩1 ∧ map f xs⇩2 = ys⇩2)"
  apply rule
  subgoal
    apply (rule exI[where x="take (length ys⇩1) xs"])
    apply (rule exI[where x="drop (length ys⇩1) xs"])
    apply (drule sym)
    by (auto simp: append_eq_conv_conj take_map drop_map)
  subgoal by auto
  done
  
  
lemma prod_case_const[simp]: "case_prod (λ_ _. c) = (λ_. c)" by auto
lemma card2_eq: "card e = 2 ⟷ (∃u v. u≠v ∧ e={u,v})"
  by (auto simp: eval_nat_numeral card_Suc_eq)
lemma in_ranE:
  assumes "v ∈ ran m"  
  obtains k where "m k = Some v"
  using assms unfolding ran_def by auto
  
  
lemma Inf_in:
  fixes A :: "'a::{linorder,complete_lattice} set"
  assumes "finite A" "A≠{}" 
  shows "Inf A ∈ A" 
  using assms 
  proof (induction A rule: finite_induct)
    case empty
    then show ?case by simp
  next
    have [simp]: "inf a b = (if a≤b then a else b)" for a b :: 'a
      by (meson inf_absorb2 le_iff_inf linear)
  
    case (insert x F)
    show ?case proof cases
      assume "F={}" thus ?thesis by auto
    next
      assume "F≠{}"
      with insert.IH have "Inf F ∈ F" .
      then show ?thesis
        using le_less_linear[of x "Inf F"]
        by auto 
    
  qed
qed  
lemma INF_of_enat_infty_iff1: "(INF x ∈ A. enat (f x)) = ∞ ⟷ A={}"
  apply (cases "A={}")
  subgoal by (simp add: top_enat_def)
  subgoal by safe (metis INF_top_conv(2) enat.distinct(1) top_enat_def)+
  done
lemma INF_of_enat_infty_iff2: 
  "∞ = (INF x ∈ A. enat (f x)) ⟷ A={}"  
  by (metis INF_of_enat_infty_iff1)
lemmas INF_of_enat_infty_iff[simp] = INF_of_enat_infty_iff1 INF_of_enat_infty_iff2
    
lemma INF_of_enat_nat_conv1: 
  assumes "finite A"  
  shows "(INF x ∈ A. enat (f x)) = enat d ⟷ (∃x∈A. d = f x ∧ (∀y∈A. f x ≤ f y))"  
proof -
  from assms have F: "finite (enat`f`A)" by auto
  show ?thesis proof (cases "A={}")
    case True thus ?thesis by (auto simp: top_enat_def)
  next
    case [simp]: False  
    note * = Inf_in[OF F, simplified]
    show ?thesis
      apply (rule iffI)
      subgoal by (smt False Inf_in assms enat.inject enat_ord_simps(1) finite_imageI imageE image_is_empty le_INF_iff order_refl)
      subgoal by clarsimp (meson INF_greatest INF_lower antisym enat_ord_simps(1))
      done
  qed
qed      
      
lemma INF_of_enat_nat_conv2: 
  assumes "finite A"  
  shows "enat d = (INF x ∈ A. enat (f x)) ⟷ (∃x∈A. d = f x ∧ (∀y∈A. f x ≤ f y))"  
  using INF_of_enat_nat_conv1[OF assms] by metis
lemmas INF_of_enat_nat_conv = INF_of_enat_nat_conv1 INF_of_enat_nat_conv2
  
lemma finite_inf_linorder_ne_ex:
  fixes f :: "_ ⇒ _::{complete_lattice,linorder}"
  assumes "finite S"
  assumes "S≠{}"
  shows "∃x∈S. (INF x ∈ S. f x) = f x"
  using assms
  by (meson Inf_in finite_imageI imageE image_is_empty)
  
  
lemma finite_linorder_eq_INF_conv: "finite S 
  ⟹ a = (INF x ∈ S. f x) ⟷ (if S={} then a=top else ∃x∈S. a=f x ∧ (∀y∈S. a ≤ f y))"
  for a :: "_::{complete_lattice,linorder}"
  by (auto 
    simp: INF_greatest INF_lower  
    intro: finite_inf_linorder_ne_ex antisym)
  
lemma sym_inv_eq[simp]: "sym E ⟹ E¯ = E" unfolding sym_def by auto 
lemma insert_inv[simp]: "(insert e E)¯ = insert (prod.swap e) (E¯)"
  by (cases e) auto
  
lemma inter_compl_eq_diff[simp]: "x ∩ - s = x - s"  
  by auto
lemma inter_same_diff[simp]: "A∩(A-S) = A-S" by blast  
  
lemma minus_inv_sym_aux[simp]: "(- {(a, b), (b, a)})¯ = -{(a,b),(b,a)}" 
  by auto
    
subsection ‹The-Default›
fun the_default :: "'a ⇒ 'a option ⇒ 'a" where
  "the_default d None = d"
| "the_default _ (Some x) = x"
lemma the_default_alt: "the_default d x = (case x of None ⇒ d | Some v ⇒ v)" by (auto split: option.split)
subsection ‹Implementing ‹enat› by Option›
text ‹Our maps are functions to ‹nat option›,which are interpreted as ‹enat›,
  ‹None› being ‹∞››
fun enat_of_option :: "nat option ⇒ enat" where
  "enat_of_option None = ∞" 
| "enat_of_option (Some n) = enat n"  
  
lemma enat_of_option_inj[simp]: "enat_of_option x = enat_of_option y ⟷ x=y"
  by (cases x; cases y; simp)
lemma enat_of_option_simps[simp]:
  "enat_of_option x = enat n ⟷ x = Some n"
  "enat_of_option x = ∞ ⟷ x = None"
  "enat n = enat_of_option x ⟷ x = Some n"
  "∞ = enat_of_option x ⟷ x = None"
  by (cases x; auto; fail)+
  
lemma enat_of_option_le_conv: "enat_of_option m ≤ enat_of_option n ⟷ (case (m,n) of 
    (_,None) ⇒ True
  | (Some a, Some b) ⇒ a≤b
  | (_, _) ⇒ False
)"
  by (auto split: option.split)
  
subsection ‹Foldr-Refine›
lemma foldr_refine:
  assumes "I s"
  assumes "⋀s x. I s ⟹ x∈set l ⟹ I (f x s) ∧ α (f x s) = f' x (α s)"
  shows "I (foldr f l s) ∧ α (foldr f l s) = foldr f' l (α s)"
  using assms
  by (induction l arbitrary: s) auto
  
end