Theory ListGA

section ‹\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 σ = σ"
    "i0; 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 Cons_nth_drop_Suc[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" "isize 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 [simp, intro!]: True
          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 σ = σ"
    "i0; 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" "isize 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 [simp, intro!]: True
          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)"

    define l where "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