(*  Title:      ZF/QPair.thy
    Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
    Copyright   1993  University of Cambridge

Many proofs are borrowed from pair.thy and sum.thy

Do we EVER have rank(a) < rank(<a;b>) ?  Perhaps if the latter rank
is not a limit ordinal?
*)

section\<open>Quine-Inspired Ordered Pairs and Disjoint Sums\<close>

theory QPair imports Sum func begin

text\<open>For non-well-founded data
structures in ZF.  Does not precisely follow Quine's construction.  Thanks
to Thomas Forster for suggesting this approach!

W. V. Quine, On Ordered Pairs and Relations, in Selected Logic Papers,
1966.
\<close>

definition
  QPair     :: "[i, i] => i"                      ("<(_;/ _)>")  where
    "<a;b> == a+b"

definition
  qfst :: "i => i"  where
    "qfst(p) == THE a. \<exists>b. p=<a;b>"

definition
  qsnd :: "i => i"  where
    "qsnd(p) == THE b. \<exists>a. p=<a;b>"

definition
  qsplit    :: "[[i, i] => 'a, i] => 'a::{}"  (*for pattern-matching*)  where
    "qsplit(c,p) == c(qfst(p), qsnd(p))"

definition
  qconverse :: "i => i"  where
    "qconverse(r) == {z. w \<in> r, \<exists>x y. w=<x;y> & z=<y;x>}"

definition
  QSigma    :: "[i, i => i] => i"  where
    "QSigma(A,B)  ==  \<Union>x\<in>A. \<Union>y\<in>B(x). {<x;y>}"

syntax
  "_QSUM"   :: "[idt, i, i] => i"               ("(3QSUM _ \<in> _./ _)" 10)
translations
  "QSUM x \<in> A. B"  => "CONST QSigma(A, %x. B)"

abbreviation
  qprod  (infixr "<*>" 80) where
  "A <*> B == QSigma(A, %_. B)"

definition
  qsum    :: "[i,i]=>i"                         (infixr "<+>" 65)  where
    "A <+> B      == ({0} <*> A) \<union> ({1} <*> B)"

definition
  QInl :: "i=>i"  where
    "QInl(a)      == <0;a>"

definition
  QInr :: "i=>i"  where
    "QInr(b)      == <1;b>"

definition
  qcase     :: "[i=>i, i=>i, i]=>i"  where
    "qcase(c,d)   == qsplit(%y z. cond(y, d(z), c(z)))"

subsection\<open>Quine ordered pairing\<close>

(** Lemmas for showing that <a;b> uniquely determines a and b **)

lemma QPair_empty [simp]: "<0;0> = 0"
by (simp add: QPair_def)

lemma QPair_iff [simp]: "<a;b> = <c;d> \<longleftrightarrow> a=c & b=d"
apply (simp add: QPair_def)
apply (rule sum_equal_iff)
done

lemmas QPair_inject = QPair_iff [THEN iffD1, THEN conjE, elim!]

lemma QPair_inject1: "<a;b> = <c;d> ==> a=c"
by blast

lemma QPair_inject2: "<a;b> = <c;d> ==> b=d"
by blast

subsubsection\<open>QSigma: Disjoint union of a family of sets
     Generalizes Cartesian product\<close>

lemma QSigmaI [intro!]: "[| a \<in> A;  b \<in> B(a) |] ==> <a;b> \<in> QSigma(A,B)"
by (simp add: QSigma_def)

(** Elimination rules for <a;b>:A*B -- introducing no eigenvariables **)

lemma QSigmaE [elim!]:
    "[| c \<in> QSigma(A,B);
        !!x y.[| x \<in> A;  y \<in> B(x);  c=<x;y> |] ==> P
     |] ==> P"
by (simp add: QSigma_def, blast)

lemma QSigmaE2 [elim!]:
    "[| <a;b>: QSigma(A,B); [| a \<in> A;  b \<in> B(a) |] ==> P |] ==> P"
by (simp add: QSigma_def)

lemma QSigmaD1: "<a;b> \<in> QSigma(A,B) ==> a \<in> A"
by blast

lemma QSigmaD2: "<a;b> \<in> QSigma(A,B) ==> b \<in> B(a)"
by blast

lemma QSigma_cong:
    "[| A=A';  !!x. x \<in> A' ==> B(x)=B'(x) |] ==>
     QSigma(A,B) = QSigma(A',B')"
by (simp add: QSigma_def)

lemma QSigma_empty1 [simp]: "QSigma(0,B) = 0"
by blast

lemma QSigma_empty2 [simp]: "A <*> 0 = 0"
by blast

subsubsection\<open>Projections: qfst, qsnd\<close>

lemma qfst_conv [simp]: "qfst(<a;b>) = a"
by (simp add: qfst_def)

lemma qsnd_conv [simp]: "qsnd(<a;b>) = b"
by (simp add: qsnd_def)

lemma qfst_type [TC]: "p \<in> QSigma(A,B) ==> qfst(p) \<in> A"
by auto

lemma qsnd_type [TC]: "p \<in> QSigma(A,B) ==> qsnd(p) \<in> B(qfst(p))"
by auto

lemma QPair_qfst_qsnd_eq: "a \<in> QSigma(A,B) ==> <qfst(a); qsnd(a)> = a"
by auto

subsubsection\<open>Eliminator: qsplit\<close>

(*A META-equality, so that it applies to higher types as well...*)
lemma qsplit [simp]: "qsplit(%x y. c(x,y), <a;b>) == c(a,b)"
by (simp add: qsplit_def)

lemma qsplit_type [elim!]:
    "[|  p \<in> QSigma(A,B);
         !!x y.[| x \<in> A; y \<in> B(x) |] ==> c(x,y):C(<x;y>)
     |] ==> qsplit(%x y. c(x,y), p) \<in> C(p)"
by auto

lemma expand_qsplit:
 "u \<in> A<*>B ==> R(qsplit(c,u)) \<longleftrightarrow> (\<forall>x\<in>A. \<forall>y\<in>B. u = <x;y> \<longrightarrow> R(c(x,y)))"
apply (simp add: qsplit_def, auto)
done

subsubsection\<open>qsplit for predicates: result type o\<close>

lemma qsplitI: "R(a,b) ==> qsplit(R, <a;b>)"
by (simp add: qsplit_def)

lemma qsplitE:
    "[| qsplit(R,z);  z \<in> QSigma(A,B);
        !!x y. [| z = <x;y>;  R(x,y) |] ==> P
    |] ==> P"
by (simp add: qsplit_def, auto)

lemma qsplitD: "qsplit(R,<a;b>) ==> R(a,b)"
by (simp add: qsplit_def)

subsubsection\<open>qconverse\<close>

lemma qconverseI [intro!]: "<a;b>:r ==> <b;a>:qconverse(r)"
by (simp add: qconverse_def, blast)

lemma qconverseD [elim!]: "<a;b> \<in> qconverse(r) ==> <b;a> \<in> r"
by (simp add: qconverse_def, blast)

lemma qconverseE [elim!]:
    "[| yx \<in> qconverse(r);
        !!x y. [| yx=<y;x>;  <x;y>:r |] ==> P
     |] ==> P"
by (simp add: qconverse_def, blast)

lemma qconverse_qconverse: "r<=QSigma(A,B) ==> qconverse(qconverse(r)) = r"
by blast

