Theory SepAlgebra

section ‹Separation Algebra›

text ‹In this section, we formalize the concept of a separation algebra~cite"Calcagno2007" and "Dockins2009", on which our package logic is based.›

theory SepAlgebra
  imports Main
begin

type_synonym 'a property = "'a  bool"

locale sep_algebra =

  fixes plus :: "'a  'a  'a option" (infixl "" 63)

  fixes core :: "'a  'a" (" |_| ")
  (* Largest duplicable part of a state *)

  assumes commutative: "a  b = b  a"
      and asso1: "a  b = Some ab  b  c = Some bc  ab  c = a  bc"
      and asso2: "a  b = Some ab  b  c = None  ab  c = None"

(* The core of x is the max of { p | pure p ∧ x ≥ p} *)
      and core_is_smaller: "Some x = x  |x|"
      and core_is_pure: "Some |x| = |x|  |x|"
      and core_max: "Some x = x  c  (r. Some |x| = c  r)"
      and core_sum: "Some c = a  b  Some |c| = |a|  |b|"

      and positivity: "a  b = Some c  Some c = c  c  Some a = a  a"
      and cancellative: "Some a = b  x  Some a = b  y  |x| = |y|  x = y"

begin

lemma asso3:
  assumes "a  b = None"
      and "b  c = Some bc"
    shows "a  bc = None"
  by (metis assms(1) assms(2) sep_algebra.asso2 sep_algebra.commutative sep_algebra_axioms)

subsection  ‹Definitions›

definition defined :: "'a  'a  bool" (infixl "##" 62) where
  "a ## b  a  b  None"

definition greater :: "'a  'a  bool" (infixl "" 50) where
  "a  b  (c. Some a = b  c)"

definition pure :: "'a  bool" where
  "pure a  Some a = a  a"

definition minus :: "'a  'a  'a" (infixl "" 63)
  where "b  a = (THE_default b (λx. Some b = a  x  x  |b| ))"

definition add_set :: "'a set  'a set  'a set" (infixl "" 60) where
  "A  B = { φ | φ a b. a  A  b  B  Some φ = a  b }"

definition greater_set :: "'a set  'a set  bool" (infixl "" 50) where
  "A  B  (a  A. b  B. a  b)"

definition up_closed :: "'a set  bool" where
  "up_closed A  (φ'. (φ  A. φ'  φ)  φ'  A)"

definition equiv :: "'a set  'a set  bool" (infixl "" 40) where
  "A  B  A  B  B  A"

definition setify :: "'a property  ('a set  bool)" where
  "setify P A  (x  A. P x)"

definition mono_prop :: "'a property  bool" where
  "mono_prop P  (x y. y  x  P x  P y)"

definition under :: "'a set  'a  'a set" where
  "under A ω = { ω' | ω'. ω'  A  ω  ω'}"

definition max_projection_prop :: "('a  bool)  ('a  'a)  bool" where
  "max_projection_prop P f  (x. x  f x  P (f x) 
  (p. P p  x  p  f x  p))"

inductive multi_plus :: "'a list  'a  bool" where
  MPSingle: "multi_plus [a] a"
| MPConcat: " length la > 0 ; length lb > 0 ; multi_plus la a ; multi_plus lb b ; Some ω = a  b   multi_plus (la @ lb)  ω"

fun splus :: "'a option  'a option  'a option" where
  "splus None _ = None"
| "splus _ None = None"
| "splus (Some a) (Some b) = a  b"



subsection ‹First lemmata›

lemma greater_equiv:
  "a  b  (c. Some a = c  b)"
  using commutative greater_def by auto

lemma smaller_compatible:
  assumes "a' ## b"
      and "a'  a"
    shows "a ## b"
  by (metis (full_types) assms(1) assms(2) asso3 commutative defined_def greater_def)

lemma bigger_sum_smaller:
  assumes "Some c = a  b"
      and "a  a'"
    shows "b'. b'  b  Some c = a'  b'"
