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 "EE¯ = {}" "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{}  XY  (LEAST y::_::wellorder. yY)  (LEAST x. xX)"
  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: "(m1 ++ m2) k = (case m2 k of None  m1 k | Some x  Some x)"
  by (auto simp: map_add_def)

lemma map_eq_append_conv: "map f xs = ys1@ys2 
   (xs1 xs2. xs = xs1@xs2  map f xs1 = ys1  map f xs2 = ys2)"
  apply rule
  subgoal
    apply (rule exI[where x="take (length ys1) xs"])
    apply (rule exI[where x="drop (length ys1) 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. uv  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 ab 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  (xA. d = f x  (yA. 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))  (xA. d = f x  (yA. 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 "xS. (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 xS. a=f x  (yS. 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)  ab
  | (_, _)  False
)"
  by (auto split: option.split)

  
subsection ‹Foldr-Refine›
lemma foldr_refine:
  assumes "I s"
  assumes "s x. I s  xset 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