Theory ListGA

theory ListGA
imports ListSpec
header {* \isaheader{Generic Algorithms for Sequences} *}
theory ListGA
imports "../spec/ListSpec" 
begin

subsection {* Iterators *}

subsubsection {* iteratei (by get, size) *}

locale idx_iteratei_loc = 
  list_size + list_get +
  constrains α :: "'s => 'a list"
  assumes [simp]: "!!s. invar s"
begin

  fun idx_iteratei_aux 
    :: "nat => nat => 's => ('σ=>bool) => ('a =>'σ => 'σ) => 'σ => 'σ"
  where
    "idx_iteratei_aux sz i l c f σ = (
      if i=0 ∨ ¬ c σ then σ
      else idx_iteratei_aux sz (i - 1) l c f (f (get l (sz-i)) σ)
    )"

  declare idx_iteratei_aux.simps[simp del]

  lemma idx_iteratei_aux_simps[simp]:
    "i=0 ==> idx_iteratei_aux sz i l c f σ = σ"
    "¬c σ ==> idx_iteratei_aux sz i l c f σ = σ"
    "[|i≠0; c σ|] ==> idx_iteratei_aux sz i l c f σ = idx_iteratei_aux sz (i - 1) l c f (f (get l (sz-i)) σ)"
    apply -
    apply (subst idx_iteratei_aux.simps, simp)+
    done

  definition idx_iteratei where 
    "idx_iteratei l c f σ ≡ idx_iteratei_aux (size l) (size l) l c f σ"

  lemma idx_iteratei_correct:
    shows "idx_iteratei s = foldli (α s)" 
  proof -
    {
      fix n l
      assume A: "Suc n ≤ length l"
      hence B: "length l - Suc n < length l" by simp
      from A have [simp]: "Suc (length l - Suc n) = length l - n" by simp
      from nth_drop'[OF B, simplified] have 
        "drop (length l - Suc n) l = l!(length l - Suc n)#drop (length l - n) l" 
        by simp
    } note drop_aux=this

    {
      fix s c f σ i
      assume "invar s" "i≤size s"
      hence "idx_iteratei_aux (size s) i s c f σ 
        = foldli (drop (size s - i) (α s)) c f σ"
      proof (induct i arbitrary: σ)
        case 0 with size_correct[of s] show ?case by simp
      next
        case (Suc n)
        note [simp, intro!] = Suc.prems(1)
        show ?case proof (cases "c σ")
          case False thus ?thesis by simp
        next
          case True[simp, intro!]
          show ?thesis using Suc by (simp add: get_correct size_correct drop_aux)
        qed
      qed
    } note aux=this

    show ?thesis
      unfolding idx_iteratei_def[abs_def]
      by (auto simp add: fun_eq_iff aux[of _ "size s", simplified])
  qed

  lemmas idx_iteratei_unfold[code_unfold] = idx_iteratei_correct[symmetric]

  subsubsection {* reverse\_iteratei (by get, size) *}

  fun idx_reverse_iteratei_aux 
    :: "nat => nat => 's => ('σ=>bool) => ('a =>'σ => 'σ) => 'σ => 'σ"
    where
    "idx_reverse_iteratei_aux sz i l c f σ = (
      if i=0 ∨ ¬ c σ then σ
      else idx_reverse_iteratei_aux sz (i - 1) l c f (f (get l (i - 1)) σ)
    )"

  declare idx_reverse_iteratei_aux.simps[simp del]

  lemma idx_reverse_iteratei_aux_simps[simp]:
    "i=0 ==> idx_reverse_iteratei_aux sz i l c f σ = σ"
    "¬c σ ==> idx_reverse_iteratei_aux sz i l c f σ = σ"
    "[|i≠0; c σ|] ==> idx_reverse_iteratei_aux sz i l c f σ 
    = idx_reverse_iteratei_aux sz (i - 1) l c f (f (get l (i - 1)) σ)"
    by (subst idx_reverse_iteratei_aux.simps, simp)+

  definition "idx_reverse_iteratei l c f σ 
    == idx_reverse_iteratei_aux (size l) (size l) l c f σ"

  lemma idx_reverse_iteratei_correct:
    shows "idx_reverse_iteratei s = foldri (α s)"
  proof -
    {
      fix s c f σ i
      assume "invar s" "i≤size s"
      hence "idx_reverse_iteratei_aux (size s) i s c f σ 
        = foldri (take i (α s)) c f σ"
      proof (induct i arbitrary: σ)
        case 0 with size_correct[of s] show ?case by simp
      next
        case (Suc n)
        note [simp, intro!] = Suc.prems(1)
        show ?case proof (cases "c σ")
          case False thus ?thesis by simp
        next
          case True[simp, intro!]
          show ?thesis using Suc 
            by (simp add: get_correct size_correct take_Suc_conv_app_nth)
        qed
      qed
    } note aux=this

    show ?thesis
      unfolding idx_reverse_iteratei_def[abs_def]
      apply (simp add: fun_eq_iff aux[of _ "size s", simplified])
      apply (simp add: size_correct)
    done
  qed

  lemmas idx_reverse_iteratei_unfold[code_unfold] 
    = idx_reverse_iteratei_correct[symmetric]

end

subsection {* Size (by iterator) *}

locale it_size_loc = poly_list_iteratei +
  constrains α :: "'s => 'a list"
begin

  definition it_size :: "'s => nat"
    where "it_size l == iterate l (λx res. Suc res) (0::nat)"

  lemma it_size_impl: shows "list_size α invar it_size"
    apply (unfold_locales)
    apply (unfold it_size_def)
    apply (simp add: iterate_correct foldli_foldl)
    done
end

subsubsection {* Size (by reverse\_iterator) *}

locale rev_it_size_loc = poly_list_rev_iteratei +
  constrains α :: "'s => 'a list"
begin

  definition rev_it_size :: "'s => nat"
    where "rev_it_size l == rev_iterate l (λx res. Suc res) (0::nat)"

  lemma rev_it_size_impl:
    shows "list_size α invar rev_it_size"
    apply (unfold_locales)
    apply (unfold rev_it_size_def)
    apply (simp add: rev_iterate_correct foldri_foldr)
    done

end

subsection {* Get (by iteratori) *}
locale it_get_loc = poly_list_iteratei + 
  constrains α :: "'s => 'a list"
begin

  definition it_get:: "'s => nat => 'a" 
    where "it_get s i ≡ 
      the (snd (iteratei s
                (λ(i,x). x=None) 
                (λx (i,_). if i=0 then (0,Some x) else (i - 1,None)) 
                (i,None)))"

  lemma it_get_correct:
    shows "list_get α invar it_get"
  proof 
    fix s i 
    assume "invar s" "i < length (α s)"

    def l  "α s"
    from `i < length (α s)`
    show "it_get s i = α s ! i"
      unfolding it_get_def iteratei_correct l_def[symmetric]
    proof (induct i arbitrary: l)
      case 0
      then obtain x xs where l_eq[simp]: "l = x # xs" by (cases l, auto)
      thus ?case by simp
    next
      case (Suc i)
      note ind_hyp = Suc(1)
      note Suc_i_le = Suc(2)
      from Suc_i_le obtain x xs 
        where l_eq[simp]: "l = x # xs" by (cases l, auto)

      from ind_hyp [of xs] Suc_i_le
      show ?case by simp
    qed
  qed
end

end