Theory Observing_Quorums
section ‹The Observing Quorums Model›
theory Observing_Quorums
imports Same_Vote
begin
subsection ‹Model definition›
text ‹The state adds one field to the Voting model state:›
record obsv_state = v_state +
  obs :: "round ⇒ (process, val) map"
text ‹For the observation mechanism to work, we need monotonicity of quorums.›
context mono_quorum begin
definition obs_safe 
  where
  "obs_safe r s v ≡ (∀r' < r. ∃p. obs s r' p ∈ {None, Some v})"
definition obsv_round 
  :: "round ⇒ process set ⇒ val ⇒ (process, val)map ⇒ process set ⇒ (obsv_state × obsv_state) set" 
  where
  "obsv_round r S v r_decisions Os = {(s, s').
     
     r = next_round s
     ∧ (S ≠ {} ⟶ obs_safe r s v)
     ∧ d_guard r_decisions (const_map v S)
     ∧ (S ∈ Quorum ⟶ Os = UNIV)
     ∧ (Os ≠ {} ⟶ S ≠ {})
     ∧ 
     s' = s⦇ 
       next_round := Suc r
       , votes := (votes s)(r := const_map v S)
       , decisions := decisions s ++ r_decisions
       , obs := (obs s)(r := const_map v Os)
     ⦈
  }"
definition obsv_trans :: "(obsv_state × obsv_state) set" where
  "obsv_trans = (⋃r S v d_f Os. obsv_round r S v d_f Os) ∪ Id"
definition obsv_init :: "obsv_state set" where
  "obsv_init = { ⦇ next_round = 0, votes = λr a. None, decisions = Map.empty, obs = λr a. None ⦈ }"  
definition obsv_TS :: "obsv_state TS" where
  "obsv_TS = ⦇ init = obsv_init, trans = obsv_trans ⦈"
lemmas obsv_TS_defs = obsv_TS_def obsv_init_def obsv_trans_def
subsection ‹Invariants›
definition OV_inv1 where
  "OV_inv1 = {s. ∀r Q v. quorum_for Q v (votes s r) ⟶
    (∀Q' ∈ Quorum. quorum_for Q' v (obs s r))}"
lemmas OV_inv1I = OV_inv1_def [THEN setc_def_to_intro, rule_format]
lemmas OV_inv1E [elim] = OV_inv1_def [THEN setc_def_to_elim, rule_format]
lemmas OV_inv1D = OV_inv1_def [THEN setc_def_to_dest, rule_format]
 
subsubsection ‹Proofs of invariants›
  
lemma OV_inv1_obsv_round: 
  "{OV_inv1} obsv_round r S v d_f Ob {> OV_inv1}"
proof(clarsimp simp add: PO_hoare_defs intro!: OV_inv1I)
  fix v' s s' Q Q' r'
  assume 
    Q: "quorum_for Q v' (votes s' r')"  
    and inv: "s ∈ OV_inv1"
    and step: "(s, s') ∈ obsv_round r S v d_f Ob"
    and quorum: "Q' ∈ Quorum"
  from Q inv[THEN OV_inv1D] step quorum
  show "quorum_for Q' v' (obs s' r')"
  proof(cases "r'=r")
    case True
    with step and Q have "S ∈ Quorum"
      by(fastforce simp add: obsv_round_def obs_safe_def quorum_for_def const_map_is_Some
        ball_conj_distrib subset_eq[symmetric] intro: mono_quorum[where Q'=S])      
    thus ?thesis using step inv[THEN OV_inv1D] Q quorum
      by(clarsimp simp add: obsv_round_def obs_safe_def quorum_for_def const_map_is_Some
        ball_conj_distrib subset_eq[symmetric] dest!: quorum_non_empty)
  qed(clarsimp simp add: obsv_round_def obs_safe_def quorum_for_def)
qed
lemma OV_inv1_inductive:
  "init obsv_TS ⊆ OV_inv1" 
  "{OV_inv1} trans obsv_TS {> OV_inv1}" 
  apply (simp add: obsv_TS_defs OV_inv1_def) 
   apply (auto simp add: obsv_TS_defs OV_inv1_obsv_round quorum_for_def dest: empty_not_quorum)
  done
lemma quorum_for_const_map:
  "(quorum_for Q w (const_map v S)) = (Q ∈ Quorum ∧ Q ⊆ S ∧ w = v)"
  by(auto simp add: quorum_for_def const_map_is_Some dest: quorum_non_empty)
subsection ‹Refinement›
definition obsv_ref_rel where 
  "obsv_ref_rel ≡ {(sa, sc).
    sa = v_state.truncate sc
  }"
lemma obsv_round_refines:
  "{obsv_ref_rel ∩ UNIV × OV_inv1} sv_round r S v dec_f, obsv_round r S v dec_f Ob {> obsv_ref_rel}"
  apply(clarsimp simp add: PO_rhoare_defs sv_round_def obsv_round_def safe_def obsv_ref_rel_def 
    v_state.truncate_def obs_safe_def quorum_for_def OV_inv1_def)
  by (metis UNIV_I UNIV_quorum  option.distinct(1) option.inject)
lemma Observable_Refines:
  "PO_refines (obsv_ref_rel ∩ UNIV × OV_inv1) sv_TS obsv_TS"
proof(rule refine_using_invariants)
  show "init obsv_TS ⊆ obsv_ref_rel `` init sv_TS"
  by(auto simp add: PO_refines_def sv_TS_defs  obsv_TS_defs  obsv_ref_rel_def 
    v_state.truncate_def)
next
  show "{obsv_ref_rel ∩ UNIV × OV_inv1} trans sv_TS, trans obsv_TS {> obsv_ref_rel}"
    by(auto simp add: PO_refines_def sv_TS_defs  obsv_TS_defs intro!: 
      obsv_round_refines relhoare_refl)
qed(auto intro: OV_inv1_inductive del: subsetI)
subsection ‹Additional invariants›
definition OV_inv2 where
  "OV_inv2 = {s. ∀r ≥ next_round s. obs s r = Map.empty }"
lemmas OV_inv2I = OV_inv2_def [THEN setc_def_to_intro, rule_format]
lemmas OV_inv2E [elim] = OV_inv2_def [THEN setc_def_to_elim, rule_format]
lemmas OV_inv2D = OV_inv2_def [THEN setc_def_to_dest, rule_format]
definition OV_inv3 where
  "OV_inv3 = {s. ∀r p v. obs s r p = Some v ⟶
    obs_safe r s v}"
