Theory VeriComp.Lifting_Simulation_To_Bisimulation
theory Lifting_Simulation_To_Bisimulation
  imports Well_founded
begin
definition stuck_state :: "('a ⇒ 'b ⇒ bool) ⇒ 'a ⇒ bool" where
  "stuck_state ℛ s ⟷ (∄s'. ℛ s s')"
definition simulation ::
  "('a ⇒ 'a ⇒ bool) ⇒ ('b ⇒ 'b ⇒ bool) ⇒ ('c ⇒ 'a ⇒ 'b ⇒ bool) ⇒ ('c ⇒ 'c ⇒ bool) ⇒ bool"
where
  "simulation ℛ⇩1 ℛ⇩2 match order ⟷
    (∀i s1 s2 s1'. match i s1 s2 ⟶ ℛ⇩1 s1 s1' ⟶
      (∃s2' i'. ℛ⇩2⇧+⇧+ s2 s2' ∧ match i' s1' s2') ∨ (∃i'. match i' s1' s2 ∧ order i' i))"
lemma finite_progress:
  fixes
    step1 :: "'s1 ⇒ 's1 ⇒ bool" and
    step2 :: "'s2 ⇒ 's2 ⇒ bool" and
    match :: "'i ⇒ 's1 ⇒ 's2 ⇒ bool" and
    order :: "'i ⇒ 'i ⇒ bool"
  assumes
    matching_states_agree_on_stuck:
      "∀i s1 s2. match i s1 s2 ⟶ stuck_state step1 s1 ⟷ stuck_state step2 s2" and
    well_founded_order: "wfp order" and
    sim: "simulation step1 step2 match order"
  shows "match i s1 s2 ⟹ step1 s1 s1' ⟹
    ∃m s1'' n s2'' i'. (step1 ^^ m) s1' s1'' ∧ (step2 ^^ Suc n) s2 s2'' ∧ match i' s1'' s2''"
  using well_founded_order
