Theory DBM_Imperative_Loops

theory DBM_Imperative_Loops
  imports 
    Refine_Imperative_HOL.IICF
begin

subsection ‹Additional proof rules for typical looping constructs›

subsubsection @{term Heap_Monad.fold_map}

lemma fold_map_ht:
  assumes "list_all (λx. <A * true> f x <λr. (Q x r) * A>t) xs"
  shows "<A * true> Heap_Monad.fold_map f xs <λrs. (list_all2 (λx r. Q x r) xs rs) * A>t"
  using assms by (induction xs; sep_auto)

lemma fold_map_ht':
  assumes "list_all (λx. <true> f x <λr. (Q x r)>t) xs"
  shows "<true> Heap_Monad.fold_map f xs <λrs. (list_all2 (λx r. Q x r) xs rs)>t"
  using assms by (induction xs; sep_auto)

lemma fold_map_ht1:
  assumes "x xi. <A * R x xi * true> f xi <λr. A * (Q x r)>t"
  shows "
  <A * list_assn R xs xsi * true>
    Heap_Monad.fold_map f xsi
  <λrs. A * (list_all2 (λx r. Q x r) xs rs)>t"
  apply (induction xs arbitrary: xsi)
   apply (sep_auto; fail)
  subgoal for x xs xsi
    by (cases xsi; sep_auto heap: assms)
  done

lemma fold_map_ht2:
  assumes "x xi. <A * R x xi * true> f xi <λr. A * R x xi * (Q x r)>t"
  shows "
  <A * list_assn R xs xsi * true>
    Heap_Monad.fold_map f xsi
  <λrs. A * list_assn R xs xsi * (list_all2 (λx r. Q x r) xs rs)>t"
  apply (induction xs arbitrary: xsi)
   apply (sep_auto; fail)
  subgoal for x xs xsi
    apply (cases xsi; sep_auto heap: assms)
     apply (rule cons_rule[rotated 2], rule frame_rule, rprems)
      apply frame_inference
     apply frame_inference
    apply sep_auto
    done
  done

lemma fold_map_ht3:
  assumes "x xi. <A * R x xi * true> f xi <λr. A * Q x r>t"
  shows "<A * list_assn R xs xsi * true> Heap_Monad.fold_map f xsi <λrs. A * list_assn Q xs rs>t"
  apply (induction xs arbitrary: xsi)
   apply (sep_auto; fail)
  subgoal for x xs xsi
    apply (cases xsi; sep_auto heap: assms)
     apply (rule Hoare_Triple.cons_pre_rule[rotated], rule frame_rule, rprems, frame_inference)
    apply sep_auto
    done
  done

