Theory Sem_Equiv

section "Constant Folding"

theory Sem_Equiv
imports Big_Step
begin

subsection "Semantic Equivalence up to a Condition"

type_synonym assn = "state  bool"

definition
  equiv_up_to :: "assn  com  com  bool" ("_  _  _" [50,0,10] 50)
where
  "(P  c  c') = (s s'. P s  (c,s)  s'  (c',s)  s')"

definition
  bequiv_up_to :: "assn  bexp  bexp  bool" ("_  _ <∼> _" [50,0,10] 50)
where
  "(P  b <∼> b') = (s. P s  bval b s = bval b' s)"

lemma equiv_up_to_True:
  "((λ_. True)  c  c') = (c  c')"
  by (simp add: equiv_def equiv_up_to_def)

lemma equiv_up_to_weaken:
  "P  c  c'  (s. P' s  P s)  P'  c  c'"
  by (simp add: equiv_up_to_def)

lemma equiv_up_toI:
  "(s s'. P s  (c, s)  s' = (c', s)  s')  P  c  c'"
  by (unfold equiv_up_to_def) blast

lemma equiv_up_toD1:
  "P  c  c'  (c, s)  s'  P s  (c', s)  s'"
  by (unfold equiv_up_to_def) blast

lemma equiv_up_toD2:
  "P  c  c'  (c', s)  s'  P s  (c, s)  s'"
  by (unfold equiv_up_to_def) blast


lemma equiv_up_to_refl [simp, intro!]:
  "P  c  c"
  by (auto simp: equiv_up_to_def)

lemma equiv_up_to_sym:
  "(P  c  c') = (P  c'  c)"
  by (auto simp: equiv_up_to_def)

lemma equiv_up_to_trans:
  "P  c  c'  P  c'  c''  P  c  c''"
  by (auto simp: equiv_up_to_def)


lemma bequiv_up_to_refl [simp, intro!]:
  "P  b <∼> b"
  by (auto simp: bequiv_up_to_def)

lemma bequiv_up_to_sym:
  "(P  b <∼> b') = (P  b' <∼> b)"
  by (auto simp: bequiv_up_to_def)

lemma bequiv_up_to_trans:
  "P  b <∼> b'  P  b' <∼> b''  P  b <∼> b''"
  by (auto simp: bequiv_up_to_def)

lemma bequiv_up_to_subst:
  "P  b <∼> b'  P s  bval b s = bval b' s"
  by (simp add: bequiv_up_to_def)


lemma equiv_up_to_seq:
  "P  c  c'  Q  d  d' 
  (s s'. (c,s)  s'  P s  Q s') 
  P  (c;; d)  (c';; d')"
  by (clarsimp simp: equiv_up_to_def) blast

lemma equiv_up_to_while_lemma_weak:
  shows "(d,s)  s' 
         P  b <∼> b' 
         P  c  c' 
         (s s'. (c, s)  s'  P s  bval b s  P s') 
         P s 
         d = WHILE b DO c 
         (WHILE b' DO c', s)  s'"
proof (induction rule: big_step_induct)
  case (WhileTrue b s1 c s2 s3)
  hence IH: "P s2  (WHILE b' DO c', s2)  s3" by auto
  from WhileTrue.prems
  have "P  b <∼> b'" by simp
  with bval b s1 P s1
  have "bval b' s1" by (simp add: bequiv_up_to_def)
  moreover
  from WhileTrue.prems
  have "P  c  c'" by simp
  with bval b s1 P s1 (c, s1)  s2
  have "(c', s1)  s2" by (simp add: equiv_up_to_def)
  moreover
  from WhileTrue.prems
  have "s s'. (c,s)  s'  P s  bval b s  P s'" by simp
  with P s1 bval b s1 (c, s1)  s2
  have "P s2" by simp
  hence "(WHILE b' DO c', s2)  s3" by (rule IH)
  ultimately
  show ?case by blast
next
  case WhileFalse
  thus ?case by (auto simp: bequiv_up_to_def)
qed (fastforce simp: equiv_up_to_def bequiv_up_to_def)+

lemma equiv_up_to_while_weak:
  assumes b: "P  b <∼> b'"
  assumes c: "P  c  c'"
  assumes I: "s s'. (c, s)  s'  P s  bval b s  P s'"
  shows "P  WHILE b DO c  WHILE b' DO c'"
proof -
  from b have b': "P  b' <∼> b" by (simp add: bequiv_up_to_sym)

  from c b have c': "P  c'  c" by (simp add: equiv_up_to_sym)

  from I
  have I': "s s'. (c', s)  s'  P s  bval b' s  P s'"
    by (auto dest!: equiv_up_toD1 [OF c'] simp: bequiv_up_to_subst [OF b'])

  note equiv_up_to_while_lemma_weak [OF _ b c]
       equiv_up_to_while_lemma_weak [OF _ b' c']
  thus ?thesis using I I' by (auto intro!: equiv_up_toI)
qed

lemma equiv_up_to_if_weak:
  "P  b <∼> b'  P  c  c'  P  d  d' 
   P  IF b THEN c ELSE d  IF b' THEN c' ELSE d'"
  by (auto simp: bequiv_up_to_def equiv_up_to_def)

lemma equiv_up_to_if_True [intro!]:
  "(s. P s  bval b s)  P  IF b THEN c1 ELSE c2  c1"
  by (auto simp: equiv_up_to_def)

lemma equiv_up_to_if_False [intro!]:
  "(s. P s  ¬ bval b s)  P  IF b THEN c1 ELSE c2  c2"
  by (auto simp: equiv_up_to_def)

lemma equiv_up_to_while_False [intro!]:
  "(s. P s  ¬ bval b s)  P  WHILE b DO c  SKIP"
  by (auto simp: equiv_up_to_def)

lemma while_never: "(c, s)  u  c  WHILE (Bc True) DO c'"
 by (induct rule: big_step_induct) auto

lemma equiv_up_to_while_True [intro!,simp]:
  "P  WHILE Bc True DO c  WHILE Bc True DO SKIP"
  unfolding equiv_up_to_def
  by (blast dest: while_never)


end