lemma qconverse_type: "r \<subseteq> A <*> B ==> qconverse(r) \<subseteq> B <*> A"
by blast

lemma qconverse_prod: "qconverse(A <*> B) = B <*> A"
by blast

lemma qconverse_empty: "qconverse(0) = 0"
by blast

subsection\<open>The Quine-inspired notion of disjoint sum\<close>

lemmas qsum_defs = qsum_def QInl_def QInr_def qcase_def

(** Introduction rules for the injections **)

lemma QInlI [intro!]: "a \<in> A ==> QInl(a) \<in> A <+> B"
by (simp add: qsum_defs, blast)

lemma QInrI [intro!]: "b \<in> B ==> QInr(b) \<in> A <+> B"
by (simp add: qsum_defs, blast)

(** Elimination rules **)

lemma qsumE [elim!]:
    "[| u \<in> A <+> B;
        !!x. [| x \<in> A;  u=QInl(x) |] ==> P;
        !!y. [| y \<in> B;  u=QInr(y) |] ==> P
     |] ==> P"
by (simp add: qsum_defs, blast)

(** Injection and freeness equivalences, for rewriting **)

lemma QInl_iff [iff]: "QInl(a)=QInl(b) \<longleftrightarrow> a=b"
by (simp add: qsum_defs )

lemma QInr_iff [iff]: "QInr(a)=QInr(b) \<longleftrightarrow> a=b"
by (simp add: qsum_defs )

lemma QInl_QInr_iff [simp]: "QInl(a)=QInr(b) \<longleftrightarrow> False"
by (simp add: qsum_defs )

lemma QInr_QInl_iff [simp]: "QInr(b)=QInl(a) \<longleftrightarrow> False"
by (simp add: qsum_defs )

lemma qsum_empty [simp]: "0<+>0 = 0"
by (simp add: qsum_defs )

(*Injection and freeness rules*)

lemmas QInl_inject = QInl_iff [THEN iffD1]
lemmas QInr_inject = QInr_iff [THEN iffD1]
lemmas QInl_neq_QInr = QInl_QInr_iff [THEN iffD1, THEN FalseE, elim!]
lemmas QInr_neq_QInl = QInr_QInl_iff [THEN iffD1, THEN FalseE, elim!]

lemma QInlD: "QInl(a): A<+>B ==> a \<in> A"
by blast

lemma QInrD: "QInr(b): A<+>B ==> b \<in> B"
by blast

(** <+> is itself injective... who cares?? **)

lemma qsum_iff:
     "u \<in> A <+> B \<longleftrightarrow> (\<exists>x. x \<in> A & u=QInl(x)) | (\<exists>y. y \<in> B & u=QInr(y))"
by blast

lemma qsum_subset_iff: "A <+> B \<subseteq> C <+> D \<longleftrightarrow> A<=C & B<=D"
by blast

lemma qsum_equal_iff: "A <+> B = C <+> D \<longleftrightarrow> A=C & B=D"
apply (simp (no_asm) add: extension qsum_subset_iff)
apply blast
done

subsubsection\<open>Eliminator -- qcase\<close>

lemma qcase_QInl [simp]: "qcase(c, d, QInl(a)) = c(a)"
by (simp add: qsum_defs )

lemma qcase_QInr [simp]: "qcase(c, d, QInr(b)) = d(b)"
by (simp add: qsum_defs )

lemma qcase_type:
    "[| u \<in> A <+> B;
        !!x. x \<in> A ==> c(x): C(QInl(x));
        !!y. y \<in> B ==> d(y): C(QInr(y))
     |] ==> qcase(c,d,u) \<in> C(u)"
by (simp add: qsum_defs, auto)

(** Rules for the Part primitive **)

lemma Part_QInl: "Part(A <+> B,QInl) = {QInl(x). x \<in> A}"
by blast

lemma Part_QInr: "Part(A <+> B,QInr) = {QInr(y). y \<in> B}"
by blast

lemma Part_QInr2: "Part(A <+> B, %x. QInr(h(x))) = {QInr(y). y \<in> Part(B,h)}"
by blast

lemma Part_qsum_equality: "C \<subseteq> A <+> B ==> Part(C,QInl) \<union> Part(C,QInr) = C"
by blast

subsubsection\<open>Monotonicity\<close>

lemma QPair_mono: "[| a<=c;  b<=d |] ==> <a;b> \<subseteq> <c;d>"
by (simp add: QPair_def sum_mono)

lemma QSigma_mono [rule_format]:
     "[| A<=C;  \<forall>x\<in>A. B(x) \<subseteq> D(x) |] ==> QSigma(A,B) \<subseteq> QSigma(C,D)"
by blast

lemma QInl_mono: "a<=b ==> QInl(a) \<subseteq> QInl(b)"
by (simp add: QInl_def subset_refl [THEN QPair_mono])

lemma QInr_mono: "a<=b ==> QInr(a) \<subseteq> QInr(b)"
by (simp add: QInr_def subset_refl [THEN QPair_mono])

lemma qsum_mono: "[| A<=C;  B<=D |] ==> A <+> B \<subseteq> C <+> D"
by blast

end


(*  Title:      ZF/UNITY/Increasing.thy
    Author:     Sidi O Ehmety, Cambridge University Computer Laboratory
    Copyright   2001  University of Cambridge

Increasing's parameters are a state function f, a domain A and an order
relation r over the domain A.
*)

section{*Charpentier's "Increasing" Relation*}

theory Increasing imports Constrains Monotonicity begin

definition
  increasing :: "[i, i, i=>i] => i" ("increasing[_]'(_, _')")  where
  "increasing[A](r, f) ==
    {F \<in> program. (\<forall>k \<in> A. F \<in> stable({s \<in> state. <k, f(s)> \<in> r})) &
                (\<forall>x \<in> state. f(x):A)}"

definition
  Increasing :: "[i, i, i=>i] => i" ("Increasing[_]'(_, _')")  where
  "Increasing[A](r, f) ==
    {F \<in> program. (\<forall>k \<in> A. F \<in> Stable({s \<in> state. <k, f(s)> \<in> r})) &
                (\<forall>x \<in> state. f(x):A)}"

abbreviation (input)
  IncWrt ::  "[i=>i, i, i] => i" ("(_ IncreasingWrt _ '/ _)" [60, 0, 60] 60)  where
  "f IncreasingWrt r/A == Increasing[A](r,f)"

(** increasing **)

lemma increasing_type: "increasing[A](r, f) \<subseteq> program"
by (unfold increasing_def, blast)

lemma increasing_into_program: "F \<in> increasing[A](r, f) ==> F \<in> program"
by (unfold increasing_def, blast)

lemma increasing_imp_stable:
"[| F \<in> increasing[A](r, f); x \<in> A |] ==>F \<in> stable({s \<in> state. <x, f(s)>:r})"
by (unfold increasing_def, blast)

lemma increasingD:
"F \<in> increasing[A](r,f) ==> F \<in> program & (\<exists>a. a \<in> A) & (\<forall>s \<in> state. f(s):A)"
apply (unfold increasing_def)
apply (subgoal_tac "\<exists>x. x \<in> state")
apply (auto dest: stable_type [THEN subsetD] intro: st0_in_state)
done

lemma increasing_constant [simp]:
 "F \<in> increasing[A](r, %s. c) \<longleftrightarrow> F \<in> program & c \<in> A"
apply (unfold increasing_def stable_def)
apply (subgoal_tac "\<exists>x. x \<in> state")
apply (auto dest: stable_type [THEN subsetD] intro: st0_in_state)
done

lemma subset_increasing_comp:
"[| mono1(A, r, B, s, g); refl(A, r); trans[B](s)  |] ==>
   increasing[A](r, f) \<subseteq> increasing[B](s, g comp f)"
apply (unfold increasing_def stable_def part_order_def
       constrains_def mono1_def metacomp_def, clarify, simp)
apply clarify
apply (subgoal_tac "xa \<in> state")
prefer 2 apply (blast dest!: ActsD)
apply (subgoal_tac "<f (xb), f (xb) >:r")
prefer 2 apply (force simp add: refl_def)
apply (rotate_tac 5)
apply (drule_tac x = "f (xb) " in bspec)
apply (rotate_tac [2] -1)
apply (drule_tac [2] x = act in bspec, simp_all)
apply (drule_tac A = "act``?u" and c = xa in subsetD, blast)
apply (drule_tac x = "f (xa) " and x1 = "f (xb) " in bspec [THEN bspec])
apply (rule_tac [3] b = "g (f (xb))" and A = B in trans_onD)
apply simp_all
done

lemma imp_increasing_comp:
     "[| F \<in> increasing[A](r, f); mono1(A, r, B, s, g);
         refl(A, r); trans[B](s) |] ==> F \<in> increasing[B](s, g comp f)"