subsubsection @{term imp_for'} and @{term imp_for}

lemma imp_for_rule2:
  assumes
    "emp A I i a"
    "i a. <A * I i a * true> ci a <λr. A * I i a * (r  c a)>t"
    "i a. i < j  c a  <A * I i a * true> f i a <λr. A * I (i + 1) r>t"
    "a. I j a A Q a" "i a. i < j  ¬ c a  I i a A Q a"
    "i  j"
  shows "<A * true> imp_for i j ci f a <λr. A * Q r>t"
proof -
  have
    "<A * I i a * true>
      imp_for i j ci f a
    <λr. A * (I j r A (A i'. (i' < j  ¬ c r) * I i' r))>t"
    using i  j assms(2,3)
    apply (induction "j - i" arbitrary: i a; sep_auto)
    subgoal
      apply (rule ent_star_mono, rule ent_star_mono)
        apply (rule ent_refl, rule ent_disjI1_direct, rule ent_refl)
      done
     apply rprems
    apply sep_auto
      apply (rprems)
       apply sep_auto+
    apply (rule ent_star_mono, rule ent_star_mono, rule ent_refl, rule ent_disjI2')
     apply solve_entails
     apply simp+
    done
  then show ?thesis
    apply (rule cons_rule[rotated 2])
    subgoal
      apply (subst merge_true_star[symmetric])
      apply (rule ent_frame_fwd[OF assms(1)])
       apply frame_inference+
      done
    apply (rule ent_star_mono)
     apply (rule ent_star_mono, rule ent_refl)
     apply (solve_entails eintros: assms(5) assms(4) ent_disjE)+
    done
qed

lemma imp_for_rule:
  assumes
    "emp A I i a"
    "i a. <I i a * true> ci a <λr. I i a * (r  c a)>t"
    "i a. i < j  c a  <I i a * true> f i a <λr. I (i + 1) r>t"
    "a. I j a A Q a" "i a. i < j  ¬ c a  I i a A Q a"
    "i  j"
  shows "<true> imp_for i j ci f a <λr. Q r>t"
  by (rule cons_rule[rotated 2], rule imp_for_rule2[where A = true])
     (rule assms | sep_auto heap: assms; fail)+

lemma imp_for'_rule2:
  assumes
    "emp A I i a"
    "i a. i < j  <A * I i a * true> f i a <λr. A * I (i + 1) r>t"
    "a. I j a A Q a"
    "i  j"
  shows "<A * true> imp_for' i j f a <λr. A * Q r>t"
  unfolding imp_for_imp_for'[symmetric] using assms(3,4)
  by (sep_auto heap: assms imp_for_rule2[where c = "λ_. True"])

lemma imp_for'_rule:
  assumes
    "emp A I i a"
    "i a. i < j  <I i a * true> f i a <λr. I (i + 1) r>t"
    "a. I j a A Q a"
    "i  j"
  shows "<true> imp_for' i j f a <λr. Q r>t"
  unfolding imp_for_imp_for'[symmetric] using assms(3,4)
  by (sep_auto heap: assms imp_for_rule[where c = "λ_. True"])

lemma nth_rule:
  assumes "is_pure S"
    and "b < length a"
  shows
    "<nat_assn b bi * array_assn S a ai> Array.nth ai bi
     <λr. Ax. nat_assn b bi * array_assn S a ai * S x r * true *  (x = a ! b)>"
  using sepref_fr_rules(165)[unfolded hn_refine_def hn_ctxt_def] assms by force

lemma imp_for_list_all:
  assumes
    "is_pure R" "n  length xs"
    "x xi. <A * R x xi * true> Pi xi <λr. A *  (r  P x)>t"
  shows "
  <A * array_assn R xs a * true>
    imp_for 0 n Heap_Monad.return
    (λi _. do {
      x  Array.nth a i; Pi x
    })
    True
  <λr. A *  array_assn R xs a * (r  list_all P (take n xs))>t"
  apply (rule imp_for_rule2[where I = "λi r.  (r  list_all P (take i xs))"])
       apply sep_auto
      apply sep_auto
  subgoal for i b
    using assms(2)
    apply (sep_auto heap: nth_rule)
     apply (rule cons_rule[rotated 2], rule frame_rule,
        rule nth_rule[where b = i and a = xs], rule assms)
       apply simp
      apply (simp add: pure_def)
      apply frame_inference
     apply frame_inference
    apply (sep_auto heap: assms(3) simp: pure_def take_Suc_conv_app_nth)
    done
    apply (simp add: take_Suc_conv_app_nth)
   apply simp
  unfolding list_all_iff
   apply clarsimp
   apply (metis le_less set_take_subset_set_take subsetCE)
  ..

lemma imp_for_list_ex:
  assumes
    "is_pure R" "n  length xs"
    "x xi. <A * R x xi * true> Pi xi <λr. A *  (r  P x)>t"
  shows "
  <A * array_assn R xs a * true>
    imp_for 0 n (λx. Heap_Monad.return (¬ x))
    (λi _. do {
      x  Array.nth a i; Pi x
    })
    False
  <λr. A *  array_assn R xs a * (r  list_ex P (take n xs))>t"
  apply (rule imp_for_rule2[where I = "λi r.  (r  list_ex P (take i xs))"])
       apply sep_auto
      apply sep_auto
  subgoal for i b
    using assms(2)
    apply (sep_auto heap: nth_rule)
     apply (rule cons_rule[rotated 2], rule frame_rule, rule nth_rule[of _ i xs], rule assms)
       apply simp
      apply (simp add: pure_def)
      apply frame_inference
     apply frame_inference
    apply (sep_auto heap: assms(3) simp: pure_def take_Suc_conv_app_nth)
    done
    apply (simp add: take_Suc_conv_app_nth)
   apply simp
  unfolding list_ex_iff
   apply clarsimp
   apply (metis le_less set_take_subset_set_take subsetCE)
  ..

lemma imp_for_list_all2:
  assumes
    "is_pure R" "is_pure S" "n  length xs" "n  length ys"
    "x xi y yi. <A * R x xi * S y yi * true> Pi xi yi <λr. A *  (r  P x y)>t"
  shows "
  <A * array_assn R xs a  * array_assn S ys b * true>
    imp_for 0 n Heap_Monad.return
    (λi _. do {
      x  Array.nth a i; y  Array.nth b i; Pi x y
    })
    True
  <λr. A *  array_assn R xs a  * array_assn S ys b * (r  list_all2 P (take n xs) (take n ys))>t"
  apply (rule imp_for_rule2[where I = "λi r.  (r  list_all2 P (take i xs) (take i ys))"])
       apply (sep_auto; fail)
      apply (sep_auto; fail)
  subgoal for i _
    supply [simp] = pure_def
    using assms(3,4)
    apply sep_auto
     apply (rule cons_rule[rotated 2], rule frame_rule, rule nth_rule[of _ i xs], rule assms)
       apply force
      apply (simp, frame_inference; fail)
     apply frame_inference
    apply sep_auto

     apply (rule cons_rule[rotated 2], rule frame_rule, rule nth_rule[of _ i ys], rule assms)
    unfolding pure_def
       apply force
      apply (simp, frame_inference; fail)
     apply frame_inference
    apply sep_auto

    supply [sep_heap_rules] = assms(5)
    apply sep_auto
    subgoal
      unfolding list_all2_conv_all_nth apply clarsimp
      subgoal for i'
        by (cases "i' = i") auto
      done
    subgoal
      unfolding list_all2_conv_all_nth by clarsimp
    apply frame_inference
    done
  unfolding list_all2_conv_all_nth apply auto
  done

lemma imp_for_list_all2':
  assumes
    "is_pure R" "is_pure S" "n  length xs" "n  length ys"
    "x xi y yi. <R x xi * S y yi> Pi xi yi <λr.  (r  P x y)>t"
  shows "
  <array_assn R xs a  * array_assn S ys b>
    imp_for 0 n Heap_Monad.return
    (λi _. do {
      x  Array.nth a i; y  Array.nth b i; Pi x y
    })
    True
  <λr. array_assn R xs a  * array_assn S ys b * (r  list_all2 P (take n xs) (take n ys))>t"
  by (rule cons_rule[rotated 2], rule imp_for_list_all2[where A = true, rotated 4])
     (sep_auto heap: assms intro: assms)+

end