lemmas OV_inv3I = OV_inv3_def [THEN setc_def_to_intro, rule_format]
lemmas OV_inv3E [elim] = OV_inv3_def [THEN setc_def_to_elim, rule_format]
lemmas OV_inv3D = OV_inv3_def [THEN setc_def_to_dest, rule_format]
definition OV_inv4 where
  "OV_inv4 = {s. ∀r p q v w. obs s r p = Some v ∧ obs s r q = Some w ⟶
    w = v}"
lemmas OV_inv4I = OV_inv4_def [THEN setc_def_to_intro, rule_format]
lemmas OV_inv4E [elim] = OV_inv4_def [THEN setc_def_to_elim, rule_format]
lemmas OV_inv4D = OV_inv4_def [THEN setc_def_to_dest, rule_format]
subsubsection ‹Proofs of additional invariants›
lemma OV_inv2_inductive:
  "init obsv_TS ⊆ OV_inv2"
  "{OV_inv2} trans obsv_TS {> OV_inv2}" 
  by(auto simp add: PO_hoare_defs OV_inv2_def obsv_TS_defs obsv_round_def const_map_is_Some)
lemma SVinv3_inductive:
  "init obsv_TS ⊆ SV_inv3"
  "{SV_inv3} trans obsv_TS {> SV_inv3}" 
  by(auto simp add: PO_hoare_defs SV_inv3_def obsv_TS_defs obsv_round_def const_map_is_Some)
lemma OV_inv3_obsv_round: 
  "{OV_inv3 ∩ OV_inv2} obsv_round r S v D Ob {> OV_inv3}"
proof(clarsimp simp add: PO_hoare_defs intro!: OV_inv3I)
  fix s s' r_w p w
  assume Assms:
    "obs s' r_w p = Some w" 
    "s ∈ OV_inv3"
    "(s, s') ∈ obsv_round r S v D Ob"
    "s ∈ OV_inv2"
  hence "s' ∈ OV_inv2"
    by(force simp add: obsv_TS_defs intro: OV_inv2_inductive(2)[THEN hoareD, OF ‹s ∈ OV_inv2›])
  hence "r_w ≤ next_round s'" using Assms
    by(auto simp add: OV_inv2_def intro!: leI)
  hence r_w_le: "r_w ≤ next_round s" using Assms
    by(auto simp add: obsv_round_def le_Suc_eq)
  show "obs_safe r_w s' w"
  proof(cases "r_w = next_round s")
    case True
    thus ?thesis using Assms
      by(auto simp add: obsv_round_def const_map_is_Some obs_safe_def)
  next
    case False
    hence "r_w < next_round s" using r_w_le
      by(metis less_le)
    moreover have "∀r'. r' ≠ next_round s ⟶ obs s' r' = obs s r'" using Assms(3)
      by(auto simp add: obsv_round_def)
    ultimately have 
      "∀r' ≤ r_w. obs s' r' = obs s r'"
      by(auto)
    thus ?thesis using Assms
      by(auto simp add: OV_inv3_def obs_safe_def)
  qed
qed
lemma OV_inv3_inductive:
  "init obsv_TS ⊆ OV_inv3"
  "{OV_inv3 ∩ OV_inv2} trans obsv_TS {> OV_inv3}" 
  apply(auto simp add: obsv_TS_def obsv_trans_def intro: OV_inv3_obsv_round)
  apply(auto simp add: obsv_init_def OV_inv3_def)
  done
lemma OV_inv4_inductive:
  "init obsv_TS ⊆ OV_inv4"
  "{OV_inv4} trans obsv_TS {> OV_inv4}" 
  by(auto simp add: PO_hoare_defs OV_inv4_def obsv_TS_defs obsv_round_def const_map_is_Some)
end
end