by (rule subset_increasing_comp [THEN subsetD], auto)

lemma strict_increasing:
   "increasing[nat](Le, f) \<subseteq> increasing[nat](Lt, f)"
by (unfold increasing_def Lt_def, auto)

lemma strict_gt_increasing:
   "increasing[nat](Ge, f) \<subseteq> increasing[nat](Gt, f)"
apply (unfold increasing_def Gt_def Ge_def, auto)
apply (erule natE)
apply (auto simp add: stable_def)
done

(** Increasing **)

lemma increasing_imp_Increasing:
     "F \<in> increasing[A](r, f) ==> F \<in> Increasing[A](r, f)"

apply (unfold increasing_def Increasing_def)
apply (auto intro: stable_imp_Stable)
done

lemma Increasing_type: "Increasing[A](r, f) \<subseteq> program"
by (unfold Increasing_def, auto)

lemma Increasing_into_program: "F \<in> Increasing[A](r, f) ==> F \<in> program"
by (unfold Increasing_def, auto)

lemma Increasing_imp_Stable:
"[| F \<in> Increasing[A](r, f); a \<in> A |] ==> F \<in> Stable({s \<in> state. <a,f(s)>:r})"
by (unfold Increasing_def, blast)

lemma IncreasingD:
"F \<in> Increasing[A](r, f) ==> F \<in> program & (\<exists>a. a \<in> A) & (\<forall>s \<in> state. f(s):A)"
apply (unfold Increasing_def)
apply (subgoal_tac "\<exists>x. x \<in> state")
apply (auto intro: st0_in_state)
done

lemma Increasing_constant [simp]:
     "F \<in> Increasing[A](r, %s. c) \<longleftrightarrow> F \<in> program & (c \<in> A)"
apply (subgoal_tac "\<exists>x. x \<in> state")
apply (auto dest!: IncreasingD intro: st0_in_state increasing_imp_Increasing)
done

lemma subset_Increasing_comp:
"[| mono1(A, r, B, s, g); refl(A, r); trans[B](s) |] ==>
   Increasing[A](r, f) \<subseteq> Increasing[B](s, g comp f)"
apply (unfold Increasing_def Stable_def Constrains_def part_order_def
       constrains_def mono1_def metacomp_def, safe)
apply (simp_all add: ActsD)
apply (subgoal_tac "xb \<in> state & xa \<in> state")
 prefer 2 apply (simp add: ActsD)
apply (subgoal_tac "<f (xb), f (xb) >:r")
prefer 2 apply (force simp add: refl_def)
apply (rotate_tac 5)
apply (drule_tac x = "f (xb) " in bspec)
apply simp_all
apply clarify
apply (rotate_tac -2)
apply (drule_tac x = act in bspec)
apply (drule_tac [2] A = "act``?u" and c = xa in subsetD, simp_all, blast)
apply (drule_tac x = "f (xa) " and x1 = "f (xb) " in bspec [THEN bspec])
apply (rule_tac [3] b = "g (f (xb))" and A = B in trans_onD)
apply simp_all
done

lemma imp_Increasing_comp:
 "[| F \<in> Increasing[A](r, f); mono1(A, r, B, s, g); refl(A, r); trans[B](s) |]
  ==> F \<in> Increasing[B](s, g comp f)"
apply (rule subset_Increasing_comp [THEN subsetD], auto)
done

lemma strict_Increasing: "Increasing[nat](Le, f) \<subseteq> Increasing[nat](Lt, f)"
by (unfold Increasing_def Lt_def, auto)

lemma strict_gt_Increasing: "Increasing[nat](Ge, f)<= Increasing[nat](Gt, f)"
apply (unfold Increasing_def Ge_def Gt_def, auto)
apply (erule natE)
apply (auto simp add: Stable_def)
done

(** Two-place monotone operations **)

lemma imp_increasing_comp2:
"[| F \<in> increasing[A](r, f); F \<in> increasing[B](s, g);
    mono2(A, r, B, s, C, t, h); refl(A, r); refl(B, s); trans[C](t) |]
 ==> F \<in> increasing[C](t, %x. h(f(x), g(x)))"
apply (unfold increasing_def stable_def
       part_order_def constrains_def mono2_def, clarify, simp)
apply clarify
apply (rename_tac xa xb)
apply (subgoal_tac "xb \<in> state & xa \<in> state")
 prefer 2 apply (blast dest!: ActsD)
apply (subgoal_tac "<f (xb), f (xb) >:r & <g (xb), g (xb) >:s")
prefer 2 apply (force simp add: refl_def)
apply (rotate_tac 6)
apply (drule_tac x = "f (xb) " in bspec)
apply (rotate_tac [2] 1)
apply (drule_tac [2] x = "g (xb) " in bspec)
apply simp_all
apply (rotate_tac -1)
apply (drule_tac x = act in bspec)
apply (rotate_tac [2] -3)
apply (drule_tac [2] x = act in bspec, simp_all)
apply (drule_tac A = "act``?u" and c = xa in subsetD)
apply (drule_tac [2] A = "act``?u" and c = xa in subsetD, blast, blast)
apply (rotate_tac -4)
apply (drule_tac x = "f (xa) " and x1 = "f (xb) " in bspec [THEN bspec])
apply (rotate_tac [3] -1)
apply (drule_tac [3] x = "g (xa) " and x1 = "g (xb) " in bspec [THEN bspec])
apply simp_all
apply (rule_tac b = "h (f (xb), g (xb))" and A = C in trans_onD)
apply simp_all
done

lemma imp_Increasing_comp2:
"[| F \<in> Increasing[A](r, f); F \<in> Increasing[B](s, g);
  mono2(A, r, B, s, C, t, h); refl(A, r); refl(B, s); trans[C](t) |] ==>
  F \<in> Increasing[C](t, %x. h(f(x), g(x)))"