proof (induction i arbitrary: s1 s1' rule: wfp_induct_rule)
  case (less i)
  show ?case
    using sim[unfolded simulation_def, rule_format, OF ‹match i s1 s2› ‹step1 s1 s1'›]
  proof (elim disjE exE conjE)
    show "⋀s2' i'. step2⇧+⇧+ s2 s2' ⟹ match i' s1' s2' ⟹ ?thesis"
      by (metis Suc_pred relpowp_0_I tranclp_power)
  next
    fix i'
    assume "match i' s1' s2" and "order i' i"
    have "¬ stuck_state step1 s1"
      using ‹step1 s1 s1'› stuck_state_def by metis
    hence "¬ stuck_state step2 s2"
      using ‹match i s1 s2› matching_states_agree_on_stuck by metis
    hence "¬ stuck_state step1 s1'"
      using ‹match i' s1' s2› matching_states_agree_on_stuck by metis
    then obtain s1'' where "step1 s1' s1''"
      by (metis stuck_state_def)
    obtain m s1''' n s2' i'' where
      "(step1 ^^ m) s1'' s1'''" and
      "(step2 ^^ Suc n) s2 s2'" and
      "match i'' s1''' s2'"
      using less.IH[OF ‹order i' i› ‹match i' s1' s2› ‹step1 s1' s1''›] by metis
    show ?thesis
    proof (intro exI conjI)
      show "(step1 ^^ Suc m) s1' s1'''"
        using ‹(step1 ^^ m) s1'' s1'''› ‹step1 s1' s1''› by (metis relpowp_Suc_I2)
    next
      show "(step2 ^^ Suc n) s2 s2'"
        using ‹(step2 ^^ Suc n) s2 s2'› .
    next
      show "match i'' s1''' s2'"
        using ‹match i'' s1''' s2'› .
    qed
  qed
qed
context begin
private inductive match_bisim
  for ℛ⇩1 :: "'a ⇒ 'a ⇒ bool" and ℛ⇩2 :: "'b ⇒ 'b ⇒ bool" and
    match :: "'c ⇒ 'a ⇒ 'b ⇒ bool" and order :: "'c ⇒ 'c ⇒ bool"
where
  bisim_stuck: "stuck_state ℛ⇩1 s1 ⟹ stuck_state ℛ⇩2 s2 ⟹ match i s1 s2 ⟹
    match_bisim ℛ⇩1 ℛ⇩2 match order (0, 0) s1 s2" |
  bisim_steps: "match i s1⇩0 s2⇩0 ⟹ ℛ⇩1⇧*⇧* s1⇩0 s1 ⟹ (ℛ⇩1 ^^ Suc m) s1 s1' ⟹
    ℛ⇩2⇧*⇧* s2⇩0 s2 ⟹ (ℛ⇩2 ^^ Suc n) s2 s2' ⟹ match i' s1' s2' ⟹
    match_bisim ℛ⇩1 ℛ⇩2 match order (m, n) s1 s2"
theorem lift_strong_simulation_to_bisimulation:
  fixes
    step1 :: "'s1 ⇒ 's1 ⇒ bool" and
    step2 :: "'s2 ⇒ 's2 ⇒ bool" and
    match :: "'i ⇒ 's1 ⇒ 's2 ⇒ bool" and
    order :: "'i ⇒ 'i ⇒ bool"
  assumes
    matching_states_agree_on_stuck:
      "∀i s1 s2. match i s1 s2 ⟶ stuck_state step1 s1 ⟷ stuck_state step2 s2" and
    well_founded_order: "wfp order" and
    sim: "simulation step1 step2 match order"
  obtains
    MATCH :: "nat × nat ⇒ 's1 ⇒ 's2 ⇒ bool" and
    ORDER :: "nat × nat ⇒ nat × nat ⇒ bool"
  where
    "⋀i s1 s2. match i s1 s2 ⟹ (∃j. MATCH j s1 s2)"
    "⋀j s1 s2. MATCH j s1 s2 ⟹
      (∃i. stuck_state step1 s1 ∧ stuck_state step2 s2 ∧ match i s1 s2) ∨
      (∃i s1' s2'. step1⇧+⇧+ s1 s1' ∧ step2⇧+⇧+ s2 s2' ∧ match i s1' s2')" and
    "wfp ORDER" and
    "right_unique step1 ⟹ simulation step1 step2 (λi s1 s2. MATCH i s1 s2) ORDER" and
    "right_unique step2 ⟹ simulation step2 step1 (λi s2 s1. MATCH i s1 s2) ORDER"
proof -
  define MATCH :: "nat × nat ⇒ 's1 ⇒ 's2 ⇒ bool" where
    "MATCH = match_bisim step1 step2 match order"
  define ORDER :: "nat × nat ⇒ nat × nat ⇒ bool" where
    "ORDER = lex_prodp ((<) :: nat ⇒ nat ⇒ bool) ((<) :: nat ⇒ nat ⇒ bool)"
  have MATCH_if_match: "⋀i s1 s2. match i s1 s2 ⟹ ∃j. MATCH j s1 s2"
  proof -
    fix i s1 s2
    assume "match i s1 s2"
    have "stuck_state step1 s1 ⟷ stuck_state step2 s2"
      using ‹match i s1 s2› matching_states_agree_on_stuck by metis
    hence "(stuck_state step1 s1 ∧ stuck_state step2 s2) ∨ (∃s1' s2'. step1 s1 s1' ∧ step2 s2 s2')"
      by (metis stuck_state_def)
    thus "∃j. MATCH j s1 s2"
    proof (elim disjE conjE exE)
      show "stuck_state step1 s1 ⟹ stuck_state step2 s2 ⟹ ∃j. MATCH j s1 s2"
        by (metis MATCH_def ‹match i s1 s2› bisim_stuck)
    next
      fix s1' s2'
      assume "step1 s1 s1'" and "step2 s2 s2'"
      obtain m n s1'' s2'' i' where
        "(step1 ^^ m) s1' s1''" and
        "(step2 ^^ Suc n) s2 s2''" and
        "match i' s1'' s2''"
        using finite_progress[OF assms ‹match i s1 s2› ‹step1 s1 s1'›] by metis
      show "∃j. MATCH j s1 s2"
      proof (intro exI)
        show "MATCH (m, n) s1 s2"
          unfolding MATCH_def
        proof (rule bisim_steps)
          show "match i s1 s2"
            using ‹match i s1 s2› .
        next
          show "step1⇧*⇧* s1 s1"
            by simp
        next
          show "(step1 ^^ Suc m) s1 s1''"
            using ‹step1 s1 s1'› ‹(step1 ^^ m) s1' s1''› by (metis relpowp_Suc_I2)
        next
          show "step2⇧*⇧* s2 s2"
            by simp
        next
          show "(step2 ^^ Suc n) s2 s2''"
            using ‹(step2 ^^ Suc n) s2 s2''› .
        next
          show "match i' s1'' s2''"
            using ‹match i' s1'' s2''› .
        qed
      qed
    qed
  qed
  show thesis
  proof (rule that)
    show "⋀i s1 s2. match i s1 s2 ⟹ ∃j. MATCH j s1 s2"
      using MATCH_if_match .
  next
    fix j :: "nat × nat" and s1 :: 's1 and s2 :: 's2
    assume "MATCH j s1 s2"
    thus "(∃i. stuck_state step1 s1 ∧ stuck_state step2 s2 ∧ match i s1 s2) ∨
      (∃i s1' s2'. step1⇧+⇧+ s1 s1' ∧ step2⇧+⇧+ s2 s2' ∧ match i s1' s2')"
      unfolding MATCH_def
    proof (cases step1 step2 match order j s1 s2 rule: match_bisim.cases)
      case (bisim_stuck i)
      thus ?thesis
        by blast
    next
      case (bisim_steps i s1⇩0 s2⇩0 m s1' n s2' i')
      hence "∃i s1' s2'. step1⇧+⇧+ s1 s1' ∧ step2⇧+⇧+ s2 s2' ∧ match i s1' s2'"
        by (metis tranclp_power zero_less_Suc)
      thus ?thesis ..
    qed
  next
    show "wfp ORDER"
      unfolding ORDER_def
      using lex_prodp_wfP wfp_on_less well_founded_order by metis
  next
    assume "right_unique step1"
    show "simulation step1 step2 MATCH ORDER"
      unfolding simulation_def
    proof (intro allI impI)
      fix j :: "nat × nat" and s1 s1' :: 's1 and s2 :: 's2
      assume "MATCH j s1 s2" and "step1 s1 s1'"
      hence "match_bisim step1 step2 match order j s1 s2"
        unfolding MATCH_def by metis
      thus "(∃s2' j'. step2⇧+⇧+ s2 s2' ∧ MATCH j' s1' s2') ∨ (∃j'. MATCH j' s1' s2 ∧ ORDER j' j)"
      proof (cases step1 step2 match order j s1 s2 rule: match_bisim.cases)
        case (bisim_stuck i)
        hence False
          using ‹step1 s1 s1'› stuck_state_def by metis
        thus ?thesis ..
      next
        case (bisim_steps i s1⇩0 s2⇩0 m s1'' n s2' i')
        have "(step1 ^^ m) s1' s1''"
          using ‹step1 s1 s1'› ‹(step1 ^^ Suc m) s1 s1''› ‹right_unique step1›
          by (metis relpowp_Suc_D2 right_uniqueD)
        show ?thesis
        proof (cases m)
          case 0
          hence "s1'' = s1'"
            using ‹(step1 ^^ m) s1' s1''› by simp
          have "step2⇧+⇧+ s2 s2'"
            using ‹(step2 ^^ Suc n) s2 s2'› by (metis tranclp_power zero_less_Suc)
          moreover have "∃j'. MATCH j' s1' s2'"
            using ‹match i' s1'' s2'› ‹s1'' = s1'› MATCH_if_match by metis
          ultimately show ?thesis
            by metis
        next
          case (Suc m')
          define j' where
            "j' = (m', n)"
          have "MATCH j' s1' s2"
            unfolding MATCH_def j'_def
          proof (rule match_bisim.bisim_steps)
            show "match i s1⇩0 s2⇩0"
              using ‹match i s1⇩0 s2⇩0› .
          next
            show "step1⇧*⇧* s1⇩0 s1'"
              using ‹step1⇧*⇧* s1⇩0 s1› ‹step1 s1 s1'› by auto
          next
            show "(step1 ^^ Suc m') s1' s1''"
              using ‹(step1 ^^ m) s1' s1''› ‹m = Suc m'› by argo
          next
            show "step2⇧*⇧* s2⇩0 s2"
              using ‹step2⇧*⇧* s2⇩0 s2› .
          next
            show "(step2 ^^ Suc n) s2 s2'"
              using ‹(step2 ^^ Suc n) s2 s2'› .
          next
            show "match i' s1'' s2'"
              using ‹match i' s1'' s2'› .
          qed
          moreover have "ORDER j' j"
            unfolding ORDER_def ‹j' = (m', n)› ‹j = (m, n)› ‹m = Suc m'›
            by (simp add: lex_prodp_def)
          ultimately show ?thesis
            by metis
        qed
      qed
    qed
  next
    assume "right_unique step2"
    show "simulation step2 step1 (λi s2 s1. MATCH i s1 s2) ORDER"
      unfolding simulation_def
    proof (intro allI impI)
      fix j :: "nat × nat" and s1 :: 's1 and s2 s2' :: 's2
      assume "MATCH j s1 s2" and "step2 s2 s2'"
      hence "match_bisim step1 step2 match order j s1 s2"
        unfolding MATCH_def by metis
      thus "(∃s1' j'. step1⇧+⇧+ s1 s1' ∧ MATCH j' s1' s2') ∨ (∃j'. MATCH j' s1 s2' ∧ ORDER j' j)"
      proof (cases step1 step2 match order j s1 s2 rule: match_bisim.cases)
        case (bisim_stuck i)
        hence "stuck_state step2 s2"
          by argo
        hence False
          using ‹step2 s2 s2'› stuck_state_def by metis
        thus ?thesis ..
      next
        case (bisim_steps i s1⇩0 s2⇩0 m s1' n s2'' i')
        show ?thesis
        proof (cases n)
          case 0
          hence "s2'' = s2'"
            using ‹step2 s2 s2'› ‹(step2 ^^ Suc n) s2 s2''› ‹right_unique step2›
            by (metis One_nat_def relpowp_1 right_uniqueD)
          have "step1⇧+⇧+ s1 s1'"
            using ‹(step1 ^^ Suc m) s1 s1'›
            by (metis less_Suc_eq_0_disj tranclp_power)
          moreover have "∃j'. MATCH j' s1' s2'"
            using ‹match i' s1' s2''› ‹s2'' = s2'› MATCH_if_match by metis
          ultimately show ?thesis
            by metis
        next
          case (Suc n')
          define j' where
            "j' = (m, n')"
          have "MATCH j' s1 s2'"
            unfolding MATCH_def j'_def
          proof (rule match_bisim.bisim_steps)
            show "match i s1⇩0 s2⇩0"
              using ‹match i s1⇩0 s2⇩0› .
          next
            show "step1⇧*⇧* s1⇩0 s1"
              using ‹step1⇧*⇧* s1⇩0 s1› .
          next
            show "(step1 ^^ Suc m) s1 s1'"
              using ‹(step1 ^^ Suc m) s1 s1'› .
          next
            show "step2⇧*⇧* s2⇩0 s2'"
              using ‹step2⇧*⇧* s2⇩0 s2› ‹step2 s2 s2'› by auto
          next
            show "(step2 ^^ Suc n') s2' s2''"
              using ‹step2 s2 s2'› ‹(step2 ^^ Suc n) s2 s2''› ‹right_unique step2›
              by (metis Suc relpowp_Suc_D2 right_uniqueD)
          next
            show "match i' s1' s2''"
              using ‹match i' s1' s2''› .
          qed
          moreover have "ORDER j' j"
            unfolding ORDER_def ‹j' = (m, n')› ‹j = (m, n)› ‹n = Suc n'›
            by (simp add: lex_prodp_def)
          ultimately show ?thesis
            by metis
        qed
      qed
    qed
  qed
qed
end
definition safe_state where
  "safe_state ℛ ℱ s ⟷ (∀s'. ℛ⇧*⇧* s s' ⟶ stuck_state ℛ s' ⟶ ℱ s')"
lemma step_preserves_safe_state:
  "ℛ s s' ⟹ safe_state ℛ ℱ s ⟹ safe_state ℛ ℱ s'"
  by (simp add: safe_state_def converse_rtranclp_into_rtranclp)
lemma rtranclp_step_preserves_safe_state:
  "ℛ⇧*⇧* s s' ⟹ safe_state ℛ ℱ s ⟹ safe_state ℛ ℱ s'"
  by (simp add: rtranclp_induct step_preserves_safe_state)
lemma tranclp_step_preserves_safe_state:
  "ℛ⇧+⇧+ s s' ⟹ safe_state ℛ ℱ s ⟹ safe_state ℛ ℱ s'"
  by (simp add: step_preserves_safe_state tranclp_induct)
lemma safe_state_before_step_if_safe_state_after:
  assumes "right_unique ℛ"
  shows "ℛ s s' ⟹ safe_state ℛ ℱ s' ⟹ safe_state ℛ ℱ s"
  by (smt (verit, ccfv_threshold) assms converse_rtranclpE right_uniqueD safe_state_def
      stuck_state_def)
lemma safe_state_before_rtranclp_step_if_safe_state_after:
  assumes "right_unique ℛ"
  shows "ℛ⇧*⇧* s s' ⟹ safe_state ℛ ℱ s' ⟹ safe_state ℛ ℱ s"
  by (smt (verit, best) assms converse_rtranclp_induct safe_state_before_step_if_safe_state_after)
lemma safe_state_before_tranclp_step_if_safe_state_after:
  assumes "right_unique ℛ"
  shows "ℛ⇧+⇧+ s s' ⟹ safe_state ℛ ℱ s' ⟹ safe_state ℛ ℱ s"
  by (meson assms safe_state_before_rtranclp_step_if_safe_state_after tranclp_into_rtranclp)
lemma safe_state_if_all_states_safe:
  fixes ℛ ℱ s
  assumes "⋀s. ℱ s ∨ (∃s'. ℛ s s')"
  shows "safe_state ℛ ℱ s"
  using assms by (metis safe_state_def stuck_state_def)
lemma
  fixes ℛ ℱ s
  shows "safe_state ℛ ℱ s ⟹ ℱ s ∨ (∃s'. ℛ s s')"
  by (metis rtranclp.rtrancl_refl safe_state_def stuck_state_def)
lemma matching_states_agree_on_stuck_if_they_agree_on_final:
  assumes
    final1_stuck: "∀s1. final1 s1 ⟶ (∄s1'. step1 s1 s1')" and
    final2_stuck: "∀s2. final2 s2 ⟶ (∄s2'. step2 s2 s2')" and
    matching_states_agree_on_final: "∀i s1 s2. match i s1 s2 ⟶ final1 s1 ⟷ final2 s2" and
    matching_states_are_safe:
      "∀i s1 s2. match i s1 s2 ⟶ safe_state step1 final1 s1 ∧ safe_state step2 final2 s2"
  shows "∀i s1 s2. match i s1 s2 ⟶ stuck_state step1 s1 ⟷ stuck_state step2 s2"
    using assms by (metis rtranclp.rtrancl_refl safe_state_def stuck_state_def)
locale wellbehaved_transition_system =
  fixes ℛ :: "'s ⇒ 's ⇒ bool" and ℱ :: "'s ⇒ bool" and 𝒮 :: "'s ⇒ bool"
  assumes
    determ: "right_unique ℛ" and
    stuck_if_final: "⋀x. ℱ x ⟹ stuck_state ℛ x" and
    safe_if_invar: "⋀x. 𝒮 x ⟹ safe_state ℛ ℱ x"
lemma (in wellbehaved_transition_system) final_iff_stuck_if_invar:
  fixes x
  assumes "𝒮 x"
  shows "ℱ x ⟷ stuck_state ℛ x"
proof (intro iffI)
  assume "ℱ x"
  thus "stuck_state ℛ x"
    by (fact stuck_if_final)
next
  assume "stuck_state ℛ x"
  thus "ℱ x"
    by (metis assms rtranclp.rtrancl_refl safe_if_invar safe_state_def stuck_state_def)
qed
lemma wellbehaved_transition_systems_agree_on_final_iff_agree_on_stuck:
  fixes
    ℛ⇩a :: "'a ⇒ 'a ⇒ bool" and ℱ⇩a :: "'a ⇒ bool" and
    ℛ⇩b :: "'b ⇒ 'b ⇒ bool" and ℱ⇩b :: "'b ⇒ bool" and
    ℳ :: "'i ⇒ 'a ⇒ 'b ⇒ bool"
  assumes
    "wellbehaved_transition_system ℛ⇩a ℱ⇩a (λa. ∃i b. ℳ i a b)" and
    "wellbehaved_transition_system ℛ⇩b ℱ⇩b (λb. ∃i a. ℳ i a b)" and
    "ℳ i a b"
  shows "(ℱ⇩a a ⟷ ℱ⇩b b) ⟷ (stuck_state ℛ⇩a a ⟷ stuck_state ℛ⇩b b)"
  using assms
  by (metis (mono_tags, lifting) wellbehaved_transition_system.final_iff_stuck_if_invar)
corollary lift_strong_simulation_to_bisimulation':
  fixes
    step1 :: "'s1 ⇒ 's1 ⇒ bool" and
    step2 :: "'s2 ⇒ 's2 ⇒ bool" and
    match :: "'i ⇒ 's1 ⇒ 's2 ⇒ bool" and
    order :: "'i ⇒ 'i ⇒ bool"
  assumes
    "right_unique step1" and
    "right_unique step2" and
    final1_stuck: "∀s1. final1 s1 ⟶ (∄s1'. step1 s1 s1')" and
    final2_stuck: "∀s2. final2 s2 ⟶ (∄s2'. step2 s2 s2')" and
    matching_states_agree_on_final:
      "∀i s1 s2. match i s1 s2 ⟶ final1 s1 ⟷ final2 s2" and
    matching_states_are_safe:
      "∀i s1 s2. match i s1 s2 ⟶ safe_state step1 final1 s1 ∧ safe_state step2 final2 s2" and
    order_well_founded: "wfp order" and
    sim: "simulation step1 step2 match order"
  obtains
    MATCH :: "nat × nat ⇒ 's1 ⇒ 's2 ⇒ bool" and
    ORDER :: "nat × nat ⇒ nat × nat ⇒ bool"
  where
    "⋀i s1 s2. match i s1 s2 ⟹ (∃j. MATCH j s1 s2)"
    "⋀j s1 s2. MATCH j s1 s2 ⟹ final1 s1 ⟷ final2 s2" and
    "⋀j s1 s2. MATCH j s1 s2 ⟹ stuck_state step1 s1 ⟷ stuck_state step2 s2" and
    "⋀j s1 s2. MATCH j s1 s2 ⟹ safe_state step1 final1 s1 ∧ safe_state step2 final2 s2" and
    "wfp ORDER" and
    "simulation step1 step2 (λi s1 s2. MATCH i s1 s2) ORDER" and
    "simulation step2 step1 (λi s2 s1. MATCH i s1 s2) ORDER"
proof -
  have matching_states_agree_on_stuck:
    "∀i s1 s2. match i s1 s2 ⟶ stuck_state step1 s1 ⟷ stuck_state step2 s2"
    using matching_states_agree_on_stuck_if_they_agree_on_final[OF final1_stuck final2_stuck
        matching_states_agree_on_final matching_states_are_safe] .
  obtain
    MATCH :: "nat × nat ⇒ 's1 ⇒ 's2 ⇒ bool" and
    ORDER :: "nat × nat ⇒ nat × nat ⇒ bool"
  where
    MATCH_if_match: "⋀i s1 s2. match i s1 s2 ⟹ ∃j. MATCH j s1 s2" and
    MATCH_spec: "⋀j s1 s2. MATCH j s1 s2 ⟹
      (∃i. stuck_state step1 s1 ∧ stuck_state step2 s2 ∧ match i s1 s2) ∨
      (∃i s1' s2'. step1⇧+⇧+ s1 s1' ∧ step2⇧+⇧+ s2 s2' ∧ match i s1' s2')" and
    "wfp ORDER" and
    "simulation step1 step2 MATCH ORDER" and
    "simulation step2 step1 (λi s2 s1. MATCH i s1 s2) ORDER"
    using ‹right_unique step1› ‹right_unique step2›
    using lift_strong_simulation_to_bisimulation[
        OF matching_states_agree_on_stuck
        order_well_founded sim]
    by (smt (verit))
  have wellbehaved1: "wellbehaved_transition_system step1 final1 (λa. ∃i b. MATCH i a b)"
  proof unfold_locales
    show "right_unique step1"
      using ‹right_unique step1› .
  next
    show "⋀x. final1 x ⟹ stuck_state step1 x"
      unfolding stuck_state_def
      using final1_stuck by metis
  next
    show "⋀x. ∃i b. MATCH i x b ⟹ safe_state step1 final1 x"
      by (meson MATCH_spec assms(1) matching_states_are_safe safe_state_before_tranclp_step_if_safe_state_after)
  qed
  have wellbehaved2: "wellbehaved_transition_system step2 final2 (λb. ∃i a. MATCH i a b)"
  proof unfold_locales
    show "right_unique step2"
      using ‹right_unique step2› .
  next
    show "⋀x. final2 x ⟹ stuck_state step2 x"
      unfolding stuck_state_def
      using final2_stuck by metis
  next
    show "⋀x. ∃i a. MATCH i a x ⟹ safe_state step2 final2 x"
      by (meson MATCH_spec assms(2) matching_states_are_safe
          safe_state_before_tranclp_step_if_safe_state_after)
  qed
  show thesis
  proof (rule that)
    show "⋀i s1 s2. match i s1 s2 ⟹ ∃j. MATCH j s1 s2"
      using MATCH_if_match .
  next
    show "⋀j s1 s2. MATCH j s1 s2 ⟹ stuck_state step1 s1 ⟷ stuck_state step2 s2"
      using MATCH_spec
      by (metis stuck_state_def tranclpD)
    then show "⋀j s1 s2. MATCH j s1 s2 ⟹ final1 s1 ⟷ final2 s2"
      using wellbehaved_transition_systems_agree_on_final_iff_agree_on_stuck[
          OF wellbehaved1 wellbehaved2]
      by blast
  next
    fix j s1 s2
    assume "MATCH j s1 s2"
    then show "safe_state step1 final1 s1 ∧ safe_state step2 final2 s2"
      using wellbehaved_transition_system.safe_if_invar[OF wellbehaved1, of s1]
      using wellbehaved_transition_system.safe_if_invar[OF wellbehaved2, of s2]
      by blast
  next
    show "wfp ORDER"
      using ‹wfp ORDER› .
  next
    show "simulation step1 step2 (λi s1 s2. MATCH i s1 s2) ORDER"
      using ‹simulation step1 step2 (λi s1 s2. MATCH i s1 s2) ORDER› .
  next
    show "simulation step2 step1 (λi s2 s1. MATCH i s1 s2) ORDER"
      using ‹simulation step2 step1 (λi s2 s1. MATCH i s1 s2) ORDER› .
  qed
qed
end