Theory SM.Gen_Cfg_Bisim
theory Gen_Cfg_Bisim
imports Gen_Scheduler_Refine
begin
  
  
  subsection ‹Functional Relations›
  definition "build_relp α I x y ≡ y=α x ∧ I x"
  abbreviation "brp ≡ build_relp"
  lemma brp_right_unique[simp, intro!]: "right_unique (brp α I)"
    apply (rule right_uniqueI)
    unfolding build_relp_def
    by auto
  definition "the_brp_α R ≡ (λx. SOME y. R x y)"
  abbreviation (input) "the_brp_invar ≡ Domainp"
  lemma the_brp[simp]: 
    assumes "right_unique R"  
    shows "brp (the_brp_α R) (the_brp_invar R) = R"
      apply (rule sym)
      apply (intro ext)
      unfolding build_relp_def the_brp_α_def
      apply auto
      apply (metis assms right_uniqueD someI)
      by (blast intro: someI)
  lemma obtain_brp:
    assumes "right_unique R"  
    obtains α I where "R=brp α I"
    using the_brp[OF assms, THEN sym] ..
  lemma the_brp_brp[simp]: 
    "I x ⟹ the_brp_α (brp α I) x = α x"
    "the_brp_invar (brp α I) = I"
    unfolding the_brp_α_def build_relp_def[abs_def]
    by (auto)
  lemma brp_comp[simp]: "brp α1 I1 OO brp α2 I2 = brp (α2 o α1) (λx. I1 x ∧ I2 (α1 x))"
    unfolding build_relp_def[abs_def] by auto
  lemma rel_of_pred_brp[simp]: "rel_of_pred (brp α invar) = br α invar"
    unfolding build_relp_def[abs_def] build_rel_def by auto
  lemma rel_option_add_simps[simp]: 
    "rel_option R None c ⟷ c=None"
    "rel_option R d None ⟷ d=None"
    apply (cases c, auto) []
    apply (cases d, auto) []
    done
  lemma rel_option_Some_conv: 
    "rel_option R (Some v) d ⟷ (∃w. R v w ∧ d = Some w)"
    "rel_option R c (Some w) ⟷ (∃v. R v w ∧ c = Some v)"
    apply (cases d, auto)
    apply (cases c, auto)
    done
  lemma rel_mset_plus_conv:
    "rel_mset R ({#a#}+m') n ⟷ (∃b n'. n={#b#}+n' ∧ R a b ∧ rel_mset R m' n')"  
    "rel_mset R m ({#b#}+n') ⟷ (∃a m'. m={#a#}+m' ∧ R a b ∧ rel_mset R m' n')"  
    apply (auto simp: union_mset_add_mset_left)
    apply (metis msed_rel_invL)
    apply (metis rel_mset_Plus)
    apply (metis msed_rel_invR)
    apply (metis rel_mset_Plus)
    done      
  lemma rel_mset_brp: 
    "rel_mset (brp α I) = brp (image_mset α) (λm. ∀x. x:#m ⟶ I x)"
  proof (intro ext iffI)
    fix m m'
    assume "rel_mset (brp α I) m m'"
    thus "brp (image_mset α) (λm. ∀x. x:#m ⟶ I x) m m'"
      apply (induction "(brp α I)" _ _ rule: rel_mset_induct)
      apply (auto simp: build_relp_def)
      done
  next
    fix m m'
    assume "brp (image_mset α) (λm. ∀x. x ∈# m ⟶ I x) m m'"
    hence 1: "m' = image_mset α m" 
      and "∀x. x ∈# m ⟶ I x" by (auto simp: build_relp_def)
    from this(2) show "rel_mset (brp α I) m m'"
      unfolding 1
      apply (induction m)
      apply (simp add: rel_mset_Zero)
      apply simp
      apply (rule rel_mset_Plus)
      apply (simp add: build_relp_def)
      .
  qed
  locale Gen_Cfg_Bisim_Pre =
    s1: Gen_Scheduler' cstep1 en ex
  + s2: Gen_Scheduler' cstep2 en ex 
    for rel_c :: "'c ⇒ 'd ⇒ bool"
    and cstep1 :: "'c ⇒ 'a ⇒ 'c ⇒ bool"
    and cstep2 :: "'d ⇒ 'a ⇒ 'd ⇒ bool"
    and en 
    and ex :: "('ls×'gs) ⇒ 'a ⇒ ('ls×'gs)" +
    assumes csim1: "⟦cstep1 c a c'; rel_c c d ⟧ ⟹ ∃d'. rel_c c' d' ∧ cstep2 d a d'"
    assumes csim2: "⟦cstep2 d a d'; rel_c c d ⟧ ⟹ ∃c'. rel_c c' d' ∧ cstep1 c a c'"
  begin
    
    definition rel_lc :: "('c,'ls) local_config ⇒ ('d,'ls) local_config ⇒ bool"
    where "rel_lc lc ld ≡ 
      rel_c (local_config.command lc) (local_config.command ld) 
    ∧ local_config.state lc = local_config.state ld"
    definition rel_gc :: "('c,'ls,'gs)global_config ⇒ ('d,'ls,'gs)global_config ⇒ bool"
    where "rel_gc gc gd ≡ 
      rel_mset rel_lc (global_config.processes gc) (global_config.processes gd)
    ∧ global_config.state gc = global_config.state gd"
    lemma gstep_sim1: "⟦(c, c') ∈ s1.gstep; rel_gc c d⟧ ⟹ ∃d'. rel_gc c' d' ∧ (d, d') ∈ s2.gstep"
      apply (cases c, simp_all)
      apply (erule s1.gstep_succE)
      apply (auto 
        simp: rel_option_Some_conv rel_gc_def rel_lc_def
        simp: rel_mset_plus_conv 
        )
      apply (drule (1) csim1, clarsimp)
      apply (drule (3) s2.gstep_succI, force)
      done
    lemma gstep_sim2: "⟦(d, d') ∈ s2.gstep; rel_gc c d⟧ ⟹ ∃c'. rel_gc c' d' ∧ (c, c') ∈ s1.gstep"
      apply (cases d, simp_all)
      apply (erule s2.gstep_succE)
      apply (auto 
        simp: rel_option_Some_conv rel_gc_def rel_lc_def
        simp: rel_mset_plus_conv
        )
      apply (drule (1) csim2, clarsimp)
      apply (drule (1) s1.gstep_succI, simp_all, force) 
      done
    lemma left_unique_rel_lcI:
      assumes "left_unique rel_c"
      shows "left_unique rel_lc"
    proof (rule left_uniqueI)
      fix lc1 lc2 lc3
      assume "rel_lc lc1 lc2" "rel_lc lc3 lc2"
      thus "lc1=lc3"
        apply (cases lc1, cases lc2, cases lc3, simp_all)
        apply (auto simp: rel_lc_def left_uniqueD[OF assms])
        done
    qed
    lemma right_unique_rel_lcI:
      assumes "right_unique rel_c"
      shows "right_unique rel_lc"
    proof (rule right_uniqueI)
      fix lc1 lc2 lc3
      assume "rel_lc lc2 lc1" "rel_lc lc2 lc3"
      thus "lc1=lc3"
        apply (cases lc1, cases lc2, cases lc3, simp_all)
        apply (auto simp: rel_lc_def right_uniqueD[OF assms])
        done
    qed
    lemma bi_unique_rel_lcI:
      assumes "bi_unique rel_c"
      shows "bi_unique rel_lc"
      using assms 
      by (auto simp: bi_unique_alt_def right_unique_rel_lcI left_unique_rel_lcI)
    lemma left_unique_rel_gcI:
      assumes "left_unique rel_c"
      shows "left_unique rel_gc"
    proof (rule left_uniqueI)
      note A = left_unique_rel_lcI[OF assms, THEN multiset.left_unique_rel]
      fix gc1 gc2 gc3
      assume "rel_gc gc1 gc2" "rel_gc gc3 gc2"
      thus "gc1=gc3"
        apply (cases gc1, cases gc2, cases gc3, simp_all)
        apply (auto simp: rel_gc_def left_uniqueD[OF A])
        done
    qed
    lemma right_unique_rel_gcI:
      assumes "right_unique rel_c"
      shows "right_unique rel_gc"
    proof (rule right_uniqueI)
      note A = right_unique_rel_lcI[OF assms, THEN multiset.right_unique_rel]
      fix gc1 gc2 gc3
      assume "rel_gc gc1 gc2" "rel_gc gc1 gc3"
      thus "gc2=gc3"
        apply (cases gc1, cases gc2, cases gc3, simp_all)
        apply (auto simp: rel_gc_def right_uniqueD[OF A])
        done
    qed
    lemma bi_unique_rel_gcI:
      assumes "bi_unique rel_c"
      shows "bi_unique rel_gc"
      using assms 
      by (auto simp: bi_unique_alt_def right_unique_rel_gcI left_unique_rel_gcI)
  end
  locale Gen_Cfg_LBisim =
    Gen_Cfg_Bisim_Pre rel_c cstep1 cstep2 en ex
    for rel_c :: "'c ⇒ 'd ⇒ bool"
    and cstep1 :: "'c ⇒ 'a ⇒ 'c ⇒ bool"
    and init1 :: "('c,'ls,'gs)global_config set"
    and label1 :: "('c,'ls,'gs)global_config ⇒ 'l"
    and cstep2 :: "'d ⇒ 'a ⇒ 'd ⇒ bool"
    and init2 :: "('d,'ls,'gs)global_config set"
    and label2 :: "('d,'ls,'gs)global_config ⇒ 'l"
    and en 
    and ex :: "('ls×'gs) ⇒ 'a ⇒ ('ls×'gs)" +
    assumes init_sim1: "⋀a0. a0 ∈ init1 ⟹ ∃b0. b0 ∈ init2 ∧ rel_gc a0 b0"
    assumes init_sim2: "⋀b0. b0 ∈ init2 ⟹ ∃a0. a0 ∈ init1 ∧ rel_gc a0 b0"
    assumes labeling_consistent: "⋀a b. rel_gc a b ⟹ label1 a = label2 b"
  begin
    sublocale s1: Gen_Scheduler'_linit cstep1 en ex init1 label1 by this
    sublocale s2: Gen_Scheduler'_linit cstep2 en ex init2 label2 by this
    sublocale lbisimulation "rel_of_pred rel_gc" s1.system_automaton s2.system_automaton
    proof -
      interpret bisim:
        lbisimulation "rel_of_pred rel_gc" s1.system_automaton' s2.system_automaton'
        apply unfold_locales
        apply simp_all
        using init_sim1 apply force
        using gstep_sim1 apply force
        using labeling_consistent apply force
        using init_sim2 apply force
        using gstep_sim2 apply force
        using labeling_consistent apply force
        done
      interpret bisim:
        lbisimulation "rel_of_pred rel_gc" s1.system_automaton s2.system_automaton
        unfolding s1.system_automaton_alt_def s2.system_automaton_alt_def
        using bisim.lstutter_extend by this
      show "lbisimulation (rel_of_pred rel_gc) s1.system_automaton s2.system_automaton"
        by unfold_locales
    qed
  end    
end