Theory Collections.AnnotatedListSpec
section ‹\isaheader{Specification of Annotated Lists}›
theory AnnotatedListSpec
imports ICF_Spec_Base
begin
subsection "Introduction"
text ‹
  We define lists with annotated elements. The annotations form a monoid.
  We provide standard list operations and the split-operation, that
  splits the list according to its annotations.
›
locale al =
  
  fixes α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes invar :: "'s ⇒ bool"
  
locale al_no_invar = al +
  assumes invar[simp, intro!]: "⋀l. invar l"
subsection "Basic Annotated List Operations"
subsubsection "Empty Annotated List"
locale al_empty = al +
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes empty :: "unit ⇒ 's"
  assumes empty_correct: 
    "invar (empty ())" 
    "α (empty ()) = Nil" 
subsubsection "Emptiness Check"
locale al_isEmpty = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes isEmpty :: "'s ⇒ bool"
  assumes isEmpty_correct: 
    "invar s ⟹ isEmpty s ⟷ α s = Nil" 
subsubsection "Counting Elements"
locale al_count = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes count :: "'s ⇒ nat"
  assumes count_correct: 
    "invar s ⟹ count s = length(α s)" 
subsubsection "Appending an Element from the Left"
locale al_consl = al +
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes consl :: "'e ⇒ 'a ⇒ 's ⇒ 's"
  assumes consl_correct:
    "invar s ⟹ invar (consl e a s)"
    "invar s ⟹ (α (consl e a s)) = (e,a) # (α s)"
subsubsection "Appending an Element from the Right"
locale al_consr = al +
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes consr :: "'s ⇒ 'e ⇒ 'a ⇒ 's"
  assumes consr_correct:
    "invar s ⟹ invar (consr s e a)"
    "invar s ⟹ (α (consr s e a)) = (α s) @ [(e,a)]"
  
subsubsection "Take the First Element"
locale al_head = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes head :: "'s ⇒ ('e × 'a)"
  assumes head_correct:
    "⟦invar s; α s ≠ Nil⟧ ⟹ head s = hd (α s)"
subsubsection "Drop the First Element"
locale al_tail = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes tail :: "'s ⇒ 's"
  assumes tail_correct:
    "⟦invar s; α s ≠ Nil⟧ ⟹ α (tail s) = tl (α s)"
    "⟦invar s; α s ≠ Nil⟧ ⟹ invar (tail s)"
subsubsection "Take the Last Element"
locale al_headR = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes headR :: "'s ⇒ ('e × 'a)"
  assumes headR_correct:
    "⟦invar s; α s ≠ Nil⟧ ⟹ headR s = last (α s)"
subsubsection "Drop the Last Element"
locale al_tailR = al +   
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes tailR :: "'s ⇒ 's"
  assumes tailR_correct:
    "⟦invar s; α s ≠ Nil⟧ ⟹ α (tailR s) = butlast (α s)"
    "⟦invar s; α s ≠ Nil⟧ ⟹ invar (tailR s)"
subsubsection "Fold a Function over the Elements from the Left"
locale al_foldl = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes foldl :: "('z ⇒ 'e × 'a ⇒ 'z) ⇒ 'z ⇒ 's ⇒ 'z"
  assumes foldl_correct:
    "invar s ⟹ foldl f σ s = List.foldl f σ (α s)"
subsubsection "Fold a Function over the Elements from the Right"
locale al_foldr = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes foldr :: "('e × 'a ⇒ 'z ⇒ 'z) ⇒ 's ⇒ 'z ⇒ 'z"
  assumes foldr_correct:
    "invar s ⟹ foldr f s σ = List.foldr f (α s) σ"
locale poly_al_fold = al +
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
begin
  definition foldl where 
    foldl_correct[code_unfold]: "foldl f σ s = List.foldl f σ (α s)"
  definition foldr where 
    foldr_correct[code_unfold]: "foldr f s σ = List.foldr f (α s) σ"
end
    
subsubsection "Concatenation of Two Annotated Lists"
locale al_app = al +
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes app :: "'s ⇒ 's ⇒ 's"
  assumes app_correct:
    "⟦invar s;invar s'⟧ ⟹ α (app s s') = (α s) @ (α s')"
    "⟦invar s;invar s'⟧ ⟹ invar (app s s')"
subsubsection "Readout the Summed up Annotations"
locale al_annot = al +
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes annot :: "'s ⇒ 'a"
  assumes annot_correct:
    "invar s ⟹ (annot s) = (sum_list (map snd (α s)))"
subsubsection "Split by Monotone Predicate"
locale al_splits = al + 
  constrains α :: "'s ⇒ ('e × 'a::monoid_add) list"
  fixes splits :: "('a ⇒ bool) ⇒ 'a ⇒ 's ⇒ 
                                ('s × ('e × 'a) × 's)"
  assumes splits_correct:
    "⟦invar s;
       ∀a b. p a ⟶ p (a + b);
       ¬ p i; 
       p (i + sum_list (map snd (α s)));
       (splits p i s) = (l, (e,a), r)⟧ 
      ⟹ 
        (α s) = (α l) @ (e,a) # (α r)  ∧
        ¬ p (i + sum_list (map snd (α l)))  ∧
        p (i + sum_list (map snd (α l)) + a)  ∧
        invar l  ∧
        invar r
    "
begin
  lemma splitsE:
    assumes 
    invar: "invar s" and
    mono: "∀a b. p a ⟶ p (a + b)" and
    init_ff: "¬ p i" and
    sum_tt: "p (i + sum_list (map snd (α s)))"
    obtains l e a r where
    "(splits p i s) = (l, (e,a), r)"
    "(α s) = (α l) @ (e,a) # (α r)"
    "¬ p (i + sum_list (map snd (α l)))"
    "p (i + sum_list (map snd (α l)) + a)"
    "invar l"
    "invar r"
    using assms
    apply (cases "splits p i s")
    apply (case_tac b)
    apply (drule_tac i = i and p = p 
      and l = a and r = c and e = aa and a = ba in  splits_correct)
    apply (simp_all)
    done
end    
subsection "Record Based Interface"