apply (unfold Increasing_def stable_def
       part_order_def constrains_def mono2_def Stable_def Constrains_def, safe)
apply (simp_all add: ActsD)
apply (subgoal_tac "xa \<in> state & x \<in> state")
prefer 2 apply (blast dest!: ActsD)
apply (subgoal_tac "<f (xa), f (xa) >:r & <g (xa), g (xa) >:s")
prefer 2 apply (force simp add: refl_def)
apply (rotate_tac 6)
apply (drule_tac x = "f (xa) " in bspec)
apply (rotate_tac [2] 1)
apply (drule_tac [2] x = "g (xa) " in bspec)
apply simp_all
apply clarify
apply (rotate_tac -2)
apply (drule_tac x = act in bspec)
apply (rotate_tac [2] -3)
apply (drule_tac [2] x = act in bspec, simp_all)
apply (drule_tac A = "act``?u" and c = x in subsetD)
apply (drule_tac [2] A = "act``?u" and c = x in subsetD, blast, blast)
apply (rotate_tac -9)
apply (drule_tac x = "f (x) " and x1 = "f (xa) " in bspec [THEN bspec])
apply (rotate_tac [3] -1)
apply (drule_tac [3] x = "g (x) " and x1 = "g (xa) " in bspec [THEN bspec])
apply simp_all
apply (rule_tac b = "h (f (xa), g (xa))" and A = C in trans_onD)
apply simp_all
done

end


(* Title: thys/SimpleGoedelEncoding.thy
   Author: Franz Regensburger (FABR) 02/2022

   - For the proof of the undecidability of the special halting problems K1 and K0
     we need some arbitrary injective encoding from Turing machines into the
     natural numbers.
 *)

section \<open>Halting Problems: do Turing Machines for deciding Termination exist?\<close>

text \<open>In this section we will show that there cannot exist Turing Machines that are able
to decide the termination of some other arbitrary Turing Machine.\<close>

subsection \<open>A simple Gödel Encoding for Turing machines\<close>

theory SimpleGoedelEncoding
  imports
     Turing_HaltingConditions
    "HOL-Library.Nat_Bijection"
begin

(* -------------------------------------------------------------------------- *)

declare adjust.simps[simp del]

declare seq_tm.simps [simp del]
declare shift.simps[simp del]
declare composable_tm.simps[simp del]
declare step.simps[simp del]
declare steps.simps[simp del]

subsubsection \<open>Some general results on injective functions and their inversion\<close>

lemma dec_is_inv_on_A:
   "dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (THE t. t\<in>A \<and> enc t = w) else (SOME t. t \<in> A)))
    \<Longrightarrow> dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (the_inv_into A enc) w else (SOME t. t \<in> A)))"
  by (auto simp add: the_inv_into_def)

lemma encode_decode_A_eq:
  "\<lbrakk> inj_on (enc::'a \<Rightarrow>'b) (A::'a set);
     (dec::'b \<Rightarrow> 'a) = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w)
                             then (THE t. t\<in>A \<and> enc t = w)
                             else (SOME t. t \<in> A)))
   \<rbrakk> \<Longrightarrow> \<forall>M\<in>A. dec(enc M) = M"
proof
  fix M
  assume inj_enc: "inj_on enc A"
    and dec_def: "dec = (\<lambda>w. if \<exists>t\<in>A. enc t = w then THE t. t \<in> A \<and> enc t = w else SOME t. t \<in> A)"
    and M_in_A: "M \<in> A"
  show "dec (enc M) = M"
  proof -
    from dec_def have
      dec_def': "dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (the_inv_into A enc) w else (SOME t. t \<in> A)))"
      by (rule dec_is_inv_on_A)
    from M_in_A have "\<exists>t\<in>A. enc t = (enc M)" by auto
    with M_in_A inj_enc and dec_def' show "dec (enc M) = M" by (auto simp add: the_inv_into_f_f)
  qed
qed

