Theory MapSpec
section ‹\isaheader{Specification of Maps}›
theory MapSpec
imports ICF_Spec_Base
begin
text_raw‹\label{thy:MapSpec}›
text ‹
  This theory specifies map operations by means of mapping to
  HOL's map type, i.e. @{typ "'k ⇀ 'v"}.
›
type_synonym ('k,'v,'s) map_α = "'s ⇒ 'k ⇀ 'v"
type_synonym ('k,'v,'s) map_invar = "'s ⇒ bool"
locale map = 
  fixes α :: "'s ⇒ 'u ⇀ 'v"                 
  fixes invar :: "'s ⇒ bool"                 
locale map_no_invar = map +
  assumes invar[simp, intro!]: "⋀s. invar s"
subsection "Basic Map Functions"
subsubsection "Empty Map"
type_synonym ('k,'v,'s) map_empty = "unit ⇒ 's"
locale map_empty = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes empty :: "unit ⇒ 's"
  assumes empty_correct:
    "α (empty ()) = Map.empty"
    "invar (empty ())"
subsubsection "Lookup"
type_synonym ('k,'v,'s) map_lookup = "'k ⇒ 's ⇒ 'v option"
locale map_lookup = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes lookup :: "'u ⇒ 's ⇒ 'v option"
  assumes lookup_correct:
    "invar m ⟹ lookup k m = α m k"
subsubsection "Update"
type_synonym ('k,'v,'s) map_update = "'k ⇒ 'v ⇒ 's ⇒ 's"
locale map_update = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes update :: "'u ⇒ 'v ⇒ 's ⇒ 's"
  assumes update_correct:
    "invar m ⟹ α (update k v m) = (α m)(k ↦ v)"
    "invar m ⟹ invar (update k v m)"
subsubsection "Disjoint Update"
type_synonym ('k,'v,'s) map_update_dj = "'k ⇒ 'v ⇒ 's ⇒ 's"
locale map_update_dj = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes update_dj :: "'u ⇒ 'v ⇒ 's ⇒ 's"
  assumes update_dj_correct: 
    "⟦invar m; k∉dom (α m)⟧ ⟹ α (update_dj k v m) = (α m)(k ↦ v)"
    "⟦invar m; k∉dom (α m)⟧ ⟹ invar (update_dj k v m)"
 
subsubsection "Delete"
type_synonym ('k,'v,'s) map_delete = "'k ⇒ 's ⇒ 's"
locale map_delete = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes delete :: "'u ⇒ 's ⇒ 's"
  assumes delete_correct: 
    "invar m ⟹ α (delete k m) = (α m) |` (-{k})"
    "invar m ⟹ invar (delete k m)"
subsubsection "Add"
type_synonym ('k,'v,'s) map_add = "'s ⇒ 's ⇒ 's"
locale map_add = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes add :: "'s ⇒ 's ⇒ 's"
  assumes add_correct:
    "invar m1 ⟹ invar m2 ⟹ α (add m1 m2) = α m1 ++ α m2"
    "invar m1 ⟹ invar m2 ⟹ invar (add m1 m2)"
type_synonym ('k,'v,'s) map_add_dj = "'s ⇒ 's ⇒ 's"
locale map_add_dj = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes add_dj :: "'s ⇒ 's ⇒ 's"
  assumes add_dj_correct:
    "⟦invar m1; invar m2; dom (α m1) ∩ dom (α m2) = {}⟧ ⟹ α (add_dj m1 m2) = α m1 ++ α m2"
    "⟦invar m1; invar m2; dom (α m1) ∩ dom (α m2) = {} ⟧ ⟹ invar (add_dj m1 m2)"
subsubsection "Emptiness Check"
type_synonym ('k,'v,'s) map_isEmpty = "'s ⇒ bool"
locale map_isEmpty = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes isEmpty :: "'s ⇒ bool"
  assumes isEmpty_correct : "invar m ⟹ isEmpty m ⟷ α m = Map.empty"
subsubsection "Singleton Maps"
type_synonym ('k,'v,'s) map_sng = "'k ⇒ 'v ⇒ 's"
locale map_sng = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes sng :: "'u ⇒ 'v ⇒ 's"
  assumes sng_correct : 
    "α (sng k v) = [k ↦ v]"
    "invar (sng k v)"
type_synonym ('k,'v,'s) map_isSng = "'s ⇒ bool"
locale map_isSng = map +
  constrains α :: "'s ⇒ 'k ⇀ 'v"
  fixes isSng :: "'s ⇒ bool"
  assumes isSng_correct:
    "invar s ⟹ isSng s ⟷ (∃k v. α s = [k ↦ v])"
begin
  lemma isSng_correct_exists1 :
    "invar s ⟹ (isSng s ⟷ (∃!k. ∃v. (α s k = Some v)))"
    apply (auto simp add: isSng_correct split: if_split_asm)
    apply (rule_tac x=k in exI)
    apply (rule_tac x=v in exI)
    apply (rule ext)
    apply (case_tac "α s x")
    apply auto
    apply force
    done
  lemma isSng_correct_card :
    "invar s ⟹ (isSng s ⟷ (card (dom (α s)) = 1))"
    by (auto simp add: isSng_correct card_Suc_eq dom_eq_singleton_conv)
end
subsubsection "Finite Maps"
locale finite_map = map +
  assumes finite[simp, intro!]: "invar m ⟹ finite (dom (α m))"
subsubsection "Size"
type_synonym ('k,'v,'s) map_size = "'s ⇒ nat"
locale map_size = finite_map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes size :: "'s ⇒ nat"
  assumes size_correct: "invar s ⟹ size s = card (dom (α s))"
  
type_synonym ('k,'v,'s) map_size_abort = "nat ⇒ 's ⇒ nat"
locale map_size_abort = finite_map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes size_abort :: "nat ⇒ 's ⇒ nat"
  assumes size_abort_correct: "invar s ⟹ size_abort m s = min m (card (dom (α s)))"
subsubsection "Iterators"
text ‹
  An iteration combinator over a map applies a function to a state for each 
  map entry, in arbitrary order.
  Proving of properties is done by invariant reasoning.
  An iterator can also contain a continuation condition. Iteration is
  interrupted if the condition becomes false.
›
type_synonym ('k,'v,'s) map_list_it
  = "'s ⇒ ('k×'v,('k×'v) list) set_iterator"
locale poly_map_iteratei_defs =
  fixes list_it :: "'s ⇒ ('u×'v,('u×'v) list) set_iterator"
begin
  definition iteratei :: "'s ⇒ ('u×'v,'σ) set_iterator"
    where "iteratei S ≡ it_to_it (list_it S)"
  abbreviation "iterate m ≡ iteratei m (λ_. True)"
end
locale poly_map_iteratei =
  finite_map + poly_map_iteratei_defs list_it
  for list_it :: "'s ⇒ ('u×'v,('u×'v) list) set_iterator" +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  assumes list_it_correct: "invar m ⟹ map_iterator (list_it m) (α m)"
begin
  lemma iteratei_correct: "invar S ⟹ map_iterator (iteratei S) (α S)"
    unfolding iteratei_def
    apply (rule it_to_it_correct)
    by (rule list_it_correct)
  lemma pi_iteratei[icf_proper_iteratorI]: 
    "proper_it (iteratei S) (iteratei S)"
    unfolding iteratei_def 
    by (intro icf_proper_iteratorI)
  lemma iteratei_rule_P:
    assumes "invar m"
    and I0: "I (map_to_set (α m)) σ0"
    and IP: "!!k v it σ. ⟦ c σ; (k,v) ∈ it; it ⊆ map_to_set (α m); I it σ ⟧ 
      ⟹ I (it - {(k,v)}) (f (k, v) σ)"
    and IF: "!!σ. I {} σ ⟹ P σ"
    and II: "!!σ it. ⟦ it ⊆ map_to_set (α m); it ≠ {}; ¬ c σ; I it σ ⟧ ⟹ P σ"
    shows "P (iteratei m c f σ0)"
    apply (rule set_iterator_rule_P[OF iteratei_correct])
    apply fact
    apply fact
    apply (case_tac x, simp add: IP)
    apply fact
    apply fact
    done
  lemma iteratei_rule_insert_P:
    assumes "invar m" 
    and "I {} σ0"
    and "!!k v it σ. ⟦ c σ; (k,v) ∈ (map_to_set (α m) - it); 
                       it ⊆ map_to_set (α m); I it σ ⟧ 
      ⟹ I (insert (k,v) it) (f (k, v) σ)"
    and "!!σ. I (map_to_set (α m)) σ ⟹ P σ"
    and "!!σ it. ⟦ it ⊆ map_to_set (α m); it ≠ map_to_set (α m); 
                  ¬ (c σ); 
                  I it σ ⟧ ⟹ P σ"
    shows "P (iteratei m c f σ0)"
    apply (rule set_iterator_rule_insert_P[OF iteratei_correct])
    apply fact
    apply fact
    apply (case_tac x, simp add: assms)
    apply fact
    apply fact
    done
  lemma iterate_rule_P:
    assumes "invar m"
    and I0: "I (map_to_set (α m)) σ0"
    and IP: "!!k v it σ. ⟦ (k,v) ∈ it; it ⊆ map_to_set (α m); I it σ ⟧ 
      ⟹ I (it - {(k,v)}) (f (k, v) σ)"
    and IF: "!!σ. I {} σ ⟹ P σ"
    shows "P (iterate m f σ0)"
    apply (rule iteratei_rule_P)
    apply fact
    apply (rule I0)
    apply (rule IP, assumption+) []
    apply (rule IF, assumption)
    apply simp
    done
  lemma iterate_rule_insert_P:
    assumes "invar m" 
    and I0: "I {} σ0"
    and "!!k v it σ. ⟦ (k,v) ∈ (map_to_set (α m) - it); 
                       it ⊆ map_to_set (α m); I it σ ⟧ 
      ⟹ I (insert (k,v) it) (f (k, v) σ)"
    and "!!σ. I (map_to_set (α m)) σ ⟹ P σ"
    shows "P (iterate m f σ0)"
    apply (rule iteratei_rule_insert_P)
    apply fact
    apply (rule I0)
    apply (rule assms, assumption+) []
    apply (rule assms, assumption)
    apply simp
    done
    
  lemma old_iteratei_rule_P:
    assumes "invar m"
    and I0: "I (dom (α m)) σ0"
    and IP: "!!k v it σ. ⟦ c σ; k ∈ it; α m k = Some v; it ⊆ dom (α m); I it σ ⟧ 
      ⟹ I (it - {k}) (f (k, v) σ)"
    and IF: "!!σ. I {} σ ⟹ P σ"
    and II: "!!σ it. ⟦ it ⊆ dom (α m); it ≠ {}; ¬ c σ; I it σ ⟧ ⟹ P σ"
    shows "P (iteratei m c f σ0)"
    using assms
    by (rule map_iterator_rule_P[OF iteratei_correct])
  lemma old_iteratei_rule_insert_P:
    assumes "invar m" 
    and "I {} σ0"
    and "!!k v it σ. ⟦ c σ; k ∈ (dom (α m) - it); α m k = Some v; 
                       it ⊆ dom (α m); I it σ ⟧ 
      ⟹ I (insert k it) (f (k, v) σ)"
    and "!!σ. I (dom (α m)) σ ⟹ P σ"
    and "!!σ it. ⟦ it ⊆ dom (α m); it ≠ dom (α m); 
                  ¬ (c σ); 
                  I it σ ⟧ ⟹ P σ"
    shows "P (iteratei m c f σ0)"
    using assms by (rule map_iterator_rule_insert_P[OF iteratei_correct])
  lemma old_iterate_rule_P:
    "⟦
      invar m;
      I (dom (α m)) σ0;
      !!k v it σ. ⟦ k ∈ it; α m k = Some v; it ⊆ dom (α m); I it σ ⟧ 
                  ⟹ I (it - {k}) (f (k, v) σ);
      !!σ. I {} σ ⟹ P σ
    ⟧ ⟹ P (iterate m f σ0)"
    using old_iteratei_rule_P [of m I σ0 "λ_. True" f P]
    by blast
  lemma old_iterate_rule_insert_P:
    "⟦
      invar m;
      I {} σ0;
      !!k v it σ. ⟦ k ∈ (dom (α m) - it); α m k = Some v; 
                    it ⊆ dom (α m); I it σ ⟧ 
                  ⟹ I (insert k it) (f (k, v) σ);
      !!σ. I (dom (α m)) σ ⟹ P σ
    ⟧ ⟹ P (iteratei m (λ_. True) f σ0)"
    using old_iteratei_rule_insert_P [of m I σ0 "λ_. True" f P]
    by blast
  end
subsubsection "Bounded Quantification"
type_synonym ('k,'v,'s) map_ball = "'s ⇒ ('k × 'v ⇒ bool) ⇒ bool"
locale map_ball = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes ball :: "'s ⇒ ('u × 'v ⇒ bool) ⇒ bool"
  assumes ball_correct: "invar m ⟹ ball m P ⟷ (∀u v. α m u = Some v ⟶ P (u, v))"
type_synonym ('k,'v,'s) map_bex = "'s ⇒ ('k × 'v ⇒ bool) ⇒ bool"
locale map_bex = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes bex :: "'s ⇒ ('u × 'v ⇒ bool) ⇒ bool"
  assumes bex_correct: 
    "invar m ⟹ bex m P ⟷ (∃u v. α m u = Some v ∧ P (u, v))"
subsubsection "Selection of Entry"
type_synonym ('k,'v,'s,'r) map_sel = "'s ⇒ ('k × 'v ⇒ 'r option) ⇒ 'r option"
locale map_sel = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes sel :: "'s ⇒ ('u × 'v ⇒ 'r option) ⇒ 'r option"
  assumes selE: 
  "⟦ invar m; α m u = Some v; f (u, v) = Some r; 
     !!u v r. ⟦ sel m f = Some r; α m u = Some v; f (u, v) = Some r ⟧ ⟹ Q 
   ⟧ ⟹ Q"
  assumes selI: 
    "⟦ invar m; ∀u v. α m u = Some v ⟶ f (u, v) = None ⟧ ⟹ sel m f = None"
begin
  lemma sel_someE: 
    "⟦ invar m; sel m f = Some r; 
       !!u v. ⟦ α m u = Some v; f (u, v) = Some r ⟧ ⟹ P
     ⟧ ⟹ P"
    apply (cases "∃u v r. α m u = Some v ∧ f (u, v) = Some r")
    apply safe
    apply (erule_tac u=u and v=v and r=ra in selE)
    apply assumption
    apply assumption
    apply simp
    apply (auto)
    apply (drule (1) selI)
    apply simp
    done
  lemma sel_noneD: "⟦invar m; sel m f = None; α m u = Some v⟧ ⟹ f (u, v) = None"
    apply (rule ccontr)
    apply simp
    apply (erule exE)
    apply (erule_tac f=f and u=u and v=v and r=y in selE)
    apply auto
    done
end
  
lemma map_sel_altI:
  assumes S1: 
    "!!s f r P. ⟦ invar s; sel s f = Some r; 
                  !!u v. ⟦α s u = Some v; f (u, v) = Some r⟧ ⟹ P
                ⟧ ⟹ P"
  assumes S2: 
    "!!s f u v. ⟦invar s; sel s f = None; α s u = Some v⟧ ⟹ f (u, v) = None"
  shows "map_sel α invar sel"
proof -
  show ?thesis
    apply (unfold_locales)
    apply (case_tac "sel m f")
    apply (force dest: S2)
    apply (force elim: S1)
    apply (case_tac "sel m f")
    apply assumption
    apply (force elim: S1)
    done
qed
subsubsection "Selection of Entry (without mapping)"
type_synonym ('k,'v,'s) map_sel' = "'s ⇒ ('k × 'v ⇒ bool) ⇒ ('k×'v) option"
locale map_sel' = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes sel' :: "'s ⇒ ('u × 'v ⇒ bool) ⇒ ('u×'v) option"
  assumes sel'E: 
  "⟦ invar m; α m u = Some v; P (u, v); 
     !!u v. ⟦ sel' m P = Some (u,v); α m u = Some v; P (u, v)⟧ ⟹ Q 
   ⟧ ⟹ Q"
  assumes sel'I: 
    "⟦ invar m; ∀u v. α m u = Some v ⟶ ¬ P (u, v) ⟧ ⟹ sel' m P = None"
begin
  lemma sel'_someE: 
    "⟦ invar m; sel' m P = Some (u,v); 
       !!u v. ⟦ α m u = Some v; P (u, v) ⟧ ⟹ thesis
     ⟧ ⟹ thesis"
    apply (cases "∃u v. α m u = Some v ∧ P (u, v)")
    apply safe
    apply (erule_tac u=ua and v=va in sel'E)
    apply assumption
    apply assumption
    apply simp
    apply (auto)
    apply (drule (1) sel'I)
    apply simp
    done
  lemma sel'_noneD: "⟦invar m; sel' m P = None; α m u = Some v⟧ ⟹ ¬ P (u, v)"
    apply (rule ccontr)
    apply simp
    apply (erule (2) sel'E[where P=P])
    apply auto
    done
  lemma sel'_SomeD:
    "⟦ sel' m P = Some (u, v); invar m ⟧ ⟹ α m u = Some v ∧ P (u, v)"
    apply(cases "∃u' v'. α m u' = Some v' ∧ P (u', v')")
     apply clarsimp
     apply(erule (2) sel'E[where P=P])
     apply simp
    apply(clarsimp)
    apply(drule (1) sel'I)
    apply simp
    done
end
subsubsection "Map to List Conversion"
type_synonym ('k,'v,'s) map_to_list = "'s ⇒ ('k×'v) list"
locale map_to_list = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes to_list :: "'s ⇒ ('u×'v) list"
  assumes to_list_correct: 
    "invar m ⟹ map_of (to_list m) = α m"
    "invar m ⟹ distinct (map fst (to_list m))"
subsubsection "List to Map Conversion"
type_synonym ('k,'v,'s) list_to_map = "('k×'v) list ⇒ 's"
locale list_to_map = map +
  constrains α :: "'s ⇒ 'u ⇀ 'v"
  fixes to_map :: "('u×'v) list ⇒ 's"
  assumes to_map_correct:
    "α (to_map l) = map_of l"
    "invar (to_map l)"
subsubsection "Image of a Map"
text ‹This locale allows to apply a function to both the keys and
 the values of a map while at the same time filtering entries.›
definition transforms_to_unique_keys ::
  "('u1 ⇀ 'v1) ⇒ ('u1 × 'v1 ⇀ ('u2 × 'v2)) ⇒ bool"
  where
  "transforms_to_unique_keys m f ≡ (∀k1 k2 v1 v2 k' v1' v2'. ( 
         m k1 = Some v1 ∧
         m k2 = Some v2 ∧
         f (k1, v1) = Some (k', v1') ∧
         f (k2, v2) = Some (k', v2')) -->
       (k1 = k2))"
type_synonym ('k1,'v1,'m1,'k2,'v2,'m2) map_image_filter  
  = "('k1 × 'v1 ⇒ ('k2 × 'v2) option) ⇒ 'm1 ⇒ 'm2"
locale map_image_filter = m1: map α1 invar1 + m2: map α2 invar2
  for α1 :: "'m1 ⇒ 'u1 ⇀ 'v1" and invar1
  and α2 :: "'m2 ⇒ 'u2 ⇀ 'v2" and invar2
  +
  fixes map_image_filter :: "('u1 × 'v1 ⇒ ('u2 × 'v2) option) ⇒ 'm1 ⇒ 'm2"
  assumes map_image_filter_correct_aux1:
    "⋀k' v'. 
     ⟦invar1 m; transforms_to_unique_keys (α1 m) f⟧ ⟹ 
     (invar2 (map_image_filter f m) ∧
      ((α2 (map_image_filter f m) k' = Some v') ⟷
       (∃k v. (α1 m k = Some v) ∧ f (k, v) = Some (k', v'))))"
begin
  
  lemma map_image_filter_correct_aux2 :
    assumes "invar1 m" 
      and "transforms_to_unique_keys (α1 m) f"
    shows "(α2 (map_image_filter f m) k' = None) ⟷
      (∀k v v'. α1 m k = Some v ⟶ f (k, v) ≠ Some (k', v'))"
  proof -
    note map_image_filter_correct_aux1 [OF assms]
    have Some_eq: "⋀v'. (α2 (map_image_filter f m) k' = Some v') =
          (∃k v. α1 m k = Some v ∧ f (k, v) = Some (k', v'))"
      by (simp add: map_image_filter_correct_aux1 [OF assms])
    
    have intro_some: "(α2 (map_image_filter f m) k' = None) ⟷
                      (∀v'. α2 (map_image_filter f m) k' ≠ Some v')" by auto
    
    from intro_some Some_eq show ?thesis by auto
  qed
  lemmas map_image_filter_correct = 
     conjunct1 [OF map_image_filter_correct_aux1] 
     conjunct2 [OF map_image_filter_correct_aux1] 
     map_image_filter_correct_aux2
end
    
text ‹Most of the time the mapping function is only applied to values. Then,
  the precondition disapears.›
type_synonym ('k,'v1,'m1,'k2,'v2,'m2) map_value_image_filter  
  = "('k ⇒ 'v1 ⇒ 'v2 option) ⇒ 'm1 ⇒ 'm2"
locale map_value_image_filter = m1: map α1 invar1 + m2: map α2 invar2
  for α1 :: "'m1 ⇒ 'u ⇀ 'v1" and invar1
  and α2 :: "'m2 ⇒ 'u ⇀ 'v2" and invar2
  +
  fixes map_value_image_filter :: "('u ⇒ 'v1 ⇒ 'v2 option) ⇒ 'm1 ⇒ 'm2"
  assumes map_value_image_filter_correct_aux:
    "invar1 m ⟹ 
     invar2 (map_value_image_filter f m) ∧
     (α2 (map_value_image_filter f m) = 
      (λk. Option.bind (α1 m k) (f k)))"
begin
  lemmas map_value_image_filter_correct =
    conjunct1[OF map_value_image_filter_correct_aux]
    conjunct2[OF map_value_image_filter_correct_aux]
  lemma map_value_image_filter_correct_alt :
    "invar1 m ⟹ 
     invar2 (map_value_image_filter f m)"
    "invar1 m ⟹
     (α2 (map_value_image_filter f m) k = Some v') ⟷
     (∃v. (α1 m k = Some v) ∧ f k v = Some v')"
    "invar1 m ⟹
     (α2 (map_value_image_filter f m) k = None) ⟷
     (∀v. (α1 m k = Some v) --> f k v = None)"
  proof -
    assume invar_m : "invar1 m"
    note aux = map_value_image_filter_correct_aux [OF invar_m]
    from aux show "invar2 (map_value_image_filter f m)" by simp
    from aux show "(α2 (map_value_image_filter f m) k = Some v') ⟷
     (∃v. (α1 m k = Some v) ∧ f k v = Some v')" 
      by (cases "α1 m k", simp_all)
    from aux show "(α2 (map_value_image_filter f m) k = None) ⟷
     (∀v. (α1 m k = Some v) --> f k v = None)" 
      by (cases "α1 m k", simp_all)
  qed
end
type_synonym ('k,'v,'m1,'m2) map_restrict = "('k × 'v ⇒ bool) ⇒ 'm1 ⇒ 'm2"
locale map_restrict = m1: map α1 invar1 + m2: map α2 invar2 
  for α1 :: "'m1 ⇒ 'u ⇀ 'v" and invar1
  and α2 :: "'m2 ⇒ 'u ⇀ 'v" and invar2
  +
  fixes restrict :: "('u × 'v ⇒ bool) ⇒ 'm1 ⇒ 'm2"
  assumes restrict_correct_aux1 :
    "invar1 m ⟹ α2 (restrict P m) = α1 m |` {k. ∃v. α1 m k = Some v ∧ P (k, v)}"
    "invar1 m ⟹ invar2 (restrict P m)"
begin
  lemma restrict_correct_aux2 :
    "invar1 m ⟹ α2 (restrict (λ(k,_). P k) m) = α1 m |` {k. P k}"
  proof -
    assume invar_m : "invar1 m"
    have "α1 m |` {k. (∃v. α1 m k = Some v) ∧ P k} = α1 m |` {k. P k}"
      (is "α1 m |` ?A1 = α1 m |` ?A2")
    proof
      fix k
      show "(α1 m |` ?A1) k = (α1 m |` ?A2) k"
      proof (cases "k ∈ ?A2")
        case False thus ?thesis by simp
      next
        case True
        hence P_k : "P k" by simp
        show ?thesis
          by (cases "α1 m k", simp_all add: P_k)
      qed
    qed
    with invar_m show "α2 (restrict (λ(k, _). P k) m) = α1 m |` {k. P k}"
      by (simp add: restrict_correct_aux1)
  qed
  lemmas restrict_correct = 
     restrict_correct_aux1
     restrict_correct_aux2
end
subsection "Ordered Maps"
  locale ordered_map = map α invar 
    for α :: "'s ⇒ ('u::linorder) ⇀ 'v" and invar
  locale ordered_finite_map = finite_map α invar + ordered_map α invar
    for α :: "'s ⇒ ('u::linorder) ⇀ 'v" and invar
subsubsection ‹Ordered Iteration›
  
locale poly_map_iterateoi_defs =
  fixes olist_it :: "'s ⇒ ('u×'v,('u×'v) list) set_iterator"
begin
  definition iterateoi :: "'s ⇒ ('u×'v,'σ) set_iterator"
    where "iterateoi S ≡ it_to_it (olist_it S)"
  abbreviation "iterateo m ≡ iterateoi m (λ_. True)"
end
locale poly_map_iterateoi =
  finite_map α invar + poly_map_iterateoi_defs list_ordered_it
  for α :: "'s ⇒ ('u::linorder) ⇀ 'v" 
  and invar 
  and list_ordered_it :: "'s ⇒ ('u×'v,('u×'v) list) set_iterator" +
  assumes list_ordered_it_correct: "invar m 
    ⟹ map_iterator_linord (list_ordered_it m) (α m)"
begin
  lemma iterateoi_correct: "invar S ⟹ map_iterator_linord (iterateoi S) (α S)"
    unfolding iterateoi_def
    apply (rule it_to_it_map_linord_correct)
    by (rule list_ordered_it_correct)
  lemma pi_iterateoi[icf_proper_iteratorI]: 
    "proper_it (iterateoi S) (iterateoi S)"
    unfolding iterateoi_def 
    by (intro icf_proper_iteratorI)
  lemma iterateoi_rule_P[case_names minv inv0 inv_pres i_complete i_inter]:
    assumes MINV: "invar m"
    assumes I0: "I (dom (α m)) σ0"
    assumes IP: "!!k v it σ. ⟦ 
      c σ; 
      k ∈ it; 
      α m k = Some v; 
      it ⊆ dom (α m); 
      I it σ;
      ⋀j. j∈it ⟹ k≤j; 
      ⋀j. j∈dom (α m) - it ⟹ j≤k
    ⟧ ⟹ I (it - {k}) (f (k, v) σ)"
    assumes IF: "!!σ. I {} σ ⟹ P σ"
    assumes II: "!!σ it. ⟦ 
      it ⊆ dom (α m); 
      it ≠ {}; 
      ¬ c σ; 
      I it σ; 
      ⋀k j. ⟦k∈it; j∈dom (α m) - it⟧ ⟹ j≤k 
    ⟧ ⟹ P σ"
    shows "P (iterateoi m c f σ0)"
    using assms by (rule map_iterator_linord_rule_P[OF iterateoi_correct])
  lemma iterateo_rule_P[case_names minv inv0 inv_pres i_complete]: 
    assumes MINV: "invar m"
    assumes I0: "I (dom (α m)) σ0"
    assumes IP: "!!k v it σ. ⟦ 
      k ∈ it; 
      α m k = Some v; 
      it ⊆ dom (α m); 
      I it σ;
      ⋀j. j∈it ⟹ k≤j; 
      ⋀j. j∈dom (α m) - it ⟹ j≤k
    ⟧ ⟹ I (it - {k}) (f (k, v) σ)"
    assumes IF: "!!σ. I {} σ ⟹ P σ"
    shows "P (iterateo m f σ0)"
    using assms 
      map_iterator_linord_rule_P[OF iterateoi_correct, of m I σ0 "λ_. True" f P]
    by blast
end
  
type_synonym ('k,'v,'s) map_list_rev_it
  = "'s ⇒ ('k×'v,('k×'v) list) set_iterator"
locale poly_map_rev_iterateoi_defs =
  fixes list_rev_it :: "'s ⇒ ('u×'v,('u×'v) list) set_iterator"
begin
  definition rev_iterateoi :: "'s ⇒ ('u×'v,'σ) set_iterator"
    where "rev_iterateoi S ≡ it_to_it (list_rev_it S)"
  abbreviation "rev_iterateo m ≡ rev_iterateoi m (λ_. True)"
  abbreviation "reverse_iterateoi ≡ rev_iterateoi"
  abbreviation "reverse_iterateo ≡ rev_iterateo"
end
locale poly_map_rev_iterateoi =
  finite_map α invar + poly_map_rev_iterateoi_defs list_rev_it
  for α :: "'s ⇒ ('u::linorder) ⇀ 'v" 
  and invar
  and list_rev_it :: "'s ⇒ ('u×'v,('u×'v) list) set_iterator" +
  assumes list_rev_it_correct: 
    "invar m ⟹ map_iterator_rev_linord (list_rev_it m) (α m)"
begin
  lemma rev_iterateoi_correct: 
    "invar S ⟹ map_iterator_rev_linord (rev_iterateoi S) (α S)"
    unfolding rev_iterateoi_def
    apply (rule it_to_it_map_rev_linord_correct)
    by (rule list_rev_it_correct)
  lemma pi_rev_iterateoi[icf_proper_iteratorI]: 
    "proper_it (rev_iterateoi S) (rev_iterateoi S)"
    unfolding rev_iterateoi_def 
    by (intro icf_proper_iteratorI)
  lemma rev_iterateoi_rule_P[case_names minv inv0 inv_pres i_complete i_inter]:
    assumes MINV: "invar m"
    assumes I0: "I (dom (α m)) σ0"
    assumes IP: "!!k v it σ. ⟦ 
      c σ; 
      k ∈ it; 
      α m k = Some v; 
      it ⊆ dom (α m); 
      I it σ;
      ⋀j. j∈it ⟹ k≥j; 
      ⋀j. j∈dom (α m) - it ⟹ j≥k
    ⟧ ⟹ I (it - {k}) (f (k, v) σ)"
    assumes IF: "!!σ. I {} σ ⟹ P σ"
    assumes II: "!!σ it. ⟦ 
      it ⊆ dom (α m); 
      it ≠ {}; 
      ¬ c σ; 
      I it σ; 
      ⋀k j. ⟦k∈it; j∈dom (α m) - it⟧ ⟹ j≥k 
    ⟧ ⟹ P σ"
    shows "P (rev_iterateoi m c f σ0)"
    using assms by (rule map_iterator_rev_linord_rule_P[OF rev_iterateoi_correct])
  lemma rev_iterateo_rule_P[case_names minv inv0 inv_pres i_complete]: 
    assumes MINV: "invar m"
    assumes I0: "I (dom (α m)) σ0"
    assumes IP: "!!k v it σ. ⟦ 
      k ∈ it; 
      α m k = Some v; 
      it ⊆ dom (α m); 
      I it σ;
      ⋀j. j∈it ⟹ k≥j; 
      ⋀j. j∈dom (α m) - it ⟹ j≥k
    ⟧ ⟹ I (it - {k}) (f (k, v) σ)"
    assumes IF: "!!σ. I {} σ ⟹ P σ"
    shows "P (rev_iterateo m f σ0)"
    using assms 
      map_iterator_rev_linord_rule_P[OF rev_iterateoi_correct, 
        of m I σ0 "λ_. True" f P]
    by blast
end
subsubsection ‹Minimal and Maximal Elements›
  type_synonym ('k,'v,'s) map_min 
    = "'s ⇒ ('k × 'v ⇒ bool) ⇒ ('k × 'v) option"
  locale map_min = ordered_map +
    constrains α :: "'s ⇒ 'u::linorder ⇀ 'v"
    fixes min :: "'s ⇒ ('u × 'v ⇒ bool) ⇒ ('u × 'v) option"
    assumes min_correct:
      "⟦ invar s; rel_of (α s) P ≠ {} ⟧ ⟹ min s P ∈ Some ` rel_of (α s) P"
      "⟦ invar s; (k,v) ∈ rel_of (α s) P ⟧ ⟹ fst (the (min s P)) ≤ k"
      "⟦ invar s; rel_of (α s) P = {} ⟧ ⟹ min s P = None"
  begin
   lemma minE: 
     assumes A: "invar s" "rel_of (α s) P ≠ {}"
     obtains k v where
     "min s P = Some (k,v)" "(k,v)∈rel_of (α s) P" "∀(k',v')∈rel_of (α s) P. k ≤ k'"
   proof -
     from min_correct(1)[OF A] have MIS: "min s P ∈ Some ` rel_of (α s) P" .
     then obtain k v where KV: "min s P = Some (k,v)" "(k,v)∈rel_of (α s) P"
       by auto
     show thesis 
       apply (rule that[OF KV])
       apply (clarify)
       apply (drule min_correct(2)[OF ‹invar s›])
       apply (simp add: KV(1))
       done
   qed
   lemmas minI = min_correct(3)
   lemma min_Some:
     "⟦ invar s; min s P = Some (k,v) ⟧ ⟹ (k,v)∈rel_of (α s) P"
     "⟦ invar s; min s P = Some (k,v); (k',v')∈rel_of (α s) P ⟧ ⟹ k≤k'"
     apply -
     apply (cases "rel_of (α s) P = {}")
     apply (drule (1) min_correct(3))
     apply simp
     apply (erule (1) minE)
     apply auto [1]
     apply (drule (1) min_correct(2))
     apply auto
     done
     
   lemma min_None:
     "⟦ invar s; min s P = None ⟧ ⟹ rel_of (α s) P = {}"
     apply (cases "rel_of (α s) P = {}")
     apply simp
     apply (drule (1) min_correct(1))
     apply auto
     done
  end
  type_synonym ('k,'v,'s) map_max
    = "'s ⇒ ('k × 'v ⇒ bool) ⇒ ('k × 'v) option"
  locale map_max = ordered_map +
    constrains α :: "'s ⇒ 'u::linorder ⇀ 'v"
    fixes max :: "'s ⇒ ('u × 'v ⇒ bool) ⇒ ('u × 'v) option"
    assumes max_correct:
      "⟦ invar s; rel_of (α s) P ≠ {} ⟧ ⟹ max s P ∈ Some ` rel_of (α s) P"
      "⟦ invar s; (k,v) ∈ rel_of (α s) P ⟧ ⟹ fst (the (max s P)) ≥ k"
      "⟦ invar s; rel_of (α s) P = {} ⟧ ⟹ max s P = None"
  begin
   lemma maxE: 
     assumes A: "invar s" "rel_of (α s) P ≠ {}"
     obtains k v where
     "max s P = Some (k,v)" "(k,v)∈rel_of (α s) P" "∀(k',v')∈rel_of (α s) P. k ≥ k'"
   proof -
     from max_correct(1)[OF A] have MIS: "max s P ∈ Some ` rel_of (α s) P" .
     then obtain k v where KV: "max s P = Some (k,v)" "(k,v)∈rel_of (α s) P"
       by auto
     show thesis 
       apply (rule that[OF KV])
       apply (clarify)
       apply (drule max_correct(2)[OF ‹invar s›])
       apply (simp add: KV(1))
       done
   qed
   lemmas maxI = max_correct(3)
   lemma max_Some:
     "⟦ invar s; max s P = Some (k,v) ⟧ ⟹ (k,v)∈rel_of (α s) P"
     "⟦ invar s; max s P = Some (k,v); (k',v')∈rel_of (α s) P ⟧ ⟹ k≥k'"
     apply -
     apply (cases "rel_of (α s) P = {}")
     apply (drule (1) max_correct(3))
     apply simp
     apply (erule (1) maxE)
     apply auto [1]
     apply (drule (1) max_correct(2))
     apply auto
     done
     
   lemma max_None:
     "⟦ invar s; max s P = None ⟧ ⟹ rel_of (α s) P = {}"
     apply (cases "rel_of (α s) P = {}")
     apply simp
     apply (drule (1) max_correct(1))
     apply auto
     done
  end
subsubsection "Conversion to List"
  type_synonym ('k,'v,'s) map_to_sorted_list 
    = "'s ⇒ ('k × 'v) list"
  locale map_to_sorted_list = ordered_map +
    constrains α :: "'s ⇒ 'u::linorder ⇀ 'v"
    fixes to_sorted_list :: "'s ⇒ ('u×'v) list"
    assumes to_sorted_list_correct: 
    "invar m ⟹ map_of (to_sorted_list m) = α m"
    "invar m ⟹ distinct (map fst (to_sorted_list m))"
    "invar m ⟹ sorted (map fst (to_sorted_list m))"
  type_synonym ('k,'v,'s) map_to_rev_list 
    = "'s ⇒ ('k × 'v) list"
  locale map_to_rev_list = ordered_map +
    constrains α :: "'s ⇒ 'u::linorder ⇀ 'v"
    fixes to_rev_list :: "'s ⇒ ('u×'v) list"
    assumes to_rev_list_correct: 
    "invar m ⟹ map_of (to_rev_list m) = α m"
    "invar m ⟹ distinct (map fst (to_rev_list m))"
    "invar m ⟹ sorted (rev (map fst (to_rev_list m)))"
subsection "Record Based Interface"