proof -
  obtain r where "Some a = a'  r" 
    using assms(2) greater_def by auto
  then obtain br where "Some br = r  b"
    by (metis assms(1) asso2 domD domIff option.discI)
  then have "Some c = a'  br" 
    by (metis Some a = a'  r assms(1) asso1)
  then show ?thesis 
    using Some br = r  b commutative greater_def by force
qed

subsubsection ‹splus›

lemma splus_develop:
  assumes "Some a = b  c"
  shows "a  d = splus (splus (Some b) (Some c)) (Some d)"
  by (metis assms splus.simps(3))

lemma splus_comm:
  "splus a b = splus b a"
  apply (cases a)
   apply (cases b)
    apply simp_all
  apply (cases b)
  by (simp_all add: commutative)

lemma splus_asso:
  "splus (splus a b) c = splus a (splus b c)"
proof (cases a)
  case None
  then show ?thesis 
    by simp
next
  case (Some a')
  then have "a = Some a'" by simp
  then show ?thesis
  proof (cases b)
    case None
    then show ?thesis by (simp add: Some)
  next
    case (Some b')
    then have "b = Some b'" by simp
    then show ?thesis
    proof (cases c)
      case None
      then show ?thesis by (simp add: splus_comm)
    next
      case (Some c')
      then have "c = Some c'" by simp
      then show ?thesis
      proof (cases "a'  b'")
        case None
        then have "a'  b' = None" by simp
        then show ?thesis
        proof (cases "b'  c'")
          case None
          then show ?thesis 
            by (simp add: Some a = Some a' a'  b' = None b = Some b')
        next
          case (Some bc)
          then show ?thesis
            by (metis (full_types) None a = Some a' b = Some b' c = Some c' sep_algebra.asso2 sep_algebra_axioms splus.simps(2) splus.simps(3) splus_comm)
        qed
      next
        case (Some ab)
        then have "Some ab = a'  b'" by simp
        then show ?thesis
        proof (cases "b'  c'")
          case None
          then show ?thesis 
            by (metis Some a = Some a' b = Some b' c = Some c' asso2 splus.simps(2) splus.simps(3))
        next
          case (Some bc)
          then show ?thesis
            by (metis Some ab = a'  b' a = Some a' b = Some b' c = Some c' sep_algebra.asso1 sep_algebra_axioms splus.simps(3))
        qed
      qed
    qed
  qed
qed







subsubsection ‹Pure›

(* Maybe need more *)
lemma pure_stable:
  assumes "pure a"
      and "pure b"
      and "Some c = a  b"
    shows "pure c"
  by (metis assms asso1 commutative pure_def)

(* Specific to pure *)
lemma pure_smaller:
  assumes "pure a"
      and "a  b"
    shows "pure b"
  by (metis assms greater_def positivity pure_def)


subsection ‹Succ is an order›

lemma succ_antisym:
  assumes "a  b"
      and "b  a"
    shows "a = b"
proof -
  obtain ra where "Some a = b  ra" 
    using assms(1) greater_def by auto
  obtain rb where "Some b = a  rb" 
    using assms(2) greater_def by auto
  then have "Some a = splus (Some a) (splus (Some ra) (Some rb))"
  proof -
    have "Some b = splus (Some a) (Some rb)"
      by (simp add: Some b = a  rb)
    then show ?thesis
      by (metis (full_types) Some a = b  ra sep_algebra.splus.simps(3) sep_algebra_axioms splus_asso splus_comm)
  qed
  moreover have "Some b = splus (Some b) (splus (Some ra) (Some rb))"
    by (metis Some a = b  ra Some b = a  rb sep_algebra.splus.simps(3) sep_algebra_axioms splus_asso)
  moreover have "pure ra  pure rb"
  proof -
    obtain rab where "Some rab = ra  rb" 
      by (metis calculation(2) splus.elims splus.simps(3))
    then have "|a|  rab" 
      by (metis calculation(1) core_max greater_def splus.simps(3))
    then have "pure rab" 
      using core_is_pure pure_def pure_smaller by blast
    moreover have "rab  ra  rab  rb" 
      using Some rab = ra  rb greater_def greater_equiv by blast
    ultimately have "pure ra" using pure_smaller 
      by blast
    moreover have "pure rb" 
      using pure rab rab  ra  rab  rb pure_smaller by blast
    ultimately show ?thesis 
      by blast
  qed
  ultimately show ?thesis 
    by (metis Some b = a  rb option.inject pure_def sep_algebra.splus.simps(3) sep_algebra_axioms splus_asso)
qed

lemma succ_trans:
  assumes "a  b"
      and "b  c"
    shows "a  c"
  using assms(1) assms(2) bigger_sum_smaller greater_def by blast

lemma succ_refl:
  "a  a" 
  using core_is_smaller greater_def by blast








subsection ‹Core (pure) and stabilize (stable)›

lemma max_projection_propI:
  assumes "x. x  f x"
      and "x. P (f x)"
      and "x p. P p  x  p  f x  p"
    shows "max_projection_prop P f"
  by (simp add: assms(1) assms(2) assms(3) max_projection_prop_def)

lemma max_projection_propE:
  assumes "max_projection_prop P f"
    shows "x. x  f x"
      and "x. P (f x)"
      and "x p. P p  x  p  f x  p"
  using assms max_projection_prop_def by auto

lemma max_projection_prop_pure_core:
  "max_projection_prop pure core"
proof (rule max_projection_propI)
  fix x
  show "x  |x|" 
    using core_is_smaller greater_equiv by blast
  show "pure |x|" 
    by (simp add: core_is_pure pure_def)
  show "p. pure p  x  p  |x|  p"
  proof -
    fix p assume "pure p  x  p"
    then obtain r where "Some x = p  r" 
      using greater_def by blast
    then show "|x|  p"
      by (metis pure p  x  p asso1 commutative core_max greater_equiv pure_def)
  qed
qed

lemma mpp_smaller:
  assumes "max_projection_prop P f"
  shows "x  f x"
  using assms max_projection_propE(1) by auto

lemma mpp_compatible:
  assumes "max_projection_prop P f"
      and "a ## b"
    shows "f a ## f b"
  by (metis (mono_tags, opaque_lifting) assms(1) assms(2) commutative defined_def max_projection_prop_def smaller_compatible)



lemma mpp_prop:
  assumes "max_projection_prop P f"
  shows "P (f x)"
  by (simp add: assms max_projection_propE(2))


lemma mppI:
  assumes "max_projection_prop P f"
      and "a  x"
      and "P x"
      and "x  f a"
    shows "x = f a"
proof -
  have "f a  x" 
    using assms max_projection_propE(3) by auto
  then show ?thesis 
    by (simp add: assms(4) succ_antisym)
qed

lemma mpp_invo:
  assumes "max_projection_prop P f"
  shows "f (f x) = f x"
  using assms max_projection_prop_def succ_antisym by auto

lemma mpp_mono:
  assumes "max_projection_prop P f"
      and "a  b"
    shows "f a  f b"
  by (metis assms max_projection_prop_def succ_trans)


subsection ‹Subtraction›

lemma addition_bigger:
  assumes "a'  a"
      and "Some x' = a'  b"
      and "Some x = a  b"
    shows "x'  x"
  by (metis assms asso1 bigger_sum_smaller greater_def)


lemma smaller_than_core:
  assumes "y  x"
      and "Some z = x  |y|"
    shows "|z| = |y|"
proof -
  have "Some |z| = |x|  |y|"
    using assms(2) core_sum max_projection_prop_pure_core mpp_invo by fastforce
  then have "Some |z| = |x|  |y|"
    by simp
  moreover have "|z|  |y|" 
    using calculation greater_equiv by blast
  ultimately show ?thesis 
    by (meson addition_bigger assms(1) assms(2) core_is_smaller core_sum greater_def succ_antisym)
qed

lemma extract_core:
  assumes "Some b = a  x  x  |b|"
  shows "|x| = |b|"
proof -
  obtain r where "Some x = r  |b|"
    using assms greater_equiv by auto
  show ?thesis
  proof (rule smaller_than_core)
    show "Some x = r  |b|"
      using Some x = r  |b| by auto
    show "b  r"
      by (metis Some x = r  |b| assms commutative greater_def succ_trans)
  qed
qed


lemma minus_unique:
  assumes "Some b = a  x  x  |b|"
      and "Some b = a  y  y  |b|"
    shows "x = y"
proof -
  have "|x| = |b|"
    using assms(1) extract_core by blast
  moreover have "|y| = |b|"
    using assms(2) extract_core by blast
  ultimately show ?thesis
    using assms(1) assms(2) cancellative by auto
qed

lemma minus_exists:
  assumes "b  a"
  shows "x. Some b = a  x  x  |b|"
  using assms bigger_sum_smaller core_is_smaller by blast

lemma minus_equiv_def:
  assumes "b  a"
    shows "Some b = a  (b  a)  (b  a)  |b|"
proof -
  let ?x = "THE_default b (λx. Some b = a  x  x  |b| )"
  have "(λx. Some b = a  x  x  |b| ) ?x"
  proof (rule THE_defaultI')
    show "∃!x. Some b = a  x  x  |b|"
      using assms local.minus_unique minus_exists by blast
  qed
  then show ?thesis by (metis minus_def)
qed

lemma minus_default:
  assumes "¬ b  a"
  shows "b  a = b"
  using THE_default_none assms greater_def minus_def by fastforce

lemma minusI:
  assumes "Some b = a  x"
      and "x  |b|"
    shows "x = b  a"  
  using assms(1) assms(2) greater_def local.minus_unique minus_equiv_def by blast

lemma minus_core:
  "|a  b| = |a|"
proof (cases "a  b")
  case True
  then have "Some a = b  (a  b)  a  b  |a|"
    using minus_equiv_def by auto
  then show ?thesis
    using extract_core by blast
next
  case False
  then show ?thesis by (simp add: minus_default)
qed


lemma minus_core_weaker:
  "|a  b| = |a|  |b|"
proof (cases "a  b")
  case True
  then show ?thesis 
    by (metis greater_equiv max_projection_prop_pure_core minus_core minus_default minus_equiv_def mpp_invo succ_antisym)
next
  case False
  then show ?thesis
    by (metis greater_equiv max_projection_prop_pure_core minus_default minus_equiv_def mpp_invo succ_antisym)
qed

lemma minus_equiv_def_any_elem:
  assumes "Some x = a  b"
  shows "Some (x  a) = b  |x|"
proof -
  obtain r where "Some r = b  |x|" 
    by (metis assms core_is_smaller domD domIff option.simps(3) sep_algebra.asso2 sep_algebra_axioms)
  have "r = x  a"
  proof (rule minusI)
    show "Some x = a  r" 
      by (metis Some r = b  |x| assms asso1 core_is_smaller)
    moreover show "r  |x|"
      using Some r = b  |x| greater_equiv by blast
  qed
  then show ?thesis 
    using Some r = b  |x| by blast
qed

lemma minus_bigger:
  assumes "Some x = a  b"
  shows "x  a  b"
  using assms greater_def minus_equiv_def_any_elem by blast

lemma minus_smaller:
  assumes "x  a"
  shows "x  x  a"
  using assms greater_equiv minus_equiv_def by blast

lemma minus_sum:
  assumes "Some a = b  c"
      and "x  a"
    shows "x  a = (x  b)  c"
proof (rule minusI)
  obtain r where "Some r = c  (x  a)"
    by (metis assms(1) assms(2) asso2 minus_equiv_def option.exhaust_sel)
  have "r = (x  b)"
  proof (rule minusI)
    show "Some x = b  r" 
      by (metis Some r = c  (x  a) assms(1) assms(2) asso1 minus_equiv_def)
    moreover show "r  |x|" 
      by (meson Some r = c  (x  a) assms(2) greater_equiv sep_algebra.minus_equiv_def sep_algebra_axioms succ_trans)
  qed
  then show "Some (x  b) = c  (x  a)" 
    using Some r = c  (x  a) by blast
  moreover show "x  a  |x  b|"
    by (simp add: assms(2) minus_core minus_equiv_def)
qed

lemma smaller_compatible_core:
  assumes "y  x"
  shows "x ## |y|"
  by (metis assms asso2 core_is_smaller defined_def greater_equiv option.discI)

lemma smaller_pure_sum_smaller:
  assumes "y  a"
      and "y  b"
      and "Some x = a  b"
      and "pure b"
    shows "y  x"
proof -
  obtain r where "Some y = r  b" "r  a"
    by (metis assms(1) assms(2) assms(4) asso1 greater_equiv pure_def)
  then show ?thesis
    using addition_bigger assms(3) by blast
qed

lemma greater_minus_trans:
  assumes "y  x"
      and "x  a"
    shows "y  a  x  a"
proof -
  obtain r where "Some y = x  r" 
    using assms(1) greater_def by blast
  then obtain ra where "Some x = a  ra" 
    using assms(2) greater_def by blast
  then have "Some (x  a) = ra  |x|"
    by (simp add: minus_equiv_def_any_elem)
  then obtain yy where "Some yy = (x  a)  r" 
    by (metis (full_types) Some y = x  r assms(2) asso3 commutative minus_equiv_def not_Some_eq)
  then obtain "Some x = a  (x  a)" "x  a   |x|"
    by (simp_all add: assms(2) sep_algebra.minus_equiv_def sep_algebra_axioms)
  then obtain y' where "Some y' = a  yy"
    using Some y = x  r Some yy = x  a  r asso1
    by metis
  moreover have "y  y'"
    by (metis Some x = a  (x  a) Some y = x  r Some yy = x  a  r asso1 calculation option.inject succ_refl)
  moreover obtain x' where "Some x' = (x  a)  a" 
    using assms(2) commutative minus_equiv_def by fastforce
  then have "y  x'" 
    by (metis assms(1) assms(2) commutative minus_equiv_def option.sel)
  moreover have "x'  x  a" 
    using Some x' = x  a  a greater_def by auto
  ultimately show ?thesis 
    using Some x' = x  a  a Some y = x  r assms(2) asso1 commutative greater_equiv minus_bigger minus_equiv_def option.sel sep_algebra.succ_trans sep_algebra_axioms
  proof -
    have f1: "Some y' = a  yy"
      by (simp add: Some y' = a  yy commutative)
    then have "y = y'"
      by (metis Some y = x  r Some yy = x  a  r x  a asso1 minus_equiv_def option.sel)
    then show ?thesis
      using f1 by (metis (no_types) Some yy = x  a  r commutative greater_equiv minus_bigger sep_algebra.succ_trans sep_algebra_axioms)
  qed
qed




lemma minus_and_plus:
  assumes "Some ω' = ω  r"
      and "ω  a"
    shows "Some (ω'  a) = (ω  a)  r"
proof -
  have "ω  ω  a" 
    by (simp add: assms(2) minus_smaller)
  then have "(ω  a) ## r" 
    by (metis (full_types) assms(1) defined_def option.discI sep_algebra.smaller_compatible sep_algebra_axioms)
  then obtain x where "Some x = (ω  a)  r"
    using defined_def by auto
  then have "Some ω' = a  x  x  |ω'|"
    by (metis (no_types, lifting) assms asso1 core_sum max_projection_prop_pure_core minus_core minus_equiv_def mpp_smaller option.inject)
  then have "x = ω'  a" 
    by (simp add: minusI)
  then show ?thesis 
    using Some x = ω  a  r by blast
qed









subsection ‹Lifting the algebra to sets of states›

lemma add_set_commm:
  "A  B = B  A"
proof
  show "A  B  B  A"
    using add_set_def sep_algebra.commutative sep_algebra_axioms by fastforce
  show "B  A  A  B"
    using add_set_def commutative by fastforce
qed

lemma x_elem_set_product:
  "x  A  B  (a b. a  A  b  B  Some x = a  b)"
  using sep_algebra.add_set_def sep_algebra_axioms by fastforce

lemma x_elem_set_product_splus:
  "x  A  B  (a b. a  A  b  B  Some x = splus (Some a) (Some b))"
  using sep_algebra.add_set_def sep_algebra_axioms by fastforce

lemma add_set_asso:
  "(A  B)  C = A  (B  C)" (is "?A = ?B")
proof -
  have "?A  ?B"
  proof (rule subsetI)
    fix x assume "x  ?A"
    then obtain ab c where "Some x = ab  c" "ab  A  B" "c  C"
      using x_elem_set_product by auto
    then obtain a b where "Some ab = a  b" "a  A" "b  B"
      using x_elem_set_product by auto
    then obtain bc where "Some bc = b  c" 
      by (metis Some x = ab  c asso2 option.exhaust)
    then show "x  ?B" 
      by (metis Some ab = a  b Some x = ab  c a  A b  B c  C asso1 x_elem_set_product)
  qed
  moreover have "?B  ?A"
  proof (rule subsetI)
    fix x assume "x  ?B"
    then obtain a bc where "Some x = a  bc" "a  A" "bc  B  C"
      using x_elem_set_product by auto
    then obtain b c where "Some bc = b  c" "c  C" "b  B"
      using x_elem_set_product by auto
    then obtain ab where "Some ab = a  b"
      by (metis Some x = a  bc asso3 option.collapse)
    then show "x  ?A"
      by (metis Some bc = b  c Some x = a  bc a  A b  B c  C asso1 x_elem_set_product)
  qed
  ultimately show ?thesis by blast
qed

lemma up_closedI:
  assumes "φ' φ. (φ' :: 'a)  φ  φ  A  φ'  A"
  shows "up_closed A"
  using assms up_closed_def by blast

lemma up_closed_plus_UNIV:
  "up_closed (A  UNIV)"
proof (rule up_closedI)
  fix φ φ'
  assume asm: "φ'  φ  φ  A  UNIV"
  then obtain r a b where "Some φ' = φ  r" "Some φ = a  b" "a  A"
    using greater_def x_elem_set_product by auto
  then obtain br where "Some br = b  r" 
    by (metis asso2 option.exhaust_sel)
  then have "Some φ' = a  br" 
    by (metis Some φ = a  b Some φ' = φ  r splus.simps(3) splus_asso)
  then show "φ'  A  UNIV" 
    using a  A x_elem_set_product by auto
qed


lemma succ_set_trans:
  assumes "A  B"
      and "B  C"
    shows "A  C"
  by (meson assms(1) assms(2) greater_set_def succ_trans)

lemma greater_setI:
  assumes "a. a  A  (b  B. a  b)"
    shows "A  B"
  by (simp add: assms greater_set_def)  

lemma bigger_set:
  assumes "A'  A"
  shows "A'  B  A  B"
proof (rule greater_setI)
  fix x assume "x  A'  B"
  then obtain a' b where "Some x = a'  b" "a'  A'" "b  B"
    using x_elem_set_product by auto
  then obtain a where "a'  a" "a  A"
    using assms greater_set_def by blast
  then obtain ab where "Some ab = a  b"
    by (metis Some x = a'  b asso2 domD domIff greater_equiv)
  then show "abA  B. x  ab"
    using Some x = a'  b a  A a'  a b  B addition_bigger x_elem_set_product by blast
qed

lemma bigger_singleton:
  assumes "φ'  φ"
  shows "{φ'}  {φ}"
  by (simp add: assms greater_set_def)

lemma add_set_elem:
  "φ  A  B  (a b. Some φ = a  b  a  A  b  B)"
  using add_set_def by auto

lemma up_closed_sum:
  assumes "up_closed A"
    shows "up_closed (A  B)"
proof (rule up_closedI)
  fix φ' φ assume asm: "φ'  φ  φ  A  B"
  then obtain a b where "a  A" "b  B" "Some φ = a  b" 
    using add_set_elem by auto
  moreover obtain r where "Some φ' = φ  r" 
    using asm greater_def by blast
  then obtain ar where "Some ar = a  r" 
    by (metis asso2 calculation(3) commutative option.exhaust_sel option.simps(3))
  then have "ar  A" 
    by (meson assms calculation(1) greater_def sep_algebra.up_closed_def sep_algebra_axioms)
  then show "φ'  A  B" 
    by (metis Some φ' = φ  r Some ar = a  r add_set_elem asso1 calculation(2) calculation(3) commutative)
qed

lemma up_closed_bigger_subset:
  assumes "up_closed B"
      and "A  B"
    shows "A  B"
  by (meson assms(1) assms(2) greater_set_def sep_algebra.up_closed_def sep_algebra_axioms subsetI)

lemma up_close_equiv:
  assumes "up_closed A"
      and "up_closed B"
    shows "A  B  A = B"
proof -
  have "A  B  A  B  B  A" 
    using local.equiv_def by auto
  also have "...  A  B  B  A" 
    by (metis assms(1) assms(2) greater_set_def set_eq_subset succ_refl up_closed_bigger_subset)
  ultimately show ?thesis 
    by blast
qed

lemma equiv_stable_sum:
  assumes "A  B"
  shows "A  C  B  C"
  using assms bigger_set local.equiv_def by auto

lemma equiv_up_closed_subset:
  assumes "up_closed A"
      and "equiv B C"
    shows "B  A  C  A" (is "?B  ?C")
proof -
  have "?B  ?C"
    by (meson greater_set_def up_closed_def equiv_def assms(1) assms(2) subsetD subsetI)
  moreover have "?C  ?B"
    by (meson greater_set_def up_closed_def equiv_def assms(1) assms(2) subsetD subsetI)
  ultimately show ?thesis by blast
qed

lemma mono_propI:
  assumes "x y. y  x  P x  P y"
  shows "mono_prop P"
  using assms mono_prop_def by blast

lemma mono_prop_set:
  assumes "A  B"
      and "setify P B"
      and "mono_prop P"
    shows "setify P A"
  using assms(1) assms(2) assms(3) greater_set_def local.setify_def mono_prop_def by auto

lemma mono_prop_set_equiv:
  assumes "mono_prop P"
      and "equiv A B"
    shows "setify P A  setify P B"
  by (meson assms(1) assms(2) local.equiv_def sep_algebra.mono_prop_set sep_algebra_axioms)

lemma setify_sum:
  "setify P (A  B)  (x  A. setify P ({x}  B))" (is "?A  ?B")
proof -
  have "?A  ?B" 
    using local.setify_def sep_algebra.add_set_elem sep_algebra_axioms singletonD by fastforce
  moreover have "?B  ?A" 
    using add_set_elem local.setify_def by fastforce
  ultimately show ?thesis by blast
qed

lemma setify_sum_image:
  "setify P ((Set.image f A)  B)  (x  A. setify P ({f x}  B))"
proof
  show "setify P (f ` A  B)  xA. setify P ({f x}  B)"
    by (meson rev_image_eqI sep_algebra.setify_sum sep_algebra_axioms)
  show "xA. setify P ({f x}  B)  setify P (f ` A  B)"
    by (metis (mono_tags, lifting) image_iff sep_algebra.setify_sum sep_algebra_axioms)
qed

lemma equivI:
  assumes "A  B"
    and "B  A"
    shows "equiv A B"
  by (simp add: assms(1) assms(2) local.equiv_def)

lemma sub_bigger:
  assumes "A  B"
  shows "A  B" 
  by (meson assms greater_set_def in_mono succ_refl)

lemma larger_set_refl:
  "A  A"
  by (simp add: sub_bigger)


definition upper_closure where
  "upper_closure A = { φ' |φ' φ. φ'  φ  φ  A }"



lemma upper_closure_up_closed:
  "up_closed (upper_closure A)"
proof (rule up_closedI)
  fix φ' φ
  assume asm0: "φ'  φ  φ  upper_closure A"
  then obtain a where "a  A  φ  a"
    using sep_algebra.upper_closure_def sep_algebra_axioms by fastforce
  then have "φ'  a"
    using asm0 succ_trans by blast
  then show "φ'  upper_closure A"
    using a  A  φ  a upper_closure_def by auto
qed


subsection ‹Addition of more than two states›

lemma multi_decompose:
  assumes "multi_plus l ω"
    shows "length l  2  (a b la lb. l = la @ lb  length la > 0  length lb > 0  multi_plus la a  multi_plus lb b  Some ω = a  b)"
  using assms
  apply (rule multi_plus.cases)
  by auto[2]



lemma multi_take_drop:
  assumes "multi_plus l ω"
      and "length l  2"
    shows "n a b. n > 0  n < length l  multi_plus (take n l) a  multi_plus (drop n l) b  Some ω = a  b"
proof -
  obtain a b la lb where asm0: "l = la @ lb  length la > 0  length lb > 0  multi_plus la a  multi_plus lb b  Some ω = a  b"
    using assms(1) assms(2) multi_decompose by blast
  let ?n = "length la"
  have "la = take ?n l"
    by (simp add: asm0)
  moreover have "lb = drop ?n l" 
    by (simp add: asm0)
  ultimately show ?thesis 
    by (metis asm0 length_drop zero_less_diff)
qed

lemma multi_plus_single:
  assumes "multi_plus [v] a"
  shows "a = v"
  using assms
  apply (cases)
  apply simp
  by (metis (no_types, lifting) Nil_is_append_conv butlast.simps(2) butlast_append length_greater_0_conv)

lemma multi_plus_two:
  assumes "length l  2"
  shows "multi_plus l ω  (a b la lb. l = (la @ lb)  length la > 0  length lb > 0  multi_plus la a  multi_plus lb b  Some ω = a  b)" (is "?A  ?B")
  by (meson MPConcat assms multi_decompose)

lemma multi_plus_head_tail:
  "length l  n  length l  2  (multi_plus l ω  (r. Some ω = (List.hd l)  r  multi_plus (List.tl l) r))"
proof (induction n arbitrary: l ω)
  case 0
  then show ?case by auto
next
  case (Suc n)
  then have IH: "(l :: 'a list) ω. length l  n  length l  2  multi_plus l ω = (r. Some ω = hd l  r  multi_plus (tl l) r)"
    by blast
  then show ?case
  proof (cases "n = 0")
    case True
    then have "n = 0" by simp
    then show ?thesis by linarith
  next
    case False
    then have "length (l :: 'a list)  2  length l  n + 1  multi_plus l ω  (r. Some ω = hd l  r  multi_plus (tl l) r)"
      (is "length l  2   length l  n + 1  ?A  ?B")
    proof -
      assume asm: "length (l :: 'a list)  2  length l  n + 1"
      have "?B  ?A"
      proof -
        assume "?B"
        then obtain r where "Some ω = hd l  r  multi_plus (tl l) r" by blast
        then have "multi_plus [hd l] (hd l)" 
          using MPSingle by blast
        moreover have "[hd l] @ (tl l) = l" 
          by (metis Suc_le_length_iff asm append_Cons list.collapse list.simps(3) numeral_2_eq_2 self_append_conv2)
        ultimately show ?A 
          by (metis (no_types, lifting) MPConcat Suc_1 Suc_le_mono asm Some ω = hd l  r  multi_plus (tl l) r append_Nil2 length_Cons length_greater_0_conv list.size(3) not_one_le_zero zero_less_Suc)
      qed
      moreover have "?A  ?B"
      proof -
        assume ?A
        then obtain la lb a b where "l = la @ lb" "length la > 0" "length lb > 0" "multi_plus la a" "multi_plus lb b" "Some ω = a  b"
          using asm multi_decompose by blast
        then have r0: "length la  n  length la  2  multi_plus la a = (r. Some a = hd la  r  multi_plus (tl la) r)"
          using IH by blast
        then show ?B
        proof (cases "length la  2")
          case True
          then obtain ra where "Some a = (hd la)  ra" "multi_plus (tl la) ra"
            by (metis Suc_eq_plus1 0 < length lb l = la @ lb r0 multi_plus la a append_eq_conv_conj asm drop_eq_Nil le_add1 le_less_trans length_append length_greater_0_conv less_Suc_eq_le order.not_eq_order_implies_strict)
          moreover obtain rab where "Some rab = ra  b"
            by (metis Some ω = a  b calculation(1) asso2 option.exhaust_sel)
          then have "multi_plus ((tl la) @ lb) rab" 
            by (metis (no_types, lifting) Nil_is_append_conv multi_plus lb b calculation(2) length_greater_0_conv list.simps(3) multi_plus.cases sep_algebra.MPConcat sep_algebra_axioms)
          moreover have "Some ω = hd la  rab" 
            by (metis Some ω = a  b Some rab = ra  b asso1 calculation(1))
          ultimately show ?B 
            using 0 < length la l = la @ lb by auto
        next
          case False
          then have "length la = 1" 
            using 0 < length la by linarith
          then have "la = [a]"
            by (metis Nitpick.size_list_simp(2) One_nat_def Suc_le_length_iff multi_plus la a diff_Suc_1 le_numeral_extra(4) length_0_conv list.sel(3) sep_algebra.multi_plus_single sep_algebra_axioms)
          then show ?thesis 
            using Some ω = a  b l = la @ lb multi_plus lb b by auto
        qed
      qed
      then show ?thesis using calculation by blast
    qed
    then show ?thesis by (metis (no_types, lifting) Suc_eq_plus1)
  qed
qed

lemma not_multi_plus_empty:
  "¬ multi_plus [] ω"
  by (metis Nil_is_append_conv length_greater_0_conv list.simps(3) sep_algebra.multi_plus.simps sep_algebra_axioms)

lemma multi_plus_deter:
  "length l  n  multi_plus l ω  multi_plus l ω'  ω = ω'"
proof (induction n arbitrary: l ω ω')
  case 0
  then show ?case 
    using multi_plus.cases by auto
next
  case (Suc n)
  then show ?case
  proof (cases "length l  2")
    case True
    then obtain r where "Some ω = (List.hd l)  r  multi_plus (List.tl l) r"
      using Suc.prems(2) multi_plus_head_tail by blast
    moreover obtain r' where "Some ω' = (List.hd l)  r'  multi_plus (List.tl l) r'"
      using Suc.prems(3) True multi_plus_head_tail by blast
    ultimately have "r = r'" 
      by (metis Suc.IH Suc.prems(1) drop_Suc drop_eq_Nil)
    then show ?thesis 
      by (metis Some ω = hd l  r  multi_plus (tl l) r Some ω' = hd l  r'  multi_plus (tl l) r' option.inject)
  next
    case False
    then have "length l  1" 
      by simp
    then show ?thesis
    proof (cases "length l = 0")
      case True
      then show ?thesis
        using Suc.prems(2) sep_algebra.not_multi_plus_empty sep_algebra_axioms by fastforce
    next
      case False
      then show ?thesis 
        by (metis One_nat_def Suc.prems(2) Suc.prems(3) Suc_length_conv length l  1 le_SucE le_zero_eq length_greater_0_conv less_numeral_extra(3) sep_algebra.multi_plus_single sep_algebra_axioms)
    qed      
  qed
qed

lemma multi_plus_implies_multi_plus_of_drop:
  assumes "multi_plus l ω"
      and "n < length l"
    shows "a. multi_plus (drop n l) a  ω  a"
  using assms
proof (induction n arbitrary: l ω)
  case 0
  then show ?case using succ_refl by fastforce
next
  case (Suc n)
  then have "length l  2" 
    by linarith
  then obtain r where "Some ω = (List.hd l)  r  multi_plus (List.tl l) r" 
    using Suc.prems(1) multi_plus_head_tail by blast
  then obtain a where "multi_plus (drop n (List.tl l)) a  r  a" 
    using Suc.IH Suc.prems(2) by fastforce
  then show ?case 
    by (metis Some ω = hd l  r  multi_plus (tl l) r bigger_sum_smaller commutative drop_Suc greater_def)
qed

lemma multi_plus_bigger_than_head:
  assumes "length l > 0"
      and "multi_plus l ω"
    shows "ω  List.hd l"
proof (cases "length l  2")
  case True
  then obtain r where "Some ω = (List.hd l)  r  multi_plus (List.tl l) r" 
    using assms(1) assms(2) multi_plus_head_tail by blast
  then show ?thesis 
    using greater_def by blast
next
  case False
  then show ?thesis
    by (metis Cons_nth_drop_Suc MPSingle assms(1) assms(2) drop_0 drop_eq_Nil hd_conv_nth length_greater_0_conv not_less_eq_eq numeral_2_eq_2 sep_algebra.multi_plus_deter sep_algebra_axioms succ_refl)
qed

lemma multi_plus_bigger:
  assumes "i < length l"
      and "multi_plus l ω"
    shows "ω  (l ! i)"
proof -
  obtain a where "multi_plus (drop i l) a  ω  a"
    using assms(1) assms(2) multi_plus_implies_multi_plus_of_drop order.strict_trans by blast
  moreover have "List.hd (drop i l) = l ! i" 
    by (simp add: assms(1) hd_drop_conv_nth)
  then show ?thesis
    by (metis (no_types, lifting) succ_trans assms(1) assms(2) drop_eq_Nil leD length_greater_0_conv multi_plus_bigger_than_head multi_plus_implies_multi_plus_of_drop)
qed


lemma sum_then_singleton:
  "Some a = b  c  {a} = {b}  {c}" (is "?A  ?B")
proof -
  have "?A  ?B"
  proof -
    assume ?A
    then have "{a}  {b}  {c}"
      using add_set_elem by auto
    moreover have "{b}  {c}  {a}"
    proof (rule subsetI)
      fix x assume "x  {b}  {c}"
      then show "x  {a}"
        by (metis Some a = b  c option.sel sep_algebra.add_set_elem sep_algebra_axioms singleton_iff)
    qed
    ultimately show ?thesis by blast
  qed
  moreover have "?B  ?A" 
    using add_set_elem by auto
  ultimately show ?thesis by blast
qed

lemma empty_set_sum:
  "{}  A = {}" 
  by (simp add: add_set_def)


end

end