lemma decode_encode_A_eq:
  "\<lbrakk> inj_on (enc::'a \<Rightarrow>'b) (A::'a set);
    dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (THE t. t\<in>A \<and> enc t = w) else (SOME t. t \<in> A)))\<rbrakk>
  \<Longrightarrow> \<forall>w. w \<in> enc`A \<longrightarrow> enc(dec(w)) = w"
proof
  fix w
  assume inj_enc: "inj_on enc A"
    and dec_def: "dec = (\<lambda>w. if \<exists>t\<in>A. enc t = w then THE t. t \<in> A \<and> enc t = w else SOME t. t \<in> A)"
  show "w \<in> enc ` A \<longrightarrow> enc (dec w) = w"
  proof
    assume "w \<in> enc ` A"
    from dec_def have
      dec_def': "dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (the_inv_into A enc) w else (SOME t. t \<in> A)))"
      by (rule dec_is_inv_on_A)
    with \<open>w \<in> enc ` A\<close> and inj_enc
    show "enc (dec w) = w"
      by (auto simp add: the_inv_into_f_f)
  qed
qed

lemma dec_in_A:
  "\<lbrakk>inj_on (enc::'a \<Rightarrow>'b) (A::'a set);
   dec = (\<lambda>w. if \<exists>t\<in>A. enc t = w then THE t. t \<in> A \<and> enc t = w else SOME t. t \<in> A);
   A \<noteq> {} \<rbrakk>
  \<Longrightarrow> \<forall>w. dec w \<in> A"
proof
  fix w
  assume inj_enc: "inj_on enc A"
    and dec_def: "dec = (\<lambda>w. if \<exists>t\<in>A. enc t = w then THE t. t \<in> A \<and> enc t = w else SOME t. t \<in> A)"
    and not_empty_A: "A \<noteq> {}"
  show "dec w \<in> A"
  proof (cases "\<exists>t\<in>A. enc t = w")
    assume "\<exists>t\<in>A. enc t = w"
    from dec_def have
      dec_def': "dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (the_inv_into A enc) w else (SOME t. t \<in> A)))"
      by (rule dec_is_inv_on_A)
    with \<open>\<exists>t\<in>A. enc t = w\<close> inj_enc show ?thesis by (auto simp add: the_inv_into_f_f)
  next
    assume "\<not>(\<exists>t\<in>A. enc t = w)"
    from dec_def have
      dec_def': "dec = (\<lambda>w. (if (\<exists>t\<in>A. enc t = w) then (the_inv_into A enc) w else (SOME t. t \<in> A)))"
      by (rule dec_is_inv_on_A)
    with \<open>\<not>(\<exists>t\<in>A. enc t = w)\<close> have "dec w = (SOME t. t \<in> A)" by auto
    from not_empty_A have "\<exists>x. x \<in> A" by auto
    then have "(SOME t. t \<in> A) \<in> A" by (rule someI_ex)
    with \<open>dec w = (SOME t. t \<in> A)\<close> show ?thesis by auto
  qed
qed

subsubsection \<open>An injective encoding of Turing Machines into the natural number\<close>

text \<open>
  We define an injective encoding function from Turing machines to natural numbers.
  This encoding function is only used for the proof of the undecidability of
  the special halting problem K where we use a locale that postulates the existence of
  some injective encoding of the Turing machines into the natural numbers.
\<close>

fun tm_to_nat_list ::  "tprog0 \<Rightarrow> nat list"
  where
    "tm_to_nat_list []              = []" |
    "tm_to_nat_list ((WB  ,s) # is) = 0 # s #  tm_to_nat_list is" |
    "tm_to_nat_list ((WO  ,s) # is) = 1 # s #  tm_to_nat_list is" |
    "tm_to_nat_list ((L   ,s) # is) = 2 # s #  tm_to_nat_list is" |
    "tm_to_nat_list ((R   ,s) # is) = 3 # s #  tm_to_nat_list is" |
    "tm_to_nat_list ((Nop ,s) # is) = 4 # s #  tm_to_nat_list is"

lemma prefix_tm_to_nat_list_cons:
 "\<exists>u v. tm_to_nat_list (x#xs) = u # v # tm_to_nat_list xs"
proof (cases x)
  case (Pair a b)
  then show ?thesis by (cases a)(auto)
qed

lemma tm_to_nat_list_cons_is_not_nil: "tm_to_nat_list (x#xs) \<noteq> tm_to_nat_list []"
proof
  assume "tm_to_nat_list (x # xs) = tm_to_nat_list []"
  moreover have "\<exists>u v. tm_to_nat_list (x#xs) = u # v # tm_to_nat_list xs"
    by (rule prefix_tm_to_nat_list_cons)
  ultimately show False by auto
qed

lemma inj_in_fst_arg_tm_to_nat_list:
 "tm_to_nat_list (x # xs) = tm_to_nat_list (y # xs) \<Longrightarrow> x = y"
proof (cases x, cases y)
  case (Pair a b)
  fix a1 s1 a2 s2
  assume "tm_to_nat_list (x # xs) = tm_to_nat_list (y # xs)"
  and "x = (a1, s1)" and "y = (a2, s2)"
  then show ?thesis by  (cases a1; cases a2)(auto)
qed

lemma inj_tm_to_nat_list: "tm_to_nat_list xs = tm_to_nat_list ys \<longrightarrow> xs = ys"
proof (induct xs ys rule:  list_induct2')
  case 1
  then show ?case by blast
next
  case (2 x xs)
  then show ?case
  proof
    assume "tm_to_nat_list (x # xs) = tm_to_nat_list []"
    then have False using tm_to_nat_list_cons_is_not_nil by auto
    then show "x # xs = []" by auto
  qed
next
  case (3 y ys)
  then show ?case
  proof
    assume "tm_to_nat_list [] = tm_to_nat_list (y # ys)"
    then have "tm_to_nat_list (y # ys) = tm_to_nat_list []" by (rule sym)
    then have False using tm_to_nat_list_cons_is_not_nil by auto
    then show "[] = y # ys" by auto
  qed
next
  case (4 x xs y ys)
  then have IH: "tm_to_nat_list xs = tm_to_nat_list ys \<longrightarrow> xs = ys" .
  show ?case
  proof
    assume A: "tm_to_nat_list (x # xs) = tm_to_nat_list (y # ys)"
    have "\<exists>u v. tm_to_nat_list (x#xs) = u # v # tm_to_nat_list xs"
      by (rule prefix_tm_to_nat_list_cons)
    then obtain u1 v1 where w_u1_v1: "tm_to_nat_list (x#xs) = u1 # v1 # tm_to_nat_list xs"
      by blast
    have "\<exists>u v. tm_to_nat_list (y#ys) = u # v # tm_to_nat_list ys"
      by (rule prefix_tm_to_nat_list_cons)
    then obtain u2 v2 where w_u2_v2: "tm_to_nat_list (y#ys) = u2 # v2 # tm_to_nat_list ys"
      by blast
    from A and w_u1_v1 and w_u2_v2 have "tm_to_nat_list xs = tm_to_nat_list ys" by auto
    with IH have "xs = ys" by auto
    moreover with A have "x=y" using inj_in_fst_arg_tm_to_nat_list by auto
    ultimately show "x # xs = y # ys" by auto
  qed
qed

definition tm_to_nat ::  "tprog0 \<Rightarrow> nat"
  where "tm_to_nat = (list_encode \<circ> tm_to_nat_list)"

theorem inj_tm_to_nat: "inj tm_to_nat"
  unfolding tm_to_nat_def
proof  (rule inj_compose)
  show "inj list_encode" by (rule inj_list_encode)
next
  show "inj tm_to_nat_list"
    unfolding inj_def by (auto simp add: inj_tm_to_nat_list)
qed

(* --- For demo purposes in classes we provide some inverse functions, explicitly --- *)

(* Note:
 * For cases where we argument list cannot be the image of nat_list_to_tm
 * we choose some arbitrary but fixed value.
 * Here we choose [(Nop, 0)].
 * However, any instruction list would do the job, we.g. [].
 *)

fun nat_list_to_tm      :: "nat list \<Rightarrow> tprog0"
  where
    "nat_list_to_tm  [] =  []"
  | "nat_list_to_tm  [ac] = [(Nop, 0)]"
  | "nat_list_to_tm  (ac # s # ns) = (
           if ac < 5
           then ([WB,WO,L,R,Nop]!ac ,s) # nat_list_to_tm ns
           else [(Nop, 0)])"

(* -- *)

lemma  nat_list_to_tm_is_inv_of_tm_to_nat_list: "nat_list_to_tm (tm_to_nat_list ns) = ns"
proof (induct ns)
  case Nil
  then show ?case by auto
next
  case (Cons a ns)
  fix instr ns
  assume IV: "nat_list_to_tm (tm_to_nat_list ns) = ns"
  show "nat_list_to_tm (tm_to_nat_list (instr # ns)) = instr # ns"
  proof (cases instr)
    case (Pair ac s)
    then have "instr = (ac, s)" .
    with Pair IV show "nat_list_to_tm (tm_to_nat_list (instr # ns)) = instr # ns"
      by (cases ac; cases s) auto
  qed
qed

definition nat_to_tm ::  "nat \<Rightarrow> tprog0"
  where "nat_to_tm = (nat_list_to_tm \<circ> list_decode)"

(* The function nat_to_tm is an explicit witness for the function ct2,
   which we define by non-constructive logic in theory HaltingProblems_K_H
   by

    definition c2t :: "nat \<Rightarrow> instr list"
      where
        "c2t = (\<lambda>n. if (\<exists>p. t2c p = n)
                   then (THE  p. t2c p = n)
                   else (SOME p. True) )"  <-- some arbitrary but fixed value
*)

(* Compare the next lemma to
    lemma c2t_comp_t2c_eq: "c2t (t2c p) = p"
   in theory HaltingProblems_K_H
 *)

lemma nat_to_tm_is_inv_of_tm_to_nat: "nat_to_tm (tm_to_nat tm) = tm"
  by (simp add: nat_list_to_tm_is_inv_of_tm_to_nat_list nat_to_tm_def tm_to_nat_def)

end


(*  Title:       Isabelle Collections Library
    Author:      Peter Lammich <peter dot lammich at uni-muenster.de>
    Maintainer:  Peter Lammich <peter dot lammich at uni-muenster.de>
*)
(*<*)
theory ICF_Userguide
imports
  "../ICF/Collections"
  "../Lib/Code_Target_ICF"
begin
(*>*)

text_raw {*\isasection{Isabelle Collections Framework Userguide}\label{thy:Userguide}*}

section "Introduction"
text {*
  This is the Userguide for the (old) Isabelle Collection Framework.
  It does not cover the Generic Collection Framework, nor the
  Automatic Refinement Framework.

  The Isabelle Collections Framework defines interfaces of various collection types and provides some standard implementations and generic algorithms.

  The relation between the data structures of the collection framework and standard Isabelle types (e.g. for sets and maps) is established by abstraction functions.

  Amongst others, the following interfaces and data-structures are provided by the Isabelle Collections Framework (For a complete list, see the overview section
  in the implementations chapter of the proof document):
  \begin{itemize}
    \item Set and map implementations based on (associative) lists, red-black trees, hashing and tries.
    \item An implementation of a FIFO-queue based on two stacks.
    \item Annotated lists implemented by finger trees.
    \item Priority queues implemented by binomial heaps, skew binomial heaps, and annotated lists (via finger trees).
  \end{itemize}

  The red-black trees are imported from the standard isabelle library. The binomial and skew binomial heaps are
  imported from the {\em Binomial-Heaps} entry of the archive of formal proofs. The finger trees are imported from
  the {\em Finger-Trees} entry of the archive of formal proofs.
*}

subsection "Getting Started"
text {*
  To get started with the Isabelle Collections Framework (assuming that you are already familiar with Isabelle/HOL and Isar),
  you should first read the introduction (this section), that provides many basic examples. More examples are in the examples/ subdirectory of the collection
  framework.
  Section~\ref{sec:userguide.structure} explains the concepts of the Isabelle Collections Framework in more detail.
  Section~\ref{sec:userguide.ext} provides information on extending the framework along with detailed examples, and
  Section~\ref{sec:userguide.design} contains a discussion on the design of this framework.
  There is also a paper \cite{LammichLochbihler2010ITP} on the design of the Isabelle Collections Framework available.
*}

subsection "Introductory Example"
text {*
  We introduce the Isabelle Collections Framework by a simple example.

  Given a set of elements represented by a red-black tree, and a list,
  we want to filter out all elements that are not contained in the set.
  This can be done by Isabelle/HOL's @{const filter}-function\footnote{Note that Isabelle/HOL uses the list comprehension syntax @{term [source] "[x\<leftarrow>l. P x]"}
  as syntactic sugar for filtering a list.}:
*}

definition rbt_restrict_list :: "'a::linorder rs \<Rightarrow> 'a list \<Rightarrow> 'a list"
where "rbt_restrict_list s l == [ x\<leftarrow>l. rs.memb x s ]"

text {*
  The type @{typ "'a rs"} is the type of sets backed by red-black trees.
  Note that the element type of sets backed by red-black trees must be
  of sort @{text linorder}.
  The function @{const rs.memb} tests membership on such sets.
*}

text {* Next, we show correctness of our function: *}
lemma rbt_restrict_list_correct:
  assumes [simp]: "rs.invar s"
  shows "rbt_restrict_list s l = [x\<leftarrow>l. x\<in>rs.\<alpha> s]"
  by (simp add: rbt_restrict_list_def rs.memb_correct)

text {*
  The lemma @{thm [source] rs.memb_correct}: @{thm [display] rs.memb_correct[no_vars]}

  states correctness of the @{const rs.memb}-function.
  The function @{const rs.\<alpha>} maps a red-black-tree to the set that it represents.
  Moreover, we have to explicitely keep track of the invariants of the used data structure,
  in this case red-black trees.
  The premise @{thm (prem 1) rs.memb_correct} represents the invariant assumption for the collection data structure.
  Red-black-trees are invariant-free, so this defaults to @{term "True"}.
  For uniformity reasons, these (unnecessary) invariant assumptions are present in all correctness lemmata.

  Many of the correctness lemmas for standard RBT-set-operations are summarized by the lemma @{thm [source] rs.correct}:
    @{thm [display] rs.correct[no_vars]}
*}

text {*
  All implementations provided by this library are compatible with the Isabelle/HOL code-generator.
  Now follow some examples of using the code-generator.
  Note that the code generator can only generate code for plain constants
  without arguments, while the operations like @{const rs.memb} have arguments,
  that are only hidden by an abbreviation.
*}

text {*
  There are conversion functions from lists to sets and, vice-versa, from sets to lists:
*}

definition "conv_tests \<equiv> (
  rs.from_list [1::int .. 10],
  rs.to_list (rs.from_list [1::int .. 10]),
  rs.to_sorted_list (rs.from_list [1::int,5,6,7,3,4,9,8,2,7,6]),
  rs.to_rev_list (rs.from_list [1::int,5,6,7,3,4,9,8,2,7,6])
)"

ML_val {* @{code conv_tests} *}

text {*
  Note that sets make no guarantee about ordering, hence the only thing we can
  prove about conversion from sets to lists is:
    @{thm [source] rs.to_list_correct}: @{thm [display] rs.to_list_correct[no_vars]}

  Some sets, like red-black-trees, also support conversion to sorted lists,
  and we have:
    @{thm [source] rs.to_sorted_list_correct}: @{thm [display] rs.to_sorted_list_correct[no_vars]} and
    @{thm [source] rs.to_rev_list_correct}: @{thm [display] rs.to_rev_list_correct[no_vars]}
*}

definition "restrict_list_test \<equiv> rbt_restrict_list (rs.from_list [1::nat,2,3,4,5]) [1::nat,9,2,3,4,5,6,5,4,3,6,7,8,9]"

ML_val {* @{code restrict_list_test} *}

definition "big_test n = (rs.from_list [(1::int)..n])"

ML_val {* @{code big_test} (@{code int_of_integer} 9000) *}

subsection "Theories"
text {*
  To make available the whole collections framework to your formalization,
  import the theory @{theory Collections} which includes everything. Here is a
  small selection:
  \begin{description}
    \item[@{theory SetSpec}] Specification of sets and set functions
    \item[@{theory SetGA}] Generic algorithms for sets
    \item[@{theory SetStdImpl}] Standard set implementations (list, rb-tree, hashing, tries)
    \item[@{theory MapSpec}] Specification of maps
    \item[@{theory MapGA}] Generic algorithms for maps
    \item[@{theory MapStdImpl}] Standard map implementations (list,rb-tree, hashing, tries)
    \item[@{theory ListSpec}] Specification of lists
    \item[@{theory Fifo}] Amortized fifo queue
    \item[@{theory DatRef}] Data refinement for the while combinator
  \end{description}

*}

subsection "Iterators"
text {* An important concept when using collections are iterators. An iterator is a kind of generalized fold-functional.
  Like the fold-functional, it applies a function to all elements of a set and modifies a state. There are
  no guarantees about the iteration order. But, unlike the fold functional, you can prove useful properties of iterations
  even if the function is not left-commutative. Proofs about iterations are done in invariant style, establishing an
  invariant over the iteration.

  The iterator combinator for red-black tree sets is @{const rs.iterate}, and the proof-rule that is usually used is:
    @{thm [source] rs.iteratei_rule_P}: @{thm [display] rs.iteratei_rule_P[no_vars]}

  The invariant @{term I} is parameterized with the set of remaining elements that have not yet been iterated over and the
  current state. The invariant has to hold for all elements remaining and the initial state: @{term "I (rs.\<alpha> S) \<sigma>0"}.
  Moreover, the invariant has to be preserved by an iteration step:
    @{term [display] "\<And>x it \<sigma>. \<lbrakk>x \<in> it; it \<subseteq> rs.\<alpha> S; I it \<sigma>\<rbrakk> \<Longrightarrow> I (it - {x}) (f x \<sigma>)"}
  And the proposition to be shown for the final state must be a consequence of the invarant for no
  elements remaining: @{term "\<And>\<sigma>. I {} \<sigma> \<Longrightarrow> P \<sigma>"}.

  A generalization of iterators are {\em interruptible iterators} where iteration is only continues while some condition on the state holds.
  Reasoning over interruptible iterators is also done by invariants:
    @{thm [source] rs.iteratei_rule_P}: @{thm [display] rs.iteratei_rule_P[no_vars]}

  Here, interruption of the iteration is handled by the premise
    @{term [display] "\<And>\<sigma> it. \<lbrakk>it \<subseteq> rs.\<alpha> S; it \<noteq> {}; \<not> c \<sigma>; I it \<sigma>\<rbrakk> \<Longrightarrow> P \<sigma>"}
  that shows the proposition from the invariant for any intermediate state of the
  iteration where the continuation condition
  does not hold (and thus the iteration is interrupted).
*}

text {*
  As an example of reasoning about results of iterators, we implement a function
  that converts a hashset to a list that contains precisely the elements of the set.
*}

definition "hs_to_list' s == hs.iteratei s (\<lambda>_. True) (op #) []"

text {*
  The correctness proof works by establishing the invariant that the list contains
  all elements that have already been iterated over.
  Again @{term "hs.invar s"} denotes the invariant for hashsets which defaults to @{term "True"}.
*}
lemma hs_to_list'_correct:
  assumes INV: "hs.invar s"
  shows "set (hs_to_list' s) = hs.\<alpha> s"
  apply (unfold hs_to_list'_def)
  apply (rule_tac
    I="\<lambda>it \<sigma>. set \<sigma> = hs.\<alpha> s - it"
    in hs.iterate_rule_P[OF INV])
  txt {* The resulting proof obligations are easily discharged using auto: *}
  apply auto
  done

text {*
  As an example for an interruptible iterator,
  we define a bounded existential-quantification over the list elements.
  As soon as the first element is found that fulfills the predicate,
  the iteration is interrupted.
  The state of the iteration is simply a boolean, indicating the (current) result of the quantification:
*}

definition "hs_bex s P == hs.iteratei s (\<lambda>\<sigma>. \<not> \<sigma>) (\<lambda>x \<sigma>. P x) False"

lemma hs_bex_correct:
  "hs.invar s \<Longrightarrow> hs_bex s P \<longleftrightarrow> (\<exists>x\<in>hs.\<alpha> s. P x)"
  apply (unfold hs_bex_def)
  txt {* The invariant states that the current result matches the result of the quantification
    over the elements already iterated over: *}
  apply (rule_tac
    I="\<lambda>it \<sigma>. \<sigma> \<longleftrightarrow> (\<exists>x\<in>hs.\<alpha> s - it. P x)"
    in hs.iteratei_rule_P)
  txt {* The resulting proof obligations are easily discharged by auto: *}
  apply auto
  done

section "Structure of the Framework"
text_raw {*\label{sec:userguide.structure}*}
text {*
  The concepts of the framework are roughly based on the object-oriented concepts of interfaces, implementations and generic algorithms.

  The concepts used in the framework are the following:
  \begin{description}
    \item[Interfaces] An interface describes some concept by providing an abstraction mapping $\alpha$ to a related Isabelle/HOL-concept.
      The definition is generic in the datatype used to implement the concept (i.e. the concrete data structure). An interface is specified by means
      of a locale that fixes the abstraction mapping and an invariant.
      For example, the set-interface contains an abstraction mapping to sets, and is specified by the locale @{text SetSpec.set}.
      An interface roughly matches the concept of a (collection) interface in Java, e.g. {\em java.util.Set}.

    \item[Functions] A function specifies some functionality involving interfaces. A function is specified by means of a locale.
                      For example, membership query for a set is specified by the locale @{const [source] SetSpec.set_memb} and
                      equality test between two sets is a function specified by @{const [source] SetSpec.set_equal}.
                      A function roughly matches a method declared in an interface, e.g. {\em java.util.Set\#contains, java.util.Set\#equals}.

    \item[Operation Records] In order to reference an interface with a standard
      set of operations, those operations are summarized in a record, and there
      is a locale that fixes this record, and makes available all operations.
      For example, the locale @{const [source] SetSpec.StdSet} fixes a record
      of standard set operations and assumes their correctness. It also defines
      abbreviations to easily access the members of the record. Internally,
      all the standard operations, like @{const hs.memb}, are introduced by
      interpretation of such an operation locale.

    \item[Generic Algorithms] A generic algorithm specifies, in a generic way,
      how to implement a function using other functions. Usually, a generic
      algorithm lives in a locale that imports the necessary operation locales.
      For example, the locale @{const SetGA.cart_loc} defines a generic
      algorithm for the cartesian product between two sets.

      There is no direct match of generic algorithms in the Java
      Collections Framework. The most related concept are abstract
      collection interfaces, that provide some default algorithms,
      e.g. {\em java.util.AbstractSet}.  The concept of {\em Algorithm} in
      the C++ Standard Template Library \cite{C++STL} matches the concept
      of Generic Algorithm quite well.

    \item[Implementation] An implementation of an interface provides a
       data structure for that interface together with an abstraction
       mapping and an invariant. Moreover, it provides implementations
       for some (or all) functions of that interface.  For example,
       red-black trees are an implementation of the set-interface,
       with the abstraction mapping @{const rs.\<alpha>} and invariant
       @{const rs.invar}; and the constant @{const rs.ins} implements
       the insert-function, as can be verified by
       @{lemma "set_ins rs.\<alpha> rs.invar rs.ins" by unfold_locales}.
       An implementation matches a concrete collection
       interface in Java, e.g. {\em java.util.TreeSet}, and the
       methods implemented by such an interface, e.g. {\em
       java.util.TreeSet\#add}.

    \item[Instantiation] An instantiation of a generic algorithm
        provides actual implementations for the used functions. For
        example, the generic cartesian-product algorithm can be
        instantiated to use red-black-trees for both arguments, and output
        a list, as will be illustrated below in Section~\ref{sec:inst_gen_algo}.
        While some of the functions
        of an implementation need to be implemented specifically, many
        functions may be obtained by instantiating generic algorithms.
        In Java, instantiation of a generic algorithm is matched most
        closely by inheriting from an abstract collection
        interface. In the C++ Standard Template Library instantiation
        of generic algorithms is done implicitely by the compiler.

  \end{description}

*}

  subsection "Instantiation of Generic Algorithms" text_raw {*\label{sec:inst_gen_algo}*}

  text {* A generic algorithm is instantiated by interpreting its locale with
    the wanted implementations. For example, to obtain a cartesian product
    between two red-black trees, yielding a list, we can do the following: *}
  setup Locale_Code.open_block
  interpretation rrl: cart_loc rs_ops rs_ops ls_ops by unfold_locales
  setup Locale_Code.close_block
  setup {* ICF_Tools.revert_abbrevs "rrl" *}

  text {* It is then available under the expected name: *}
  term "rrl.cart"

  text {* Note the three lines of boilerplate code, that work around some
    technical problems of Isabelle/HOL: The @{text Locale_Code.open_block} and
    @{text Locale_Code.close_block} commands set up code generation for any
    locale that is interpreted in between them. They also have to be specified
    if an existing locale that already has interpretations is extended by
    new definitions.

    The @{text "ICF_Tools.revert_abbrevs \"rrl\""} reverts all
    abbreviations introduced by the locale, such that the displayed
    information becomes nicer.
    *}

  subsection "Naming Conventions"
  text {*
    The Isabelle Collections Framework follows these general naming conventions.
    Each implementation has a two-letter (or three-letter) and a one-letter (or two-letter) abbreviation, that are used as prefixes for the related constants, lemmas and instantiations.

    The two-letter and three-letter abbreviations should be unique over all interfaces and instantiations, the one-letter abbreviations should be unique
    over all implementations of the same interface.
    Names that reference the implementation of only one interface are prefixed with that implementation's two-letter abbreviation (e.g. @{const hs.ins} for insertion into a HashSet (hs,h)),
    names that reference more than one implementation are prefixed with the one-letter (or two-letter) abbreviations (e.g. @{const rrl.cart} for the cartesian
    product between two RBT-Sets, yielding a list-set)

    The most important abbreviations are:
    \begin{description}
      \item[lm,l] List Map
      \item[lmi,li] List Map with explicit invariant
      \item[rm,r] RB-Tree Map
      \item[hm,h] Hash Map
      \item[ahm,a] Array-based hash map
      \item[tm,t] Trie Map
      \item[ls,l] List Set
      \item[lsi,li] List Set with explicit invariant
      \item[rs,r] RB-Tree Set
      \item[hs,h] Hash Set
      \item[ahs,a] Array-based hash map
      \item[ts,t] Trie Set
    \end{description}

    Each function @{text name} of an interface @{text interface} is declared in a locale @{text interface_name}. This locale provides a fact @{text name_correct}. For example, there is the locale @{const set_ins} providing
    the fact @{thm [source] set_ins.ins_correct}.
    An implementation instantiates the locales of all implemented functions, using its two-letter abbreviation as instantiation prefix. For example, the HashSet-implementation instantiates the locale @{const set_ins}
    with the prefix {\em hs}, yielding the lemma @{thm [source] hs.ins_correct}. Moreover, an implementation with two-letter abbreviation {\em aa} provides a lemma @{text aa.correct}
    that summarizes the correctness facts for the basic
    operations. It should only contain those facts that are safe to be used with the simplifier. E.g., the correctness facts for basic operations on hash sets are available via the lemma @{thm [source] hs.correct}.

  *}

section "Extending the Framework"
text_raw {*\label{sec:userguide.ext}*}
text {*
  The best way to add new features, i.e., interfaces, functions,
  generic algorithms, or implementations to the collection framework is to use
  one of the existing items as example.
*}

section "Design Issues"
text_raw {*\label{sec:userguide.design}*}
  text {*
    In this section, we motivate some of the design decisions of the Isabelle Collections Framework and report our experience with alternatives.
    Many of the design decisions are justified by restrictions of Isabelle/HOL and the code generator, so that there may be better
    options if those restrictions should vanish from future releases of Isabelle/HOL.
    *}

  text {*
    The main design goals of this development are:
    \begin{enumerate}
      \item\label{dg_unified} Make available various implementations of collections under a unified interface.
      \item\label{dg_extensible} It should be easy to extend the framework by new interfaces, functions, algorithms, and implementations.
      \item\label{dg_concise} Allow simple and concise reasoning over functions using collections.
      \item\label{dg_genalgo} Allow generic algorithms, that are independent of the actual data structure that is used.
      \item\label{dg_exec} Support generation of executable code.
      \item\label{dg_control} Let the user precisely control what data structures are used in the implementation.
    \end{enumerate}
    *}

  subsection {* Data Refinement *}
  text {*
    In order to allow simple reasoning over collections, we use a data refinement approach. Each collection
    interface has an abstraction function that maps it on a related Isabelle/HOL concept (abstract level).
    The specification of functions are also relative to the abstraction.
    This allows most of the correctness reasoning to be done on the abstract level. On this level,
    the tool support is more elaborated and one is not yet fixed to a concrete implementation.
    In a next step, the abstract specification is refined to use an actual implementation (concrete level). The correctness properties
    proven on the abstract level usually transfer easily to the concrete level.

    Moreover, the user has precise control how the refinement is done, i.e. what data structures are used. An alternative would be to do refinement
    completely automatic, as e.g. done in the code generator setup of the Theory~{\em Executable-Set}. This has the advantage that it induces less writing overhead.
    The disadvantage is that the user looses a great amount of control over the refinement. For example, in {\em Executable-Set}, all sets have to be represented by lists,
    and there is no possibility to represent one set differently from another.

    For a more detailed discussion of the data refinement issue, we refer to
    the monadic refinement framework, that is available in the AFP
    (@{url "http://afp.sourceforge.net/entries/Refine_Monadic.shtml"})
    *}

  subsection {* Operation Records *}
  text {*
    In order to allow convenient access to the most frequently used functions
    of an interface,
    we have grouped them together in a record, and defined a locale that only
    fixes this record. This greatly reduces the boilerplate required to define
    a new (generic) algorithm, as only the operation locale (instead of every
    single function) has to be included in the locale for the generic algorithm.

    Note however, that parameters of locales are monomorphic inside the locale.
    Thus, we have to import an own instance for the locale for every element
    type of a set, or key/value type of a map.
    For iterators, where this problem was most annoying, we have installed a
    workaround that allows polymorphic iterators even inside locales.
    *}

  subsection {* Locales for Generic Algorithms *}
  text {*
    A generic algorithm is defined within a locale, that includes the required
    functions (or operation locales). If many instances of the same interface
    are required, prefixes are used to distinguish between them. This makes
    the code for a generic algorithm quite consise and readable.

    However, there are some technical issues that one has to consider:
    \begin{itemize}
      \item  When fixing parameters in the declaration of the locale, their
        types will be inferred independently of the definitions later done in
        the locale context. In order to get the correct types, one has to add
        explicit type constraints.
      \item The code generator has problems with generating code from
        definitions inside a locale. Currently, the @{text Locale_Code}-package
        provides a rather convenient workaround for that issue: It requires the
        user to enclose interpretations and definitions of new constants inside
        already interpreted locales within two special commands, that set up
        the code generator appropriately.
    \end{itemize}
    *}

  subsection {* Explicit Invariants vs Typedef *}
  text {*
    The interfaces of this framework use explicit invariants.
    This provides a more general specification which allows some operations to
    be implemented more efficiently, cf. @{const "lsi.ins_dj"}
    in @{theory ListSetImpl_Invar}.

    Most implementations, however, hide the invariant in a typedef and setup
    the code generator appropriately.
    In that case, the invariant is just @{term "\<lambda>_. True"}, and removed
    automatically by the simplifier and classical reasoner.
    However, it still shows up in some premises and conclusions due to
    uniformity reasons.
    *}

(*<*)
end
(*>*)