Theory AbstractCommutativity

section ‹Soundness of CommCSL›

subsection ‹Abstract Commutativity›

text ‹In this file, we prove lemma 4.2 from the paper: Essentially, conditions (1)-(4) from Section 2
are sufficient to ensure that the abstraction of the final shared value is low. ›

theory AbstractCommutativity
  imports Main CommCSL "HOL-Library.Multiset"
begin

datatype ('i, 'a, 'b) action = Shared (get_s: 'a) | Unique (get_i: 'i) (get_u: 'b)
text ‹We consider a family of unique actions indexed by the type 'i›

lemma sabstract:
  assumes "all_axioms α sact spre uact upre"
  shows "α v = α v'  spre sarg sarg'  α (sact v sarg) = α (sact v' sarg')"
  using all_axioms_def[of α sact spre uact upre] assms by fast

lemma uabstract:
  assumes "all_axioms α sact spre uact upre"
  shows "α v = α v'  upre i uarg uarg'  α (uact i v uarg) = α (uact i v' uarg')"
  using all_axioms_def[of α sact spre uact upre] assms by fast

lemma spre_refl:
  assumes "all_axioms α sact spre uact upre"
  shows "spre sarg sarg'  spre sarg' sarg'"
  using all_axioms_def[of α sact spre uact upre] assms by fast

lemma upre_refl:
  assumes "all_axioms α sact spre uact upre"
  shows "upre i uarg uarg'  upre i uarg' uarg'"
  using all_axioms_def[of α sact spre uact upre] assms by fast

lemma ss_com:
  assumes "all_axioms α sact spre uact upre"
  shows "α v = α v'  spre sarg sarg  spre sarg' sarg'  α (sact (sact v sarg) sarg') = α (sact (sact v' sarg') sarg)"
  using all_axioms_def[of α sact spre uact upre] assms by blast

lemma su_com:
  assumes "all_axioms α sact spre uact upre"
  shows "α v = α v'  spre sarg sarg  upre i uarg uarg  α (sact (uact i v uarg) sarg) = α (uact i (sact v' sarg) uarg)"
  using all_axioms_def[of α sact spre uact upre] assms by blast

lemma uu_com:
  assumes "all_axioms α sact spre uact upre"
      and "i  i'"
      and "α v = α v'"
      and "upre i' uarg' uarg'"
      and "upre i uarg uarg"
    shows "α (uact i' (uact i v uarg) uarg') = α (uact i (uact i' v' uarg') uarg)"
proof -
  have "v v' uarg uarg' i i'.
             i  i'  α v = α v'  upre i uarg uarg  upre i' uarg' uarg'  α (uact i' (uact i v uarg) uarg') = α (uact i (uact i' v' uarg') uarg)"
  using all_axioms_def[of α sact spre uact upre] assms(1)
  by blast
  then show ?thesis
    using assms(2) assms(3) assms(4) assms(5) by blast
qed


definition PRE_shared :: "('a  'a  bool)  'a multiset  'a multiset  bool" where
  "PRE_shared spre sargs sargs'  (ms. image_mset fst ms = sargs  image_mset snd ms = sargs'  (x ∈# ms. spre (fst x) (snd x)))"

lemma PRE_shared_same_size:
  assumes "PRE_shared spre sargs sargs'"
  shows "size sargs = size sargs'"
proof -
  obtain ms where "image_mset fst ms = sargs  image_mset snd ms = sargs'  (x ∈# ms. spre (fst x) (snd x))"
    by (metis PRE_shared_def assms)
  then have "size sargs = size ms  size ms = size sargs'"
    by force
  then show ?thesis
    by simp
qed

definition is_Unique :: "('i, 'a, 'b) action  bool" where
  "is_Unique a  ¬ is_Shared a"

definition is_Unique_i :: "'i  ('i, 'a, 'b) action  bool" where
  "is_Unique_i i a  is_Unique a  get_i a = i"

text ‹The following definition expresses that a sequence of actions corresponds to some interleaving
of a multiset of shared actions and a family of sequences of unique actions, by projecting the sequence
of actions on each type of action.›

definition possible_sequence :: "'a multiset  ('i  'b list)  ('i, 'a, 'b) action list  bool" where
  "possible_sequence sargs uargs s  ((i. uargs i = map get_u (filter (is_Unique_i i) s))
   sargs = image_mset get_s (filter_mset is_Shared (mset s)))"

lemma possible_sequenceI:
  assumes "i. uargs i = map get_u (filter (is_Unique_i i) s)"
      and "sargs = image_mset get_s (filter_mset is_Shared (mset s))"
    shows "possible_sequence sargs uargs s"
  using assms(1) assms(2) possible_sequence_def by blast

fun remove_at_index :: "nat  'd list  'd list" where
  "remove_at_index _ [] = []"
| "remove_at_index 0 (x # xs) = xs"
| "remove_at_index (Suc n) (x # xs) = x # (remove_at_index n xs)"

lemma remove_at_index:
  assumes "n < length l"
  shows "length (remove_at_index n l) = length l - 1"
    and "i  0  i < n  remove_at_index n l ! i = l ! i"
    and "i  n  i < length l - 1  remove_at_index n l ! i = l ! (i + 1)"
  using assms
proof (induct l arbitrary: n i)
  case (Cons a l)
  {
    case 1
    then show ?case
    proof (cases n)
      case (Suc k)
      then show ?thesis
        using "1" Cons.hyps(1) by force
    qed (simp)
  next
    case 2
    then show ?case
    proof (cases n)
      case (Suc k)
      then show ?thesis
        using "2.prems"(1) "2.prems"(2) Cons.hyps(2) Suc_less_eq2 less_Suc_eq_0_disj by auto
    qed (simp)
  next
    case 3
    then show ?case
    proof (cases n)
      case (Suc k)
      then have "remove_at_index (Suc k) (a # l) ! i = (a # l) ! (i + 1)"
        apply (cases i)
        using "3.prems"(1) apply blast
        using "3.prems"(1) Cons.hyps(3) Suc_less_eq2 by auto
      then show "remove_at_index n (a # l) ! i = (a # l) ! (i + 1)"
        using Suc by blast
    qed (simp)
  }
qed (auto)

fun insert_at :: "nat  'd  'd list  'd list" where
  "insert_at 0 x l = x # l"
| "insert_at _ x [] = [x]"
| "insert_at (Suc n) x (h # xs) = h # (insert_at n x xs)"

lemma insert_at_index:
  assumes "n  length l"
  shows "length (insert_at n x l) = length l + 1"
    and "i  0  i < n  insert_at n x l ! i = l ! i"
    and "n  0  insert_at n x l ! n = x"
    and "i > n  i < length l + 1  insert_at n x l ! i = l ! (i - 1)"
  using assms
proof (induct l arbitrary: n i)
  case (Cons a l)
  {
    case 1
    then show ?case by (cases n) (simp_all add: Cons.hyps(1))
  next
    case 2
    then show ?case apply (cases n)
       apply blast
      using Cons.hyps(2) less_Suc_eq_0_disj by force
  next
    case 3
    then show ?case apply (cases n)
       apply simp
      by (simp add: Cons.hyps(3))
  next
    case 4
    then show ?case apply (cases n)
       apply simp
      by (metis (no_types, lifting) "4.prems"(1) "4.prems"(2) Cons.hyps(4) Nat.add_0_right One_nat_def Suc_le_length_iff Suc_less_eq Suc_pred add_Suc_right bot_nat_0.not_eq_extremum insert_at.simps(3) less_zeroE list.inject list.size(4) nat.simps(3) nth_Cons' nth_Cons_Suc)
  }
qed (simp_all)

lemma list_ext:
  assumes "length a = length b"
      and "i. i  0  i < length a  a ! i = b ! i"
    shows "a = b"
  by (meson assms(1) assms(2) bot_nat_0.extremum nth_equalityI)

lemma mset_remove_index:
  assumes "i  0  i < length l"
  shows "mset l = mset (remove_at_index i l) + {# l ! i #}"
  using assms
proof (induct l arbitrary: i)
  case (Cons a l)
  then show ?case
  proof (cases i)
    case (Suc k)
    then show ?thesis
      using Cons.hyps Cons.prems by force
  qed (auto)
qed (simp)

lemma filter_remove:
  assumes "k  0  k < length s"
      and "¬ P (s ! k)"
    shows "filter P (remove_at_index k s) = filter P s"
  using assms
proof (induct k arbitrary: s)
  case 0
  then have "s = hd s # tl s"
    by simp
  then show ?case
    by (metis "0.prems"(2) filter.simps(2) nth_Cons_0 remove_at_index.simps(2))
next
  case (Suc k)
  then show ?case
    by (cases s) simp_all
qed

lemma exists_index_in_sequence_shared:
  assumes "a ∈# sargs"
      and "possible_sequence sargs uargs s"
    shows "i. i  0  i < length s  s ! i = Shared a  possible_sequence (sargs - {# a #}) uargs (remove_at_index i s)"
proof -
  have "a ∈# image_mset get_s (filter_mset is_Shared (mset s))"
    by (metis assms(1) assms(2) possible_sequence_def)
  then have "Shared a  set s"
    by fastforce
  then obtain i where "i  0  i < length s  s ! i = Shared a"
    by (meson bot_nat_0.extremum in_set_conv_nth)
  let ?s = "remove_at_index i s"
  have "sargs - {# a #} = image_mset get_s (filter_mset is_Shared (mset ?s))"
  proof -
    have "sargs = image_mset get_s (filter_mset is_Shared (mset s))"
      using possible_sequence_def assms(2) by blast
    moreover have "mset s = mset ?s + {# Shared a #}"
      by (metis 0  i  i < length s  s ! i = Shared a mset_remove_index)
    ultimately show ?thesis
      by simp
  qed
  moreover have "i. uargs i = map get_u (filter (is_Unique_i i) ?s)"
    by (metis 0  i  i < length s  s ! i = Shared a action.disc(1) assms(2) filter_remove is_Unique_def is_Unique_i_def possible_sequence_def)
  ultimately show ?thesis
    using 0  i  i < length s  s ! i = Shared a possible_sequence_def by blast
qed

lemma head_possible_exists_first_unique:
  assumes "a = hd (uargs j)"
      and "uargs j  []"
      and "possible_sequence sargs uargs s"
    shows "i. i  0  i < length s  s ! i = Unique j a  (k. k  0  k < i  ¬ is_Unique_i j (s ! k))"
  using assms
proof (induct s arbitrary: sargs uargs)
  case Nil
  then show ?case by (simp add: possible_sequence_def)
next
  case (Cons x xs)
  then show "i0. i < length (x # xs)  (x # xs) ! i = Unique j a  (k. 0  k  k < i  ¬ is_Unique_i j ((x # xs) ! k))"
  proof (cases x)
    case (Shared sarg)
    moreover have "possible_sequence (sargs - {# sarg #}) uargs xs"
    proof (rule possible_sequenceI)
      show "sargs - {#sarg#} = image_mset get_s (filter_mset is_Shared (mset xs))"
        using Cons.prems(3) action.disc(1) action.sel(1) add_mset_remove_trivial[of sarg ]
          calculation
          filter_mset_add_mset image_mset_add_mset mset.simps(2) possible_sequence_def[of sargs uargs "x # xs"]
        by auto
      fix i show "uargs i = map get_u (filter (is_Unique_i i) xs)"
        using Cons.prems(3) action.disc(1) calculation filter_remove is_Unique_def is_Unique_i_def
          le_numeral_extra(3) length_greater_0_conv list.discI nth_Cons_0 possible_sequence_def[of sargs uargs "x # xs"]
          remove_at_index.simps(2)
        by metis
    qed
    then obtain i where "i  0  i < length xs  xs ! i = Unique j a  (k. 0  k  k < i  ¬ is_Unique_i j (xs ! k))"
      using Cons.hyps[of uargs] Cons.prems(1) Cons.prems(2) by auto
    moreover have "k. 0  k  k < i + 1  ¬ is_Unique_i j ((x # xs) ! k)"
    proof 
      fix k assume "0  k  k < i + 1"
      then show "¬ is_Unique_i j ((x # xs) ! k)"
        apply (cases k)
         apply (simp add: Shared is_Unique_def is_Unique_i_def)
        by (simp add: calculation(2))
    qed
    ultimately show ?thesis
      by (metis Suc_eq_plus1 Suc_less_eq bot_nat_0.extremum length_Cons nth_Cons_Suc)
  next
    case (Unique k uarg)
    then show ?thesis
    proof (cases "j = k")
      case True
      then have "uargs j = map get_u (filter (is_Unique_i j) (x # xs))"
        by (meson Cons.prems(3) possible_sequence_def)
      then have "uarg = a"
        by (simp add: True Unique Cons.prems(1) is_Unique_def is_Unique_i_def)
      then show ?thesis
        using True Unique by fastforce
    next
      case False
      moreover have "possible_sequence sargs (uargs(k := tl (uargs k))) xs"
      proof (rule possible_sequenceI)
        show "sargs = image_mset get_s (filter_mset is_Shared (mset xs))"
          by (metis (mono_tags, lifting) Cons.prems(3) Unique action.disc(2) filter_mset_add_mset mset.simps(2) possible_sequence_def)
        fix i show "(uargs(k := tl (uargs k))) i = map get_u (filter (is_Unique_i i) xs)"
        proof (cases "i = k")
          case True
          then show ?thesis
            using Cons.prems(3) Unique action.disc(2) action.sel(2) filter.simps(2) fun_upd_same
              is_Unique_def is_Unique_i_def list.sel(3) map_tl possible_sequence_def[of sargs uargs "x # xs"]
            by metis
        next
          case False
          then show ?thesis
            using Cons.prems(3) Unique action.sel(2) filter_remove fun_upd_apply is_Unique_i_def
            le_numeral_extra(3) length_greater_0_conv list.discI nth_Cons_0 possible_sequence_def[of sargs uargs "x # xs"]
            remove_at_index.simps(2) by metis
        qed
      qed
      then obtain i where "i  0  i < length xs  xs ! i = Unique j a  (k. 0  k  k < i  ¬ is_Unique_i j (xs ! k))"
        by (metis Cons.hyps Cons.prems(1) Cons.prems(2) calculation fun_upd_other)
      moreover have "k. 0  k  k < i + 1  ¬ is_Unique_i j ((x # xs) ! k)"
      proof 
        fix k assume "0  k  k < i + 1"
        then show "¬ is_Unique_i j ((x # xs) ! k)"
          apply (cases k)
           apply (metis False Unique action.sel(2) is_Unique_i_def nth_Cons_0)
          by (simp add: calculation(2))
      qed
      ultimately show ?thesis
        by (metis Suc_eq_plus1 Suc_less_eq bot_nat_0.extremum length_Cons nth_Cons_Suc)
    qed
  qed
qed

lemma remove_at_index_filter:
  assumes "i  0  i < length s  P (s ! i)"
      and "j. j  0  j < i  ¬ P (s ! j)"
    shows "tl (map get_u (filter P s)) = map get_u (filter P (remove_at_index i s))"
  using assms
proof (induct s arbitrary: i)
  case (Cons a s)
  then show ?case
  proof (cases i)
    case 0
    then show ?thesis
      using Cons.prems(1) by auto
  next
    case (Suc k)
    then have "tl (map get_u (filter P s)) = map get_u (filter P (remove_at_index k s))"
      apply (cases s)
       apply simp
      by (metis Cons.hyps Cons.prems(1) Cons.prems(2) Suc_less_eq bot_nat_0.extremum length_Cons nth_Cons_Suc)
    then show ?thesis
      by (metis Cons.prems(2) Suc bot_nat_0.extremum filter.simps(2) nth_Cons_0 remove_at_index.simps(3) zero_less_Suc)
  qed
qed (simp)

definition tail_kth where
  "tail_kth uargs k = uargs(k := tl (uargs k))"

lemma exists_index_in_sequence_unique:
  assumes "a = hd (uargs k)"
      and "uargs k  []"
      and "possible_sequence sargs uargs s"
    shows "i. i  0  i < length s  s ! i = Unique k a  possible_sequence sargs (tail_kth uargs k) (remove_at_index i s)
           (j. j  0  j < i  ¬ is_Unique_i k (s ! j))"
proof -
  obtain i where "i  0  i < length s  s ! i = Unique k a  (j. j  0  j < i  ¬ is_Unique_i k (s ! j))"
    by (metis assms(1) assms(2) assms(3) head_possible_exists_first_unique)
  let ?s = "remove_at_index i s"
  have "sargs = image_mset get_s (filter_mset is_Shared (mset ?s))" 
    by (metis 0  i  i < length s  s ! i = Unique k a  (j. 0  j  j < i  ¬ is_Unique_i k (s ! j)) action.disc(2) add.right_neutral assms(3) filter_single_mset filter_union_mset mset_remove_index possible_sequence_def)
  moreover have "tl (uargs k) = map get_u (filter (is_Unique_i k) ?s)"
  proof -
    have "uargs k = map get_u (filter (is_Unique_i k) s)"
      by (meson assms(3) possible_sequence_def)
    then show ?thesis
      by (metis 0  i  i < length s  s ! i = Unique k a  (j. 0  j  j < i  ¬ is_Unique_i k (s ! j)) action.disc(2) action.sel(2) is_Unique_def is_Unique_i_def remove_at_index_filter)
  qed
  moreover have "possible_sequence sargs (tail_kth uargs k) (remove_at_index i s)"
  proof (rule possible_sequenceI)
    show "sargs = image_mset get_s (filter_mset is_Shared (mset (remove_at_index i s)))"
      by (simp add: calculation(1))
    fix ia show "tail_kth uargs k ia = map get_u (filter (is_Unique_i ia) (remove_at_index i s))"
      by (metis (mono_tags, lifting) 0  i  i < length s  s ! i = Unique k a  (j. 0  j  j < i  ¬ is_Unique_i k (s ! j)) action.sel(2) assms(3) calculation(2) filter_remove fun_upd_other fun_upd_same is_Unique_i_def possible_sequence_def tail_kth_def)
  qed
  ultimately show ?thesis
    using 0  i  i < length s  s ! i = Unique k a  (j. 0  j  j < i  ¬ is_Unique_i k (s ! j)) by blast
qed

lemma possible_sequence_where_is_unique:
  assumes "possible_sequence sargs uargs (Unique k a # s)"
  shows "a = hd (uargs k)"
proof -
  let ?s = "Unique k a # s"
  have "Unique k a = hd (filter is_Unique ?s)"
    by (simp add: is_Unique_def)
  then have "a = hd (map get_u (filter is_Unique ?s))"
    by (simp add: is_Unique_def)
  then show ?thesis
    using action.disc(2) action.sel(2) assms filter.simps(2) hd_map is_Unique_def
      is_Unique_i_def list.discI list.sel(1) possible_sequence_def[of sargs uargs "Unique k a # s"]
    by metis
qed

lemma possible_sequence_where_is_shared:
  assumes "possible_sequence sargs uargs (Shared a # s)"
  shows "a ∈# sargs"
proof -
  let ?s = "Shared a # s"
  have "a  set (map get_s (filter is_Shared ?s))"
    by simp
  then show ?thesis
    by (metis (no_types, lifting) assms mset_filter mset_map possible_sequence_def set_mset_mset)
qed


lemma PRE_unique_tlI:
  assumes "PRE_unique upre qa qb"
      and "upre ta tb"
    shows "PRE_unique upre (ta # qa) (tb # qb)"
proof (rule PRE_uniqueI)
  show "length (ta # qa) = length (tb # qb)"
    using PRE_unique_def assms(1) by auto
  fix i
  show "0  i  i < length (tb # qb)  upre ((ta # qa) ! i) ((tb # qb) ! i)"
  proof (cases i)
    case 0
    then show ?thesis
      using assms(2) by auto
  next
    case (Suc k)
    assume "0  i  i < length (tb # qb)"
    then have "(ta # qa) ! i = qa ! k  (tb # qb) ! i = qb ! k"
      by (simp add: Suc)
    then show ?thesis using assms(1) PRE_unique_def
      using Suc 0  i  i < length (tb # qb) by auto
  qed
qed

fun abstract_pre :: "('a  'a  bool)  ('i  'b  'b  bool)  ('i, 'a, 'b) action  ('i, 'a, 'b) action  bool" where
  "abstract_pre spre upre (Shared sarg) (Shared sarg')  spre sarg sarg'"
| "abstract_pre spre upre (Unique k uarg) (Unique k' uarg')  k = k'  upre k uarg uarg'"
| "abstract_pre spre upre _ _  False"

definition PRE_sequence :: "('a  'a  bool)  ('i => 'b  'b  bool)  ('i, 'a, 'b) action list  ('i, 'a, 'b) action list  bool" where
  "PRE_sequence spre upre s s'  length s = length s'  (i. i  0  i < length s  abstract_pre spre upre (s ! i) (s' ! i))"

lemma PRE_sequenceE:
  assumes "PRE_sequence spre upre s s'"
      and "i  0  i < length s"
    shows "abstract_pre spre upre (s ! i) (s' ! i)"
  using PRE_sequence_def assms(1) assms(2) by blast

lemma PRE_sequenceI:
  assumes "length s = length s'"
      and "i. i  0  i < length s  abstract_pre spre upre (s ! i) (s' ! i)"
    shows "PRE_sequence spre upre s s'"
  by (simp add: PRE_sequence_def assms(1) assms(2))

lemma PRE_sequenceI_rec:
  assumes "PRE_sequence spre upre s s'"
      and "abstract_pre spre upre a b"
    shows "PRE_sequence spre upre (a # s) (b # s')"
  using PRE_sequence_def[of spre upre "a # s" "b # s'"] PRE_sequence_def[of spre upre s s']
  assms(1) assms(2) less_Suc_eq_0_disj length_Cons less_Suc_eq_le nth_Cons_0 nth_Cons_Suc
  by force
  
lemma PRE_sequenceE_rec:
  assumes "PRE_sequence spre upre (a # s) (b # s')"
  shows "PRE_sequence spre upre s s'"
      and "abstract_pre spre upre a b"
  using PRE_sequence_def[of spre upre "a # s" "b # s'"] PRE_sequence_def[of spre upre s s']
  apply (metis Suc_less_eq assms bot_nat_0.extremum diff_Suc_1 length_Cons nth_Cons_Suc)
  by (metis PRE_sequenceE assms length_Cons list.size(3) nth_Cons_0 remdups_adj.simps(1) remdups_adj_length zero_less_Suc)

fun compute :: "('v  'a  'v)  ('i  'v  'b  'v)  'v  ('i, 'a, 'b) action list  'v" where
  "compute sact uact v0 [] = v0"
| "compute sact uact v0 (Shared sarg # s) = sact (compute sact uact v0 s) sarg"
| "compute sact uact v0 (Unique k uarg # s) = uact k (compute sact uact v0 s) uarg"


lemma obtain_other_elem_ms:
  assumes "PRE_shared spre sargs sargs'"
      and "sarg ∈# sargs"
    shows "sarg'. sarg' ∈# sargs'  spre sarg sarg'  PRE_shared spre (sargs - {# sarg #}) (sargs' - {# sarg' #})"
proof -
  obtain ms where asm: "image_mset fst ms = sargs  image_mset snd ms = sargs'  (x ∈# ms. spre (fst x) (snd x))"
    using PRE_shared_def assms(1) by blast
  then obtain x where "x ∈# ms" "fst x = sarg"
    using assms(2) by auto
  then have "snd x ∈# sargs'  spre sarg (snd x)"
    using asm by force
  moreover have "PRE_shared spre (sargs - {# sarg #}) (sargs' - {# snd x #})"
  proof -
    let ?ms = "ms - {# x #}"
    have "image_mset fst ?ms = (sargs - {# sarg #})  image_mset snd ?ms = (sargs' - {# snd x #})"
      by (simp add: fst x = sarg x ∈# ms asm image_mset_Diff)
    moreover have "y. y ∈# ?ms  spre (fst y) (snd y)"
      by (meson asm in_diffD)
    ultimately show ?thesis
      using PRE_shared_def by blast
  qed
  ultimately show ?thesis
    by blast
qed

lemma exists_aligned_sequence:
  assumes "possible_sequence sargs uargs s"
      and "possible_sequence sargs' uargs' s'"

      and "PRE_shared spre sargs sargs'"
      and "k. PRE_unique (upre k) (uargs k) (uargs' k)"

    shows "s''. possible_sequence sargs' uargs' s''  PRE_sequence spre upre s s''"
  using assms
proof (induct s arbitrary: sargs uargs sargs' uargs' s')
  case Nil
  then have "sargs = mset []  (k. uargs k = [])"
    by (simp add: possible_sequence_def)
  then have "sargs' = {#}  (k. uargs' k = [])"
    by (metis Nil.prems(3) Nil.prems(4) PRE_shared_same_size PRE_unique_def length_0_conv mset.simps(1) size_eq_0_iff_empty)
  then show "s''. possible_sequence sargs' uargs' s''  PRE_sequence spre upre [] s''"
    by (simp add: PRE_sequence_def possible_sequence_def)
next
  case (Cons act s)

  show "s''. possible_sequence sargs' uargs' s''  PRE_sequence spre upre (act # s) s''"
  proof (cases act)
    case (Shared sarg)

    then have "sarg ∈# sargs"
      by (metis Cons.prems(1) possible_sequence_where_is_shared)
    then obtain sarg' where "sarg' ∈# sargs'" "spre sarg sarg'" "PRE_shared spre (sargs - {# sarg #}) (sargs' - {# sarg' #})"
      by (metis Cons.prems(3) obtain_other_elem_ms)
    let ?sargs = "sargs - {# sarg #}"
    let ?sargs' = "sargs' - {# sarg' #}"
    have "possible_sequence ?sargs uargs s"
    proof (rule possible_sequenceI)
      show "i. uargs i = map get_u (filter (is_Unique_i i) s)"
        using Cons.prems(1) Shared action.disc(1) filter.simps(2) is_Unique_def is_Unique_i_def
          possible_sequence_def[of sargs uargs "act # s"]
        by metis
      have "sargs = image_mset get_s (filter_mset is_Shared (mset(Shared sarg # s)))"
        using Cons.prems(1) Shared possible_sequence_def by blast
      then show "sargs - {#sarg#} = image_mset get_s (filter_mset is_Shared (mset s))" by simp
    qed

    obtain i where "i  0  i < length s'  s' ! i = Shared sarg'  possible_sequence ?sargs' uargs' (remove_at_index i s')"
      by (meson Cons.prems(2) sarg' ∈# sargs' exists_index_in_sequence_shared)
    
    then obtain s'' where "possible_sequence ?sargs' uargs' s''  PRE_sequence spre upre s s''"
      using Cons.hyps Cons.prems(4) PRE_shared spre (sargs - {#sarg#}) (sargs' - {#sarg'#}) possible_sequence (sargs - {#sarg#}) uargs s by blast

    let ?s'' = "Shared sarg' # s''"

    have "possible_sequence sargs' uargs' ?s''"
    proof (rule possible_sequenceI)
      show "i. uargs' i = map get_u (filter (is_Unique_i i) (Shared sarg' # s''))"
        by (metis possible_sequence (sargs' - {#sarg'#}) uargs' s''  PRE_sequence spre upre s s'' action.disc(1) filter.simps(2) is_Unique_def is_Unique_i_def possible_sequence_def)
      show "sargs' = image_mset get_s (filter_mset is_Shared (mset (Shared sarg' # s'')))"
        using possible_sequence (sargs' - {#sarg'#}) uargs' s''  PRE_sequence spre upre s s'' sarg' ∈# sargs'
          insert_DiffM[of sarg' sargs'] possible_sequence_def[of "sargs' - {#sarg'#}" uargs' s'']
          action.disc(1) action.sel(1) filter_mset_add_mset msed_map_invL mset.simps(2)
        by auto
    qed

    moreover have "PRE_sequence spre upre (act # s) ?s''"
      by (simp add: PRE_sequenceI_rec Shared possible_sequence (sargs' - {#sarg'#}) uargs' s''  PRE_sequence spre upre s s'' spre sarg sarg')

    ultimately show "s''. possible_sequence sargs' uargs' s''  PRE_sequence spre upre (act # s) s''" by auto
  next
    case (Unique k uarg)
    then have "hd (uargs k) = uarg"
      by (metis Cons.prems(1) possible_sequence_where_is_unique)
    moreover have "uargs k  []"
      by (metis (no_types, lifting) Cons.prems(1) Unique action.disc(2) action.sel(2) dropWhile_eq_Cons_conv dropWhile_eq_self_iff filter.simps(2) is_Unique_def is_Unique_i_def list.map_disc_iff possible_sequence_def)
    ultimately have "uargs k = uarg # tl (uargs k)"
      by fastforce
    moreover have "uargs' k = hd (uargs' k) # tl (uargs' k)"
      by (metis Cons.prems(4) PRE_unique_def calculation length_Cons list.exhaust_sel list.size(3) nat.simps(3))
    ultimately have "upre k uarg (hd (uargs' k))"
      by (metis Cons.prems(4) PRE_unique_def length_greater_0_conv list.simps(3) list.size(3) nth_Cons_0 remdups_adj.simps(1) remdups_adj_length)
    moreover have "PRE_unique (upre k) (tl (uargs k)) (tl (uargs' k))"
      by (metis Cons.prems(4) PRE_unique_implies_tl uargs k = uarg # tl (uargs k) uargs' k = hd (uargs' k) # tl (uargs' k))
    moreover have "possible_sequence sargs (tail_kth uargs k) s"
    proof (rule possible_sequenceI)
      show "i. tail_kth uargs k i = map get_u (filter (is_Unique_i i) s)"
      proof -
        fix i 
        obtain ii where asms: "ii  0" "ii < length (act # s) 
           (act # s) ! ii = Unique k uarg 
           possible_sequence sargs (tail_kth uargs k) (remove_at_index ii (act # s))  (j. 0  j  j < ii  ¬ is_Unique_i k ((act # s) ! j))"
          by (metis Cons.prems(1) hd (uargs k) = uarg uargs k  [] exists_index_in_sequence_unique)
        then show "tail_kth uargs k i = map get_u (filter (is_Unique_i i) s)"
          by (metis Unique action.disc(2) action.sel(2) bot_nat_0.extremum bot_nat_0.not_eq_extremum is_Unique_def is_Unique_i_def nth_Cons_0 possible_sequence_def remove_at_index.simps(2))
      qed
      show "sargs = image_mset get_s (filter_mset is_Shared (mset s))"
        by (metis (mono_tags, lifting) Cons.prems(1) Unique action.disc(2) filter_mset_add_mset mset.simps(2) possible_sequence_def)
    qed
    let ?uarg' = "hd (uargs' k)"
    
    obtain i where "i  0  i < length s'  s' ! i = Unique k ?uarg'  possible_sequence sargs' (tail_kth uargs' k) (remove_at_index i s')"
      by (metis Cons.prems(2) uargs' k = hd (uargs' k) # tl (uargs' k) exists_index_in_sequence_unique list.discI)
    then obtain s'' where "possible_sequence sargs' (tail_kth uargs' k) s''  PRE_sequence spre upre s s''"
      using Cons.hyps[of sargs "tail_kth uargs k" sargs' "tail_kth uargs' k"] Cons.prems(3) possible_sequence sargs (tail_kth uargs k) s calculation(2)
        Cons.prems(4) fun_upd_other fun_upd_same tail_kth_def
      by metis

    let ?s'' = "Unique k (hd (uargs' k)) # s''" 
    have "PRE_sequence spre upre (act # s) ?s''"
      by (simp add: PRE_sequenceI_rec Unique possible_sequence sargs' (tail_kth uargs' k) s''  PRE_sequence spre upre s s'' calculation(1))
    moreover have "possible_sequence sargs' uargs' ?s''"
    proof (rule possible_sequenceI)
      show "i. uargs' i = map get_u (filter (is_Unique_i i) (Unique k (hd (uargs' k)) # s''))"
      proof -
        fix i
        obtain ii where ii_def: "ii  0  ii < length s' 
       s' ! ii = Unique k (hd (uargs' k)) 
       possible_sequence sargs' (tail_kth uargs' k) (remove_at_index ii s')  (j. 0  j  j < ii  ¬ is_Unique_i k (s' ! j))"
          by (metis Cons.prems(2) uargs' k = hd (uargs' k) # tl (uargs' k) exists_index_in_sequence_unique list.discI)
        then show "uargs' i = map get_u (filter (is_Unique_i i) (Unique k (hd (uargs' k)) # s''))"
          using filter_remove[of ii s' "is_Unique_i i"] remove_at_index_filter[of ii s' "is_Unique_i i"]
            Cons.prems(2) possible_sequence sargs' (tail_kth uargs' k) s''  PRE_sequence spre upre s s''
            uargs' k = hd (uargs' k) # tl (uargs' k) action.sel(2) action.sel(3)
            filter.simps(2)[of "is_Unique_i i" "Unique k (hd (uargs' k))" s'']
             is_Unique_i_def list.simps(9)[of get_u]
            possible_sequence_def[of sargs' "tail_kth uargs' k" "remove_at_index ii s'"]
            possible_sequence_def[of sargs' uargs' s']
            possible_sequence_def[of sargs' "tail_kth uargs' k" s''] ii_def
          by metis
      qed
      show "sargs' = image_mset get_s (filter_mset is_Shared (mset (Unique k (hd (uargs' k)) # s'')))"
        using possible_sequence sargs' (tail_kth uargs' k) s''  PRE_sequence spre upre s s'' possible_sequence_def by auto
    qed
    ultimately show "s''. possible_sequence sargs' uargs' s''  PRE_sequence spre upre (act # s) s''" by blast
  qed
qed

lemma insert_remove_same_list:
  assumes "k  0  k < length s"
      and "s ! k = x"
  shows "s = insert_at k x (remove_at_index k s)"
proof (rule list_ext)
  show "length s = length (insert_at k x (remove_at_index k s))"
    by (metis One_nat_def Suc_pred add.commute assms(1) insert_at_index(1) length_greater_0_conv less_Suc_eq_le linorder_not_le list.size(3) plus_1_eq_Suc remove_at_index(1))
  fix i assume asm0: "0  i  i < length s"
  show "s ! i = insert_at k x (remove_at_index k s) ! i"
  proof (cases "i < k")
    case True
    then show ?thesis
      by (metis (no_types, lifting) One_nat_def Suc_pred asm0 assms(1) insert_at_index(2) less_Suc_eq_le order_le_less_trans remove_at_index(1) remove_at_index(2))
  next
    case False
    then have "i  k" by simp
    then show ?thesis
    proof (cases "i = k")
      case True
      then show ?thesis
        by (metis (no_types, lifting) One_nat_def Suc_pred assms(1) assms(2) insert_at_index(3) less_Suc_eq_le order_le_less_trans remove_at_index(1))
    next
      case False
      then have "i > k"
        using k  i nless_le by blast
      then show "s ! i = insert_at k x (remove_at_index k s) ! i"
        apply (cases i)
         apply blast
        using Groups.add_ac(2) One_nat_def Suc_less_eq Suc_pred asm0 assms(1)
          insert_at_index(4)[of k _ i x]
          less_Suc_eq_le order_le_less_trans plus_1_eq_Suc remove_at_index(1)[of k s]
          remove_at_index(3)[of k s  ]
        by fastforce
    qed
  qed
qed

lemma swap_works:
  assumes "length s = length s'"
      and "k < length s - 1"
      and "i. i  0  i < length s  i  k  i  k + 1  s ! i = s' ! i"
      and "s ! k = s' ! (k + 1)"
      and "s' ! k = s ! (k + 1)"
      and "PRE_sequence spre upre s s"
      and "α v0 = α v0'"
      and "¬ (k'. is_Unique_i k' (s ! k)  is_Unique_i k' (s ! (k + 1)))"
      and "all_axioms α sact spre uact upre"
    shows "α (compute sact uact v0 s) = α (compute sact uact v0' s')" (is "?A = ?B")
  using assms
proof (induct k arbitrary: s s')
  case 0
  then obtain x1 x2 xs where "s = x1 # x2 # xs"
    by (metis Suc_length_conv Suc_pred add_0 le_add_diff_inverse less_diff_conv less_imp_le_nat plus_1_eq_Suc)
  then have "hd s' = x2"
    by (metis "0.prems"(1) "0.prems"(2) "0.prems"(5) One_nat_def add_0 hd_conv_nth length_greater_0_conv length_tl list.sel(2) nth_Cons_0 nth_Cons_Suc)
  moreover have "hd (tl s') = x1"
    by (metis "0.prems"(1) "0.prems"(2) "0.prems"(4) Suc_eq_plus1 s = x1 # x2 # xs hd_conv_nth length_greater_0_conv length_tl nth_Cons_0 nth_tl)
  ultimately obtain xs' where "s' = x2 # x1 # xs'"
    by (metis "0.prems"(1) "0.prems"(2) length_greater_0_conv length_tl list.collapse list.sel(2))
  moreover have "xs = xs'"
  proof (rule list_ext)
    show "length xs = length xs'"
      using "0.prems"(1) s = x1 # x2 # xs calculation by auto
    fix i assume "0  i  i < length xs"
    then show "xs ! i = xs' ! i"
      by (metis "0.prems"(3) Suc_eq_plus1 Suc_less_eq s = x1 # x2 # xs bot_nat_0.extremum calculation diff_Suc_1 length_Cons nat.simps(3) nth_Cons_Suc)
  qed
  have "PRE_sequence spre upre xs xs"
    apply (cases x1) apply (cases x2)
    using "0.prems"(6) s = x1 # x2 # xs PRE_sequenceE_rec(1) by blast+
  then have "α (compute sact uact v0 xs) = α (compute sact uact v0' xs)"
    using assms(7)
  proof (induct xs)
    case Nil
    then show ?case by simp
  next
    case (Cons a xs)
    then have "α (compute sact uact v0 xs) = α (compute sact uact v0' xs)"
      using PRE_sequenceE_rec(1) by blast
    then show "α (compute sact uact v0 (a # xs)) = α (compute sact uact v0' (a # xs))"
    proof (cases a)
      case (Shared x1)
      then show ?thesis
        by (metis all_axioms α sact spre uact upre Cons.prems(1) PRE_sequenceE_rec(2) α (compute sact uact v0 xs) = α (compute sact uact v0' xs) abstract_pre.simps(1) compute.simps(2) sabstract)
    next
      case (Unique x2)
      then show ?thesis
        by (metis all_axioms α sact spre uact upre Cons.prems(1) PRE_sequenceE_rec(2) α (compute sact uact v0 xs) = α (compute sact uact v0' xs) abstract_pre.simps(2) compute.simps(3) uabstract)
    qed
  qed
  then show ?case
  proof (cases x1)
    case (Shared sarg1)
    then have "x1 = Shared sarg1" by simp
    then show ?thesis
    proof (cases x2)
      case (Shared sarg2)
      then show "α (compute sact uact v0 s) = α (compute sact uact v0' s')"
        using all_axioms α sact spre uact upre "0.prems"(2) "0.prems"(5) "0.prems"(6) One_nat_def
          PRE_sequenceE_rec(2)[of spre upre x1 "x2 # xs" x1 "x2 # xs"]
          PRE_sequence_def[of spre upre s s] Suc_eq_plus1
          α (compute sact uact v0 xs) = α (compute sact uact v0' xs) s = x1 # x2 # xs
          x1 = Shared sarg1 xs = xs'
          abstract_pre.simps(1)[of spre upre sarg2 sarg2]
          abstract_pre.simps(1)[of spre upre sarg1 sarg1]
          calculation compute.simps(2)[of sact uact v0]
          calculation compute.simps(2)[of sact uact v0']
          nth_Cons_0 ss_com[of α sact spre uact upre] zero_less_diff zero_less_one_class.zero_le_one
        by metis
    next
      case (Unique uarg2)
      then show ?thesis
        using all_axioms α sact spre uact upre "0.prems"(6) PRE_sequenceE_rec(1)[of spre upre x1 "x2 # xs" x1 "x2 # xs"]
          PRE_sequenceE_rec(2)[of spre upre ]
          Shared α (compute sact uact v0 xs) = α (compute sact uact v0' xs) s = x1 # x2 # xs xs = xs'
          abstract_pre.simps(1)[of spre upre] abstract_pre.simps(2)[of spre upre] calculation
          compute.simps(2)[of sact uact ] compute.simps(3)[of sact uact]
          su_com[of α sact spre uact upre]
        by metis
    qed
  next
    case (Unique k1 uarg1)
    then have "x1 = Unique k1 uarg1" by simp
    then show ?thesis
    proof (cases x2)
      case (Shared sarg2)
      then have "spre sarg2 sarg2  upre k1 uarg1 uarg1"
        by (metis "0.prems"(6) PRE_sequenceE_rec(1) PRE_sequenceE_rec(2) Unique s = x1 # x2 # xs abstract_pre.simps(1) abstract_pre.simps(2))
      then show ?thesis
      using all_axioms α sact spre uact upre Unique α (compute sact uact v0 xs) = α (compute sact uact v0' xs)
        s = x1 # x2 # xs s' = x2 # x1 # xs' xs = xs' compute.simps(2)[of sact uact]
        compute.simps(3)[of sact uact] su_com[of α sact spre uact upre]
      by (metis Shared)
    next
      case (Unique k2 uarg2)
      then have "k1  k2"
        by (metis "0.prems"(5) "0.prems"(8) Suc_eq_plus1 thesis. (xs'. s' = x2 # x1 # xs'  thesis)  thesis s = x1 # x2 # xs x1 = Unique k1 uarg1 action.disc(2) action.sel(2) is_Unique_def is_Unique_i_def nth_Cons_0)
      then have "upre k2 uarg2 uarg2  upre k1 uarg1 uarg1"
        by (metis "0.prems"(6) PRE_sequenceE_rec(1) PRE_sequenceE_rec(2) Unique s = x1 # x2 # xs x1 = Unique k1 uarg1 abstract_pre.simps(2))

      then show ?thesis
      using all_axioms α sact spre uact upre Unique α (compute sact uact v0 xs) = α (compute sact uact v0' xs)
        s = x1 # x2 # xs s' = x2 # x1 # xs' xs = xs' compute.simps(2)[of sact uact]
        uu_com[of α sact spre uact upre k1 k2 "compute sact uact v0' xs" "compute sact uact v0 xs"]
         k1  k2 x1 = Unique k1 uarg1 compute.simps(3)
      by auto
    qed
  qed
next
  case (Suc k)
  then obtain x xs x' xs' where "s = x # xs" "s' = x' # xs'"
    by (metis diff_0_eq_0 length_0_conv neq_Nil_conv not_less_zero)
  then have "x = x'"
    using Suc.prems(3) by force
  moreover have "α (compute sact uact v0 (tl s)) = α (compute sact uact v0' (tl s'))"
  proof (rule Suc(1))
    show "length (tl s) = length (tl s')"
      by (simp add: Suc.prems(1))
    show "k < length (tl s) - 1"
      using Suc.prems(2) by auto
    show "i. 0  i  i < length (tl s)  i  k  i  k + 1  tl s ! i = tl s' ! i"
      by (metis Suc.prems(3) Suc_eq_plus1 length (tl s) = length (tl s') length_tl less_diff_conv nat.inject nat_le_linear not_less_eq_eq nth_tl)
    show "tl s ! k = tl s' ! (k + 1)"
      by (metis Suc.prems(4) Suc_eq_plus1 s = x # xs s' = x' # xs' add_diff_cancel_right' add_gr_0 le_neq_implies_less list.sel(3) not_one_le_zero nth_Cons_pos zero_less_one_class.zero_le_one)
    show "tl s' ! k = tl s ! (k + 1)"
      by (metis Suc.prems(5) Suc_eq_plus1 s = x # xs s' = x' # xs' list.sel(3) nth_Cons_Suc)
    show "PRE_sequence spre upre (tl s) (tl s)"
      by (metis Suc.prems(6) s = x # xs PRE_sequenceE_rec(1) list.sel(3))
    show "α v0 = α v0'"
      by (simp add: assms(7))
    show "¬ (k'. is_Unique_i k' (tl s ! k)  is_Unique_i k' (tl s ! (k + 1)))"
      using Suc.prems(8) s = x # xs by force
    show "all_axioms α sact spre uact upre"
      by (simp add: Suc.prems(9))
  qed
  ultimately show ?case
  proof (cases x)
    case (Shared x1)
    then show ?thesis
      using all_axioms α sact spre uact upre PRE_sequenceE_rec(2) Suc.prems(6) α (compute sact uact v0 (tl s)) = α (compute sact uact v0' (tl s')) s = x # xs s' = x' # xs' x = x' sabstract 
      by fastforce
  next
    case (Unique x2)
    then show ?thesis
      using all_axioms α sact spre uact upre PRE_sequenceE_rec(2) Suc.prems(6)
        α (compute sact uact v0 (tl s)) = α (compute sact uact v0' (tl s')) s = x # xs s' = x' # xs'
        x = x' uabstract[of α sact spre uact upre]
      by fastforce
  qed
qed

lemma mset_remove:
  assumes "k  0  k < length s"
  shows "mset s = mset (remove_at_index k s) + {# s ! k #}"
  using assms
proof (induct s arbitrary: k)
  case Nil
  then show ?case
    by simp
next
  case (Cons a s)
  then show ?case
    using less_Suc_eq_0_disj by auto
qed

lemma abstract_pre_refl:
  assumes "abstract_pre spre upre a b"
      and "all_axioms α sact spre uact upre"
  shows "abstract_pre spre upre b b"
  apply (cases a)
   apply (cases b)
  using abstract_pre.simps(1) assms spre_refl apply metis
  using assms apply force
   apply (cases b)
  using assms apply force
  using abstract_pre.simps(2) assms upre_refl by metis

lemma PRE_sequence_refl:
  assumes "PRE_sequence spre upre s s'"
      and "all_axioms α sact spre uact upre"
  shows "PRE_sequence spre upre s' s'"
proof (rule PRE_sequenceI)
  show "length s' = length s'"
    by simp
  fix i assume "0  i  i < length s'"
  then show "abstract_pre spre upre (s' ! i) (s' ! i)"
    by (metis PRE_sequence_def abstract_pre_refl assms)
qed

lemma PRE_sequence_removes:
  assumes "PRE_sequence spre upre s s"
  shows "PRE_sequence spre upre (remove_at_index n s) (remove_at_index n s)"
  using assms
proof (induct n arbitrary: s)
  case 0
  then show ?case
    by (metis PRE_sequenceE_rec(1) nat.simps(3) remove_at_index.elims)
next
  case (Suc n)
  then show ?case
    apply (cases s)
     apply force
    by (metis PRE_sequenceE_rec(1) PRE_sequenceE_rec(2) PRE_sequenceI_rec remove_at_index.simps(3))
qed

lemma PRE_sequence_insert:
  assumes "abstract_pre spre upre x x"
    and "PRE_sequence spre upre s s"
    shows "PRE_sequence spre upre (insert_at n x s) (insert_at n x s)"
  using assms
proof (induct n arbitrary: s)
  case 0
  then show ?case
    by (simp add: PRE_sequenceI_rec)
next
  case (Suc n)
  then show ?case
    apply (cases s)
     apply (simp add: PRE_sequenceI_rec)
    by (metis PRE_sequenceE_rec(1) PRE_sequenceE_rec(2) PRE_sequenceI_rec insert_at.simps(3))
qed

lemma empty_possible_sequence:
  assumes "possible_sequence sargs uargs []"
      and "possible_sequence sargs uargs s'"
  shows "s' = []"
proof (rule ccontr)
  assume "s'  []"
  then obtain x q where "s' = x # q"
    by (meson neq_Nil_conv)
  then show False
  proof (cases x)
    case (Shared x1)
    then show ?thesis
      by (metis s' = x # q assms(1) assms(2) exists_index_in_sequence_shared less_zeroE list.size(3) possible_sequence_where_is_shared)
  next
    case (Unique k uarg)
    then have "uargs k  []"
      by (metis (no_types, lifting) s' = x # q action.disc(2) action.sel(2) assms(2) filter.simps(2) is_Unique_def is_Unique_i_def list.discI list.map_disc_iff possible_sequence_def)
    then show ?thesis
      by (metis assms(1) exists_index_in_sequence_unique less_nat_zero_code list.size(3))
  qed
qed

lemma it_all_commutes:
  assumes "possible_sequence sargs uargs s"
      and "possible_sequence sargs uargs s'"
      and "α v0 = α v0'"
      and "PRE_sequence spre upre s s"
      and "PRE_sequence spre upre s' s'"
      and "all_axioms α sact spre uact upre"
    shows "α (compute sact uact v0 s) = α (compute sact uact v0' s')"
  using assms
proof (induct "size s" arbitrary: sargs uargs s s')
  case 0
  then have "s = []  s' = []"
    by (simp add: empty_possible_sequence)
  then show ?case
    by (simp add: "0.prems"(1) "0.prems"(2) assms(3))
next
  case (Suc n)
  moreover obtain x s1 where "s = x # s1"
    by (meson Suc.hyps(2) Suc_length_conv)
  then have "abstract_pre spre upre x x"
    using Suc.prems(4) PRE_sequenceE_rec(2) by blast
  then show ?case
  proof (cases x)
    case (Shared sarg)
    then have "Shared sarg  set s'"
      by (metis Suc.prems(1) Suc.prems(2) s = x # s1 exists_index_in_sequence_shared nth_mem possible_sequence_where_is_shared)
    then obtain k where "k  0  k < length s'  s' ! k = x"
      by (metis Shared bot_nat_0.extremum in_set_conv_nth)

    let ?s' = "remove_at_index k s'"
    have "length ?s' = length s' - 1"
      by (simp add: 0  k  k < length s'  s' ! k = x remove_at_index(1))
    moreover have "k < length s'"
      by (simp add: 0  k  k < length s'  s' ! k = x)
    then have "s' = insert_at k x ?s'"
      by (simp add: 0  k  k < length s'  s' ! k = x insert_remove_same_list)
    define i :: nat where "i = k"
    have "i  0  i  k  α (compute sact uact v0' (insert_at (k - i) x ?s')) = α (compute sact uact v0' s')" 
    proof (induct i)
      case 0
      then show ?case
        using s' = insert_at k x (remove_at_index k s') by auto
    next
      case (Suc i)
      then have "α (compute sact uact v0' (insert_at (k - i) x (remove_at_index k s'))) = α (compute sact uact v0' s')"
        using Suc_leD by blast
      moreover have "α (compute sact uact v0' (insert_at (k - Suc i) x (remove_at_index k s'))) = α (compute sact uact v0' (insert_at (k - i) x (remove_at_index k s')))"
      proof (rule swap_works)
        show "length (insert_at (k - Suc i) x (remove_at_index k s')) = length (insert_at (k - i) x (remove_at_index k s'))"
          by (metis (no_types, lifting) Suc_pred' 0  k  k < length s'  s' ! k = x length (remove_at_index k s') = length s' - 1 diff_le_self insert_at_index(1) less_Suc_eq_le order_le_less_trans)
        show "PRE_sequence spre upre (insert_at (k - Suc i) x (remove_at_index k s')) (insert_at (k - Suc i) x (remove_at_index k s'))"
        proof -
          have "PRE_sequence spre upre (remove_at_index k s') (remove_at_index k s')" using PRE_sequence spre upre s' s'
            using PRE_sequence_removes by auto
          then show ?thesis using PRE_sequence_insert abstract_pre spre upre x x by blast
        qed
        show "α v0' = α v0'" by simp
        let ?k = "k - Suc i"

        show "?k < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1"
          using One_nat_def Suc.prems Suc_diff_Suc Suc_le_lessD k < length s' length (remove_at_index k s') = length s' - 1
            s' = insert_at k x (remove_at_index k s') diff_le_self diff_zero
            insert_at_index(1)[of "k - Suc i" _ x] insert_at_index(1)[of k _ x] less_Suc_eq_le order_le_less_trans
          by simp
        show "insert_at (k - Suc i) x (remove_at_index k s') ! ?k = insert_at (k - i) x (remove_at_index k s') ! (?k + 1)"
          apply (cases k)
          using Suc.prems apply blast
          apply (cases ?k)
           apply (metis (no_types, lifting) Suc.prems Suc_eq_plus1 Suc_leI k - Suc i < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1 add_diff_cancel_right' diff_diff_cancel diff_zero insert_at_index(1) insert_at_index(3) le_numeral_extra(3) length_greater_0_conv list.size(3) nat_less_le plus_1_eq_Suc)
        proof -
          fix nat nata assume r: "k = Suc nat" "k - Suc i = Suc nata"
          moreover have "insert_at (k - i) x (remove_at_index k s') ! (k - i) = x"
            by (metis Suc_pred' k < length s' length (remove_at_index k s') = length s' - 1 bot_nat_0.extremum diff_le_self insert_at_index(3) less_Suc_eq_le order_le_less_trans)
          moreover have "x. insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i) = x"
            by (metis Suc_leI Suc_le_mono Suc_pred' 0  k  k < length s'  s' ! k = x length (remove_at_index k s') = length s' - 1 bot_nat_0.extremum diff_le_self insert_at_index(3) order_le_less_trans)
          ultimately show ?thesis
            by (metis Suc.prems Suc_diff_Suc Suc_eq_plus1 Suc_le_lessD)
        qed
        show "insert_at (k - i) x (remove_at_index k s') ! ?k = insert_at (k - Suc i) x (remove_at_index k s') ! (?k + 1)"
        proof -
          have "insert_at (k - i) x (remove_at_index k s') ! (k - Suc i) = remove_at_index k s' ! (k - Suc i)"
            by (metis (no_types, lifting) Suc.prems Suc_diff_Suc Suc_eq_plus1 Suc_leI Suc_le_lessD k < length s' length (remove_at_index k s') = length s' - 1 add_leE insert_at_index(2) le_add_diff_inverse2 le_add_same_cancel2 lessI less_Suc_eq_le)
          moreover have "length (insert_at (k - Suc i) x (remove_at_index k s')) = length (remove_at_index k s') + 1"
            by (metis Suc_eq_plus1 0  k  k < length s'  s' ! k = x length (remove_at_index k s') = length s' - 1 add_le_imp_le_diff insert_at_index(1) less_eq_Suc_le less_imp_diff_less)
          then have "insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i + 1) = remove_at_index k s' ! (k - Suc i + 1 - 1)"
            by (metis k - Suc i < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1 add_diff_cancel_right' insert_at_index(4) less_add_one less_diff_conv less_imp_le_nat)
          ultimately show ?thesis
            by simp
        qed

        show "¬ (k'. is_Unique_i k' (insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i)) 
         is_Unique_i k' (insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i + 1)))"
          by (metis (no_types, lifting) One_nat_def Shared Suc.prems Suc_diff_Suc k < length s' length (remove_at_index k s') = length s' - 1 action.disc(1) add_leE diff_zero insert_at_index(3) is_Unique_def is_Unique_i_def le_add_diff_inverse2 le_add_same_cancel2 less_Suc_eq_le order_le_less_trans)

        show "j. 0  j  j < length (insert_at (k - Suc i) x (remove_at_index k s'))  j  ?k  j  ?k + 1 
         insert_at (k - Suc i) x (remove_at_index k s') ! j = insert_at (k - i) x (remove_at_index k s') ! j"
        proof (clarify)
          fix j assume "0  j" "j < length (insert_at (k - Suc i) x (remove_at_index k s'))" "j  k - Suc i" "j  k - Suc i + 1"
          moreover have "length (insert_at (k - Suc i) x (remove_at_index k s')) = length (remove_at_index k s') + 1"
            by (metis (no_types, lifting) One_nat_def Suc.prems Suc_diff_Suc k < length s' length (remove_at_index k s') = length s' - 1 add_leE diff_zero insert_at_index(1) le_add_diff_inverse2 less_Suc_eq_le order_le_less_trans)
          moreover have "k - Suc i  length (remove_at_index k s')"
            using k - Suc i < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1 calculation(5) by force
          ultimately show "insert_at (k - Suc i) x (remove_at_index k s') ! j = insert_at (k - i) x (remove_at_index k s') ! j"
            apply (cases "j < k - Suc i")
            using insert_at_index(2)[of "k - Suc i" "remove_at_index k s'" j x] insert_at_index(2)[of "k - i" "remove_at_index k s'" j x]
            apply (metis Suc.prems Suc_diff_le Suc_eq_plus1 Suc_leI k - Suc i < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1 diff_Suc_1 diff_Suc_Suc less_Suc_eq)
            by (simp add: insert_at_index(4) nat_neq_iff)
        qed
        show "all_axioms α sact spre uact upre"
          by (simp add: assms(6))
      qed
      ultimately show ?case
        by presburger
    qed
    then have "α (compute sact uact v0' (x # ?s')) = α (compute sact uact v0' s')"
      using i_def by force
    moreover have "α (compute sact uact v0 s1) = α (compute sact uact v0' ?s')"
    proof (rule Suc(1))
      show "n = length s1"
        using Suc.hyps(2) s = x # s1 by auto
      show "α v0 = α v0'"
        using assms(3) by auto
      show "PRE_sequence spre upre s1 s1"
        using PRE_sequenceE_rec(1) Suc.prems(4) s = x # s1 by blast
      show "possible_sequence (sargs - {# sarg #}) uargs s1"
      proof (rule possible_sequenceI)
        show "i. uargs i = map get_u (filter (is_Unique_i i) s1)"
          by (metis (mono_tags, lifting) Shared Suc.hyps(2) Suc.prems(1) s = x # s1 action.disc(1) filter_remove is_Unique_def is_Unique_i_def le_numeral_extra(3) nth_Cons_0 possible_sequence_def remove_at_index.simps(2) zero_less_Suc)
        show "sargs - {#sarg#} = image_mset get_s (filter_mset is_Shared (mset s1))"
          using Shared Suc.prems(1) s = x # s1 action.disc(1)[of sarg] action.sel(1)[of sarg] add_mset_diff_bothsides diff_empty
            filter_mset_add_mset msed_map_invL mset.simps(2) possible_sequence_def[of sargs uargs s]
          by simp
      qed

      show "possible_sequence (sargs - {#sarg#}) uargs (remove_at_index k s')"
      proof (rule possible_sequenceI)
        show "i. uargs i = map get_u (filter (is_Unique_i i) (remove_at_index k s'))"
        proof (rule list_ext)
          have "filter is_Unique (remove_at_index k s') = filter is_Unique s'"
            by (simp add: Shared 0  k  k < length s'  s' ! k = x filter_remove is_Unique_def)
          then show "i. length (uargs i) = length (map get_u (filter (is_Unique_i i) (remove_at_index k s')))"
            by (metis Shared Suc.prems(2) 0  k  k < length s'  s' ! k = x action.disc(1) filter_remove is_Unique_def is_Unique_i_def possible_sequence_def)
          show "i ia. 0  ia  ia < length (uargs i)  uargs i ! ia = map get_u (filter (is_Unique_i i) (remove_at_index k s')) ! ia"
            by (metis Shared Suc.prems(2) 0  k  k < length s'  s' ! k = x action.disc(1) filter_remove is_Unique_def is_Unique_i_def possible_sequence_def)
        qed
        have "sargs = image_mset get_s (filter_mset is_Shared (mset s'))"
          using Suc.prems(2) possible_sequence_def by blast
        show "sargs - {#sarg#} = image_mset get_s (filter_mset is_Shared (mset (remove_at_index k s')))"
        proof -
          have "mset s' = mset (remove_at_index k s') + {# x #}"
            using 0  k  k < length s'  s' ! k = x mset_remove_index by blast
          then show ?thesis
            by (simp add: Shared sargs = image_mset get_s (filter_mset is_Shared (mset s')))
        qed
      qed
      show "PRE_sequence spre upre (remove_at_index k s') (remove_at_index k s')" using Suc.prems(5) PRE_sequence_removes by blast
      show "all_axioms α sact spre uact upre" by (simp add: assms(6))
    qed
    ultimately show ?thesis
      using all_axioms α sact spre uact upre PRE_sequenceE_rec(2) Shared Suc.prems(4) s = x # s1 abstract_pre.simps(1) compute.simps(2) sabstract
      by fastforce
  next
    case (Unique ind uarg)
    let ?uargs = "uargs ind"
    have "hd ?uargs = uarg"
      by (metis Unique s = x # s1 calculation(3) possible_sequence_where_is_unique)
    moreover have "?uargs  []"
      by (metis (no_types, opaque_lifting) Suc.prems(1) Unique s = x # s1 action.disc(2) action.sel(2) filter.simps(2) is_Unique_def is_Unique_i_def list.distinct(1) list.map_disc_iff possible_sequence_def)
    ultimately have "?uargs = uarg # tl ?uargs"
      by force
    then obtain k where "k  0  k < length s'  s' ! k = x" "j. j  0  j < k  ¬ is_Unique_i ind (s' ! j)"
      by (metis Suc.prems(2) Unique hd (uargs ind) = uarg uargs ind  [] exists_index_in_sequence_unique)
    let ?s' = "remove_at_index k s'"
    have "length ?s' = length s' - 1"
      by (simp add: 0  k  k < length s'  s' ! k = x remove_at_index(1))
    moreover have "k < length s'"
      by (simp add: 0  k  k < length s'  s' ! k = x)
    then have "s' = insert_at k x ?s'"
      by (simp add: 0  k  k < length s'  s' ! k = x insert_remove_same_list)
    define i :: nat where "i = k"
    have "i  0  i  k  α (compute sact uact v0' (insert_at (k - i) x ?s')) = α (compute sact uact v0' s')" 
    proof (induct i)
      case 0
      then show ?case
        using s' = insert_at k x (remove_at_index k s') by auto
    next
      case (Suc i)
      then have "α (compute sact uact v0' (insert_at (k - i) x (remove_at_index k s'))) = α (compute sact uact v0' s')"
        using Suc_leD by blast
      moreover have "α (compute sact uact v0' (insert_at (k - Suc i) x (remove_at_index k s'))) = α (compute sact uact v0' (insert_at (k - i) x (remove_at_index k s')))"
      proof (rule swap_works)
        show "length (insert_at (k - Suc i) x (remove_at_index k s')) = length (insert_at (k - i) x (remove_at_index k s'))"
          by (metis (no_types, lifting) Suc_pred' 0  k  k < length s'  s' ! k = x length (remove_at_index k s') = length s' - 1 insert_at_index(1) less_Suc_eq_le less_imp_diff_less order_le_less_trans)
        show "PRE_sequence spre upre (insert_at (k - Suc i) x (remove_at_index k s')) (insert_at (k - Suc i) x (remove_at_index k s'))"
        proof -
          have "PRE_sequence spre upre (remove_at_index k s') (remove_at_index k s')"
            using PRE_sequence spre upre s' s'
            by (simp add: PRE_sequence_removes)
          then show ?thesis
            using abstract_pre spre upre x x PRE_sequence_insert by blast
        qed

        show "α v0' = α v0'" by simp
        let ?k = "k - Suc i"


        show "?k < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1"
          using One_nat_def Suc.prems Suc_diff_Suc Suc_le_lessD k < length s'
            length (remove_at_index k s') = length s' - 1 s' = insert_at k x (remove_at_index k s')
            diff_le_self diff_zero insert_at_index(1)[of k "remove_at_index k s'" x] insert_at_index(1)[of "k - Suc i" "remove_at_index k s'" x]
            less_Suc_eq_le order_le_less_trans
          by simp
        show "insert_at (k - Suc i) x (remove_at_index k s') ! ?k = insert_at (k - i) x (remove_at_index k s') ! (?k + 1)"
        proof -
          have "insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i) = x"
            by (metis Suc_pred' k < length s' length (remove_at_index k s') = length s' - 1 bot_nat_0.extremum diff_self_eq_0 insert_at_index(3) less_Suc_eq_le less_imp_diff_less)
          moreover have "insert_at (k - i) x (remove_at_index k s') ! (k - i) = x"
            by (metis Suc_pred' k < length s' length (remove_at_index k s') = length s' - 1 bot_nat_0.extremum insert_at_index(3) less_Suc_eq_le less_imp_diff_less less_nat_zero_code not_gr_zero)
          ultimately show ?thesis
            by (simp add: Suc.prems Suc_diff_Suc Suc_le_lessD)
        qed
        have "insert_at (k - i) x (remove_at_index k s') ! (k - Suc i) = remove_at_index k s' ! (k - Suc i)"
          by (metis (no_types, lifting) Suc.prems Suc_diff_Suc Suc_eq_plus1 Suc_leI Suc_le_lessD k < length s' length (remove_at_index k s') = length s' - 1 add_leE insert_at_index(2) le_add_diff_inverse2 le_add_same_cancel2 lessI less_Suc_eq_le)
        then 
        show "insert_at (k - i) x (remove_at_index k s') ! ?k = insert_at (k - Suc i) x (remove_at_index k s') ! (?k + 1)"
          using  One_nat_def Suc.prems Suc_diff_Suc k - Suc i < length (insert_at (k - Suc i) x (remove_at_index k s')) - 1
            k < length s' length (remove_at_index k s') = length s' - 1 add_diff_cancel_right'
            add_leE diff_zero insert_at_index(1)[of "k - Suc i" "remove_at_index k s'" x] insert_at_index(4)[of "k - Suc i" "remove_at_index k s'"]
            le_add_diff_inverse2 less_Suc_eq_le
            less_add_same_cancel1 less_diff_conv order_le_less_trans zero_less_one
          by simp

        have "insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i + 1) = remove_at_index k s' ! (k - Suc i + 1 - 1)"
          using insert_at (k - i) x (remove_at_index k s') ! (k - Suc i) = insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i + 1) insert_at (k - i) x (remove_at_index k s') ! (k - Suc i) = remove_at_index k s' ! (k - Suc i) by auto
        then have "¬ is_Unique_i ind (insert_at (k - Suc i) x (remove_at_index k s') ! (?k + 1))"
          by (metis One_nat_def Suc.prems Suc_le_lessD j. 0  j  j < k  ¬ is_Unique_i ind (s' ! j) k < length s' add_diff_cancel_right' add_leE diff_Suc_less le_add2 le_add_same_cancel2 plus_1_eq_Suc remove_at_index(2))
        then show "¬ (k'. is_Unique_i k' (insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i)) 
         is_Unique_i k' (insert_at (k - Suc i) x (remove_at_index k s') ! (k - Suc i + 1)))"
          by (metis (no_types, lifting) One_nat_def Suc.prems Suc_diff_Suc Unique k < length s' length (remove_at_index k s') = length s' - 1 action.sel(2) diff_zero insert_at_index(3) is_Unique_i_def le_add2 le_add_diff_inverse le_add_same_cancel2 less_Suc_eq_le order_le_less_trans)
        show "j. 0  j  j < length (insert_at (k - Suc i) x (remove_at_index k s'))  j  ?k  j  ?k + 1 
         insert_at (k - Suc i) x (remove_at_index k s') ! j = insert_at (k - i) x (remove_at_index k s') ! j"
        proof -
          fix j assume "0  j  j < length (insert_at (k - Suc i) x (remove_at_index k s'))  j  ?k  j  ?k + 1"
          moreover have "k - Suc i  length (remove_at_index k s')"
            using 0  k  k < length s'  s' ! k = x length (remove_at_index k s') = length s' - 1 by force
          moreover have "k - i  length (remove_at_index k s')"
            using k < length s' length (remove_at_index k s') = length s' - 1 by linarith
          then show "insert_at (k - Suc i) x (remove_at_index k s') ! j = insert_at (k - i) x (remove_at_index k s') ! j"
            apply (cases "j < k - i")
            apply (metis Suc.prems Suc_diff_Suc Suc_le_lessD calculation(1) calculation(2) insert_at_index(2) less_Suc_eq)
            by (metis Suc.prems Suc_diff_Suc Suc_eq_plus1 Suc_le_lessD calculation(1) calculation(2) insert_at_index(1) insert_at_index(4) linorder_le_less_linear linorder_neqE_nat)
        qed
        show "all_axioms α sact spre uact upre" by (simp add: assms(6))
      qed
      ultimately show ?case
        by presburger
    qed
    then have "α (compute sact uact v0' (x # ?s')) = α (compute sact uact v0' s')"
      using i_def by force
    moreover have "α (compute sact uact v0 s1) = α (compute sact uact v0' ?s')"
    proof (rule Suc(1))
      show "all_axioms α sact spre uact upre" by (simp add: assms(6))
      show "n = length s1"
        using Suc.hyps(2) s = x # s1 by auto
      show "α v0 = α v0'"
        using assms(3) by auto
      show "PRE_sequence spre upre s1 s1"
        using Suc.prems(4) s = x # s1 PRE_sequenceE_rec(1) by blast
      show "possible_sequence sargs (tail_kth uargs ind) s1"
      proof (rule possible_sequenceI)
        show "i. tail_kth uargs ind i = map get_u (filter (is_Unique_i i) s1)"
        proof -
          fix i show "tail_kth uargs ind i = map get_u (filter (is_Unique_i i) s1)"
          proof (cases "i = ind")
            case True
            then have "tail_kth uargs ind i = tl ?uargs"
              by (simp add: tail_kth_def)
            then show ?thesis using exists_index_in_sequence_unique[of uarg uargs ind sargs s]
              by (metis Suc.prems(1) Unique hd (uargs ind) = uarg s = x # s1 uargs ind  [] action.disc(2) action.sel(2) is_Unique_def is_Unique_i_def le_eq_less_or_eq nth_Cons_0 possible_sequence_def remove_at_index.simps(2))
          next
            case False
            then show ?thesis
              using Suc.hyps(2) Suc.prems(1) Unique s = x # s1 action.sel(2) filter_remove
                fun_upd_apply is_Unique_i_def le_numeral_extra(3) nth_Cons_0[of x s1] possible_sequence_def[of sargs uargs s]
                remove_at_index.simps(2)[of x s1] tail_kth_def zero_less_Suc
              by metis
          qed
        qed
        show "sargs = image_mset get_s (filter_mset is_Shared (mset s1))"
          by (metis Suc.prems(1) Unique s = x # s1 action.disc(2) filter_mset_add_mset mset.simps(2) possible_sequence_def)
      qed
      show "possible_sequence sargs (tail_kth uargs ind) (remove_at_index k s')"
      proof (rule possible_sequenceI)
        show "i. tail_kth uargs ind i = map get_u (filter (is_Unique_i i) (remove_at_index k s'))"
          using Suc.prems(1) Suc.prems(2) Unique 0  k  k < length s'  s' ! k = x j. 0  j  j < k  ¬ is_Unique_i ind (s' ! j)
            possible_sequence sargs (tail_kth uargs ind) s1 s = x # s1 action.sel(2) filter.simps(2)
            filter_remove fun_upd_same is_Unique_i_def possible_sequence_def[of sargs "tail_kth uargs ind" s1]
            possible_sequence_def[of sargs uargs s] possible_sequence_def[of sargs uargs s']
            remove_at_index_filter tail_kth_def
          by metis
        show "sargs = image_mset get_s (filter_mset is_Shared (mset (remove_at_index k s')))"
          by (metis Suc.prems(2) Unique 0  k  k < length s'  s' ! k = x action.disc(2) filter_remove mset_filter possible_sequence_def)
      qed
      show "PRE_sequence spre upre (remove_at_index k s') (remove_at_index k s')"
        using PRE_sequence_removes Suc.prems(5) by auto
    qed
    ultimately show ?thesis
      using Unique abstract_pre spre upre x x s = x # s1 abstract_pre.simps(2)[of ]
        assms(6) compute.simps(3)[of sact uact] uabstract[of α sact spre uact upre ]
      by metis
  qed
qed

lemma PRE_sequence_same_abstract:
  assumes "PRE_sequence spre upre s s'"
      and "α v0 = α v0'"
      and "all_axioms α sact spre uact upre"
    shows "α (compute sact uact v0 s) = α (compute sact uact v0' s')"
  using assms
proof (induct s' arbitrary: s v0 v0')
  case Nil
  then show ?case
    by (simp add: PRE_sequence_def)
next
  case (Cons act' s')
  then show ?case
  proof (cases act')
    case (Shared sarg')
    then obtain sarg s0 where "s = Shared sarg # s0" "spre sarg sarg'" "PRE_sequence spre upre s0 s'"
      by (metis Cons.prems(1) PRE_sequenceE_rec(1) PRE_sequenceE_rec(2) PRE_sequence_def abstract_pre.simps(1) abstract_pre.simps(3) action.exhaust length_0_conv neq_Nil_conv)
    then show ?thesis
      using Cons.hyps Cons.prems(2) Cons.prems(3) Shared sabstract by fastforce
  next
    case (Unique k uarg')
    then obtain uarg s0 where "s = Unique k uarg # s0" "upre k uarg uarg'" "PRE_sequence spre upre s0 s'"
      by (metis Cons.prems(1) PRE_sequenceE_rec(1) PRE_sequenceE_rec(2) PRE_sequence_def abstract_pre.simps(2) abstract_pre.simps(4) action.exhaust length_0_conv neq_Nil_conv)
    then show ?thesis
      using Cons.hyps Cons.prems(2) Unique assms(3) uabstract by fastforce
  qed
qed

lemma simple_possible_PRE_seq:
  assumes "possible_sequence sargs uargs s"
      and "possible_sequence sargs' uargs' s'"
      and "PRE_shared spre sargs sargs'"
      and "k. PRE_unique (upre k) (uargs k) (uargs' k)"
      and "all_axioms α sact spre uact upre"
    shows "PRE_sequence spre upre s' s'"
proof (rule PRE_sequenceI)
  show "length s' = length s'" by simp
  fix i assume "0  i  i < length s'"
  then show "abstract_pre spre upre (s' ! i) (s' ! i)"
  proof (cases "s' ! i")
    case (Shared sarg')
    then have "Shared sarg' ∈# filter_mset is_Shared (mset s')"
      using 0  i  i < length s' nth_mem_mset by fastforce
    then have "sarg' ∈# sargs'"
      by (metis (mono_tags, lifting) action.sel(1) assms(2) imageI possible_sequence_def set_image_mset)
    moreover obtain ms where "image_mset fst ms = sargs  image_mset snd ms = sargs'  (x ∈# ms. spre (fst x) (snd x))"
      using PRE_shared_def assms(3) by blast
    then obtain x where "x ∈# ms" "snd x = sarg'"
      using calculation by fastforce
    then show ?thesis
      using Shared image_mset fst ms = sargs  image_mset snd ms = sargs'  (x∈#ms. spre (fst x) (snd x)) spre_refl
      by (metis abstract_pre.simps(1) assms(5))
  next
    case (Unique k uarg')
    then have "Unique k uarg'  set (filter is_Unique s')"
      by (metis 0  i  i < length s' is_Unique_def action.disc(2) filter_set member_filter nth_mem)
    then have "uarg'  set (map get_u (filter (is_Unique_i k) s'))"
      by (metis (no_types, lifting) action.sel(2) action.sel(3) filter_set image_eqI is_Unique_i_def list.set_map member_filter)
    then obtain i where "i  0  i < length (uargs' k)  uarg' = (uargs' k) ! i"
      by (metis assms(2) gr_implies_not_zero in_set_conv_nth linorder_le_less_linear possible_sequence_def)
    then have "upre k ((uargs k) ! i) ((uargs' k) ! i)"
      using PRE_unique_def assms(4) by blast
    then show ?thesis
      using Unique 0  i  i < length (uargs' k)  uarg' = uargs' k ! i assms(5) upre_refl by fastforce
  qed
qed

lemma main_lemma:
  assumes "possible_sequence sargs uargs s"
      and "possible_sequence sargs' uargs' s'"

      and "PRE_shared spre sargs sargs'"
      and "k. PRE_unique (upre k) (uargs k) (uargs' k)"

      and "α v0 = α v0'"
      and "all_axioms α sact spre uact upre"

    shows "α (compute sact uact v0 s) = α (compute sact uact v0' s')"
proof -
  obtain s'' where "possible_sequence sargs' uargs' s''  PRE_sequence spre upre s s''"
    using assms(1) assms(2) assms(3) assms(4) exists_aligned_sequence by blast
  have "α (compute sact uact v0' s'') = α (compute sact uact v0' s')"
  proof (rule it_all_commutes)
    show "possible_sequence sargs' uargs' s''"
      by (simp add: possible_sequence sargs' uargs' s''  PRE_sequence spre upre s s'')
    show "possible_sequence sargs' uargs' s'"
      by (simp add: assms(2))
    show "α v0' = α v0'"
      by simp
    show "PRE_sequence spre upre s'' s''"
      using possible_sequence sargs' uargs' s''  PRE_sequence spre upre s s'' PRE_sequence_refl assms(6) by blast
    show "PRE_sequence spre upre s' s'"
      using simple_possible_PRE_seq assms(1) assms(2) assms(3) assms(4) assms(6) by blast
    show "all_axioms α sact spre uact upre"
      using assms(6) by auto
  qed
  moreover have "α (compute sact uact v0' s'') = α (compute sact uact v0 s)"
    using PRE_sequence_same_abstract possible_sequence sargs' uargs' s''  PRE_sequence spre upre s s'' assms(1) assms(5) assms(6) by metis
  ultimately show ?thesis
    by auto
qed

text ‹The following inductive predicate captures all possible final values that can be reached with
some interleaving of the actions described a multiset and a family of sequences of actions.›
inductive reachable_value :: "('v  'a  'v)  ('i  'v  'b  'v)  'v  'a multiset  ('i  'b list)  'v  bool" where
  Self: "reachable_value sact uact v0 {#} (λk. []) v0"
| SharedStep: "reachable_value sact uact v0 sargs uargs v1  reachable_value sact uact v0 (sargs + {# sarg #}) uargs (sact v1 sarg)"
| UniqueStep: "reachable_value sact uact v0 sargs uargs v1  reachable_value sact uact v0 sargs (uargs(k := uarg # uargs k)) (uact k v1 uarg)"

lemma reachable_then_possible_sequence_and_compute:
  assumes "reachable_value sact uact v0 sargs uargs v1"
  shows "s. possible_sequence sargs uargs s  v1 = compute sact uact v0 s"
  using assms
proof (induct rule: reachable_value.induct)
  case (Self sact uact v0)
  have "possible_sequence {#} (λk. []) []  v0 = compute sact uact v0 []"
    by (simp add: possible_sequenceI)
  then show ?case by blast
next
  case (SharedStep sact uact v0 sargs uargs v1 sarg)
  then obtain s where "possible_sequence sargs uargs s  v1 = compute sact uact v0 s" by blast
  let ?s = "Shared sarg # s"
  have "possible_sequence (sargs + {#sarg#}) uargs ?s"
  proof (rule possible_sequenceI)
    show "i. uargs i = map get_u (filter (is_Unique_i i) (Shared sarg # s))"
      by (metis possible_sequence sargs uargs s  v1 = compute sact uact v0 s action.disc(1) filter.simps(2) is_Unique_def is_Unique_i_def possible_sequence_def)
    show "sargs + {#sarg#} = image_mset get_s (filter_mset is_Shared (mset (Shared sarg # s)))"
      using possible_sequence sargs uargs s  v1 = compute sact uact v0 s possible_sequence_def by auto
  qed
  then show ?case
    using possible_sequence sargs uargs s  v1 = compute sact uact v0 s by auto
next
  case (UniqueStep sact uact v0 sargs uargs v1 k uarg)
  then obtain s where "possible_sequence sargs uargs s  v1 = compute sact uact v0 s" by blast
  let ?s = "Unique k uarg # s"
  have "possible_sequence sargs (uargs(k := uarg # uargs k)) ?s"
  proof (rule possible_sequenceI)
    show "i. (uargs(k := uarg # uargs k)) i = map get_u (filter (is_Unique_i i) (Unique k uarg # s))"
    proof -
      fix i show "(uargs(k := uarg # uargs k)) i = map get_u (filter (is_Unique_i i) (Unique k uarg # s))"
      proof (cases "i = k")
        case True
        then show ?thesis
          using Cons_eq_map_conv possible_sequence sargs uargs s  v1 = compute sact uact v0 s
            action.disc(2) action.sel(2) action.sel(3) filter.simps(2) fun_upd_same is_Unique_def
            is_Unique_i_def possible_sequence_def[of sargs uargs s]
          by fastforce
      next
        case False
        then show ?thesis
          by (metis possible_sequence sargs uargs s  v1 = compute sact uact v0 s action.sel(2) filter.simps(2) fun_upd_other is_Unique_i_def possible_sequence_def)
      qed
    qed
    show "sargs = image_mset get_s (filter_mset is_Shared (mset (Unique k uarg # s)))"
      using possible_sequence sargs uargs s  v1 = compute sact uact v0 s possible_sequence_def by force
  qed
  then show ?case using possible_sequence sargs uargs s  v1 = compute sact uact v0 s
    by (metis compute.simps(3))
qed

lemma PRE_shared_simpler_implies:
  assumes "PRE_shared_simpler spre a b"
  shows "PRE_shared spre a b"
  using assms
proof (induct rule: PRE_shared_simpler.induct)
  case (Empty spre)
  then show ?case
    by (simp add: PRE_shared_def)
next
  case (Step spre a b xa xb)
  then obtain ms where "image_mset fst ms = a  image_mset snd ms = b  (x∈#ms. spre (fst x) (snd x))"
    by (metis PRE_shared_def)
  then have "image_mset fst (ms + {# (xa, xb) #}) = (a + {#xa#})  image_mset snd (ms + {# (xa, xb) #}) = (b + {#xb#})  (x∈#(ms + {# (xa, xb) #}). spre (fst x) (snd x))"
    using Step.hyps(3) by auto
  then show ?case using PRE_shared_def by blast
qed

text ‹The following theorem corresponds to Lemma 4.2 in the paper.›
theorem main_result:
  assumes "reachable_value sact uact v0 sargs uargs v"
      and "reachable_value sact uact v0' sargs' uargs' v'"
      and "PRE_shared_simpler spre sargs sargs'"
      and "k. PRE_unique (upre k) (uargs k) (uargs' k)"
      and "α v0 = α v0'"
      and "all_axioms α sact spre uact upre"
    shows "α v = α v'"
proof -
  obtain s s' where "possible_sequence sargs uargs s  v = compute sact uact v0 s" "possible_sequence sargs' uargs' s'  v' = compute sact uact v0' s'" 
    using assms(1) assms(2) reachable_then_possible_sequence_and_compute
    by metis
  then show ?thesis
    by (meson PRE_shared_simpler_implies assms(3) assms(4) assms(5) assms(6) main_lemma)
qed

end