merged draft
authornipkow
Mon, 31 Jul 2017 09:34:31 +0200
changeset 69877 3a4da8caad49
parent 69876 295b5feb4e9c (diff)
parent 69872 8b31caaa4f06 (current diff)
child 69878 9c7fe85cafd3
merged
--- a/Exercises/ROOT	Mon Jul 31 09:31:07 2017 +0200
+++ b/Exercises/ROOT	Mon Jul 31 09:34:31 2017 +0200
@@ -84,6 +84,19 @@
   theories ex13
   document_files "root.tex" "exercise.sty" "build"
 
+session "ex14_base" in "ex14" = HOL +
+  theories 
+    "~~/src/HOL/Library/Multiset"
+    "~~/src/HOL/Library/Code_Target_Nat"
+    "~~/src/HOL/Library/RBT"
+    "~~/src/HOL/Library/Char_ord"
+    "~~/src/HOL/Library/Code_Char"
+    
+session "ex14" in "ex14" = ex14_base +
+  options [document = pdf, document_output = "generated", document_variants = "ex14"]
+  theories ex14
+  document_files "root.tex" "exercise.sty" "build"
+    
 session exam_basis = HOL +     
   theories [document=false] 
   "~~/src/HOL/Library/Multiset"
@@ -94,3 +107,32 @@
   options [document = pdf, document_output = "generated", document_variants = "exam"]
   theories[show_question_marks=false] exam
   document_files "root.tex" "exercise.sty" "build"
+
+session hwsol_basis = HOL +
+  theories
+  "~~/src/HOL/Library/Multiset"
+  "../../Public/Demos/BST_Demo"
+  "~~/src/HOL/Library/Tree"
+  "~~/src/HOL/Data_Structures/Tree23_Set"
+  "../../Public/Thys/Trie1"
+  "../../Public/Thys/Leftist_Heap"
+  "../../Public/Thys/Heap_Prelim"  
+  "../../Public/Thys/Skew_Heap"  
+    
+session "hwsol" in "hwsol" = hwsol_basis +
+  options [document = pdf, document_output = "generated", document_variants = "hwsol"]
+  theories[show_question_marks=false] 
+    hwsol01
+    hwsol02
+    hwsol03
+    hwsol04
+    hwsol05
+    hwsol06
+    hwsol07
+    hwsol08
+    hwsol09
+    hwsol10
+    hwsol11
+    hwsol12
+    hwsol13
+  document_files "root.tex" "build"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/ex13/sol13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,213 @@
+(*<*)
+theory sol13
+imports "../../../Public/Thys/Skew_Heap"
+begin
+(*>*)
+  
+text {* \ExerciseSheet{13}{21.~7.~2017} *}
+  
+text  \<open>{
+  \large\bf Presentation of Mini-Projects}
+
+  You are invited, on a voluntary basis, to give a short presentation
+  of your mini-projects in the tutorial on July 28.
+
+  Depending on how many presentations we have, the time slots 
+  will be 5 to 10 minutes, plus 2 minutes for questions.
+    
+  If you are interested, please write me a short email until Thursday, July 27.
+\<close>  
+
+(* FIXME: Should there be a hint about function "abs" for the use in \<Phi>? *)
+
+text \<open>
+\Exercise{Double-Ended Queues}
+
+Design a double-ended queue where all operations have constant-time amortized
+complexity. Prove functional correctness and constant-time amortized complexity.
+
+For your proofs, it is enough to count the number of newly allocated list cells.
+You may assume that operations @{term \<open>rev xs\<close>} and @{term \<open>xs@ys\<close>} allocate \<open>O(|xs|)\<close> 
+cells.
+
+Explanation: A double-ended queue is like a queue with two further operations:
+Function \<open>enq_front\<close> adds an element at the front (whereas \<open>enq\<close> adds an element at the back).
+Function \<open>deq_back\<close> removes an element at the back (whereas \<open>deq\<close> removes an element at the front).
+Here is a formal specification where the double ended queue is just a list:
+\<close>
+
+abbreviation (input) enq_list :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+"enq_list x xs \<equiv> xs @ [x]"
+
+abbreviation (input) enq_front_list :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+"enq_front_list x xs \<equiv> x # xs"
+
+abbreviation (input) deq_list :: "'a list \<Rightarrow> 'a list" where
+"deq_list xs \<equiv> tl xs"
+
+abbreviation (input) deq_back_list :: "'a list \<Rightarrow> 'a list" where
+"deq_back_list xs \<equiv> butlast xs"
+
+text\<open>
+Hint: You may want to start with the \<open>Queue\<close> implementation in \<open>Thys/Amortized_Examples\<close>.\<close>
+
+(*<*)  
+  
+type_synonym 'a queue = "'a list * 'a list"
+  
+fun list_of :: "'a queue \<Rightarrow> 'a list" where
+"list_of(xs,ys) = ys @ rev xs"
+
+(*>*)
+
+(*<*)
+
+(* Definitions *)
+
+definition init :: "'a queue" where
+"init = ([],[])"
+
+fun enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue" where
+"enq x (xs,ys) = (x#xs, ys)"
+
+fun enq_front :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue" where
+"enq_front x (xs,ys) = (xs, x#ys)"
+
+fun deq :: "'a queue \<Rightarrow> 'a queue" where
+"deq (xs,ys) =
+  (if ys = []
+   then let n = length xs div 2
+        in (take n xs, tl(rev (drop n xs)))
+   else (xs, tl ys))"
+
+fun deq_back :: "'a queue \<Rightarrow> 'a queue" where
+"deq_back (xs,ys) =
+  (if xs = []
+   then let n = length ys div 2
+        in (tl(rev (drop n ys)), take n ys)
+   else (tl xs, ys))"
+
+(*>*)
+(* Functional Correctness *)
+
+lemma "list_of init = []"
+(*<*)  
+  by (auto simp: init_def)
+(*>*)
+
+lemma "list_of(enq x q) = enq_list x (list_of q)"
+(*<*)  
+by(cases q) auto
+(*>*)
+
+lemma "list_of(enq_front x q) = enq_front_list x (list_of q)"
+(*<*)  
+by(cases q) auto
+(*>*)
+
+lemma "list_of q \<noteq> [] \<Longrightarrow> list_of(deq q) = deq_list (list_of q)"
+(*<*)  
+proof (cases q)
+  case [simp]: (Pair a b)
+    
+  assume "list_of q \<noteq> []" 
+  hence "\<not> length a \<le> length a div 2" and [simp]: "a\<noteq>[]" if "b=[]" using that
+    by (cases a; auto)+
+
+  then show ?thesis  
+    by (auto simp: Let_def rev_drop rev_take tl_append2[symmetric] 
+             simp del: tl_append2)
+    
+qed
+(*>*)
+
+(*<*)  
+lemma rev_tl_butlast_rev: "rev (tl xs) = butlast(rev xs)"
+by (metis One_nat_def butlast_conv_take drop_0 drop_Suc drop_rev rev_swap)
+
+lemma butlast_append2: "b\<noteq>[] \<Longrightarrow> butlast (a@b) = a@butlast b"
+  by (auto simp: butlast_append)
+  
+lemma [simp]: "b \<noteq> [] \<Longrightarrow> \<not> length b \<le> length b div 2" by (cases b) auto
+(*>*)
+    
+lemma "list_of q \<noteq> [] \<Longrightarrow> list_of(deq_back q) = deq_back_list (list_of q)"
+(*<*)  
+  apply (cases q)
+  apply (auto simp: Let_def rev_tl_butlast_rev butlast_append2[symmetric])
+  done  
+(*>*)
+
+
+(*<*)
+    
+fun t_enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> int" where
+(*<*)  
+"t_enq x (xs,ys) = 1"
+(*>*)  
+
+fun t_enq_front :: "'a \<Rightarrow> 'a queue \<Rightarrow> int" where
+(*<*)  
+"t_enq_front x (xs,ys) = 1"
+(*>*)  
+
+
+fun t_deq :: "'a queue \<Rightarrow> int" where
+(*<*)  
+"t_deq (xs,ys) =
+  (if ys = []
+   then let n = length xs div 2
+        in int(n + (length xs - n))
+   else 0)"
+(*>*)  
+
+fun t_deq_back :: "'a queue \<Rightarrow> int" where
+(*<*)  
+"t_deq_back (xs,ys) =
+  (if xs = []
+   then let n = length ys; m = n div 2
+        in int((length ys - n) + n)
+   else 0)"
+(*>*)  
+
+fun \<Phi> :: "'a queue \<Rightarrow> int" 
+(*<*)  
+  where
+"\<Phi> (xs,ys) = abs(int(length xs) - int(length ys))"
+(*>*)  
+
+lemma "\<Phi> q \<ge> 0"
+(*<*)  
+by(cases q) simp
+(*>*)  
+
+lemma "\<Phi> init = 0"
+(*<*)  
+by(simp add: init_def)
+(*>*)  
+
+lemma "t_enq x q + \<Phi>(enq x q) - \<Phi> q \<le> 2"
+(*<*)  
+by(cases q) auto
+(*>*)  
+
+lemma "t_enq_front x q + \<Phi>(enq_front x q) - \<Phi> q \<le> 2"
+(*<*)  
+by(cases q) auto
+(*>*)  
+
+lemma "t_deq q + \<Phi>(deq q) - \<Phi> q \<le> 2"
+(*<*)  
+by(cases q) (auto simp: Let_def)
+(*>*)  
+
+lemma "t_deq_back q + \<Phi>(deq_back q) - \<Phi> q \<le> 2"
+(*<*)  
+by(cases q) (auto simp: Let_def)
+(*>*)  
+
+(*>*)  
+
+(*<*)  
+end
+(*>*)
Binary file Exercises/ex14.pdf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/ex14/document/build	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+${ISABELLE_TOOL} latex -o sty root.tex && \
+${ISABELLE_TOOL} latex -o pdf root.tex && \
+${ISABELLE_TOOL} latex -o pdf root.tex && \
+${ISABELLE_TOOL} latex -o pdf root.tex && \
+cp root.pdf ../../../$2.pdf
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/ex14/document/exercise.sty	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,51 @@
+
+\newcommand{\Lecture}{Functional Data Structures}
+\newcommand{\Semester}{SS 2017}
+\newcommand{\Prof}{Prof.~Tobias~Nipkow,~Ph.D.}
+\newcommand{\Tutor}{Dr. Peter Lammich}
+
+\newcounter{sheet}
+\newcounter{homework}
+
+\newlength{\abslength}\setlength{\abslength}{2mm plus 1mm minus 1mm}
+\newcommand{\abs}{\par\vspace{\abslength}}
+
+\newlength{\TUMBr}\settowidth{\TUMBr}{{\bf Technische Universit{\"a}t M{\"u}nchen}}
+\newcommand{\Header}[5]{{\bf
+ \makebox[\TUMBr]{Technische Universit{\"a}t M{\"u}nchen} \hfill #3\\
+ \makebox[\TUMBr]{Institut f{\"u}r Informatik} \hfill #4\\
+ \makebox[\TUMBr]{#1} \hfill #5\\
+ \makebox[\TUMBr]{#2}}\abs}
+
+\newcommand{\Title}[1]{%
+  \begin{center}{\LARGE\bf\Lecture}\\[1ex]{\bf Exercise Sheet #1}\end{center}}
+
+\newcommand{\ExerciseSheet}[2]{%
+  \pagestyle{empty}%
+  \setcounter{sheet}{#1}%
+  \vspace*{-2cm}\Header{\Prof}{\Tutor}{\Semester}{#2}{}\vspace*{1cm}%
+  \Title{#1}\abs}
+
+\newcounter{exercise}
+\newcommand{\Exercise}[1]{%
+  \refstepcounter{exercise}%
+  \pagebreak[3]%
+  \relax%
+  \vspace{0.8em}%
+  \subsection*{{Exercise \arabic{sheet}.\arabic{exercise}\ \ \normalfont\sffamily #1}}}
+
+\newcommand{\Homework}[2]{%
+  \pagebreak[3]%
+  \relax%
+  \vspace{0.8em}%
+  \subsection*{{Homework \arabic{sheet}\ \ \normalfont\sffamily #1}}%
+  \emph{Submission until Friday, #2, 11:59am.}}
+
+\newcommand{\NumHomework}[2]{%
+  \refstepcounter{homework}%
+  \pagebreak[3]%
+  \relax%
+  \vspace{0.8em}%
+  \subsection*{{Homework \arabic{sheet}.\arabic{homework}\ \ \normalfont\sffamily #1}}%
+  \emph{Submission until Friday, #2, 11:59am.}}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/ex14/document/root.tex	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,66 @@
+\documentclass[11pt,a4paper]{scrartcl}
+\usepackage{isabelle,isabellesym}
+\usepackage{exercise}
+\usepackage{amsmath}
+
+% further packages required for unusual symbols (see also
+% isabellesym.sty), use only when needed
+
+\usepackage{amssymb}
+  %for \<leadsto>, \<box>, \<diamond>, \<sqsupset>, \<mho>, \<Join>,
+  %\<lhd>, \<lesssim>, \<greatersim>, \<lessapprox>, \<greaterapprox>,
+  %\<triangleq>, \<yen>, \<lozenge>
+
+%\usepackage[greek,english]{babel}
+  %option greek for \<euro>
+  %option english (default language) for \<guillemotleft>, \<guillemotright>
+
+\usepackage[latin1]{inputenc}
+  %for \<onesuperior>, \<onequarter>, \<twosuperior>, \<onehalf>,
+  %\<threesuperior>, \<threequarters>, \<degree>
+
+\usepackage[only,bigsqcap]{stmaryrd}
+  %for \<Sqinter>
+
+%\usepackage{eufrak}
+  %for \<AA> ... \<ZZ>, \<aa> ... \<zz> (also included in amssymb)
+
+%\usepackage{textcomp}
+  %for \<cent>, \<currency>
+
+% this should be the last package used
+\usepackage{pdfsetup}
+
+% urls in roman style, theory text in math-similar italics
+\urlstyle{rm}
+\isabellestyle{it}
+
+% for uniform font size
+%\renewcommand{\isastyle}{\isastyleminor}
+
+\begin{document}
+
+% sane default for proof documents
+\parindent 0pt\parskip 0.5ex
+
+
+\renewcommand{\isachardoublequote}{`\"}
+\renewcommand{\isachardoublequoteopen}{``}
+\renewcommand{\isachardoublequoteclose}{''}
+\renewcommand{\isacharunderscore}{\_}
+\renewcommand{\isacharunderscorekeyword}{\_}
+
+
+% generated text of all theories
+\input{session}
+
+% optional bibliography
+%\bibliographystyle{abbrv}
+%\bibliography{root}
+
+\end{document}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
--- a/Exercises/ex14/ex14.thy	Mon Jul 31 09:31:07 2017 +0200
+++ b/Exercises/ex14/ex14.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -1,3 +1,4 @@
+text {* \ExerciseSheet{14}{28.~7.~2017} *}
 theory ex14
 imports 
   "~~/src/HOL/Library/Multiset"
@@ -7,92 +8,235 @@
   "~~/src/HOL/Library/Code_Char"
 begin
 
-  definition "freq ws \<equiv> count (mset ws)"
   
-  definition "incr1 k m \<equiv> case m k of None \<Rightarrow> m(k\<mapsto>1) | Some v \<Rightarrow> m(k\<mapsto>Suc v)"
-    
-  definition "freq1 ws \<equiv> fold incr1 ws Map.empty"
-    
-  definition "abs_freq1 m k \<equiv> case m k of None \<Rightarrow> 0 | Some v \<Rightarrow> v"  
-    
-  lemma [simp]: "abs_freq1 Map.empty = (\<lambda>_. 0)"  
-    unfolding abs_freq1_def by auto
+  text \<open>
+    \Exercise{Word Frequency --- Down to ML code}
+
+    Your task is to develop a program that reads a corpus and
+    prints the words in the corpus together with their frequencies,
+    sorted by descending frequencies.
+
+    Except input and output, your program shall be formalized in Isabelle/HOL.
+    A corpus is described as @{typ \<open>'a list\<close>}, 
+    and the result is described by @{typ \<open>('a \<times> nat) list\<close>}
+  \<close>  
+
+  text \<open>The frequency of a word in a corpus can be specified as:\<close>
+  definition freq :: "'a list \<Rightarrow> 'a \<Rightarrow> nat"
+    where "freq ws = count (mset ws)"
     
-  lemma [simp]: "abs_freq1 (freq1 ws) = freq ws"
-  proof
-    fix k
-    have "abs_freq1 (fold incr1 ws m) k = freq ws k + abs_freq1 m k" for m k
-      apply (induction ws arbitrary: m)
-      apply (auto simp: freq_def abs_freq1_def incr1_def split: option.splits)  
-      done  
-    from this[of Map.empty k] show "abs_freq1 (freq1 ws) k = freq ws k"
-      by (auto simp: freq1_def)
-  qed  
-    
+  text \<open>
+    Specify a predicate that characterizes a correct result.
+    Note: If words have the same frequency, any order is allowed.
+  \<close>  
+  definition is_freq_list :: "'a list \<Rightarrow> ('a \<times> nat) list \<Rightarrow> bool" 
+    (*<*)
+    where
+    "is_freq_list ws fl \<equiv> (
+        distinct (map fst fl) 
+      \<and> (sorted (rev (map snd fl)))
+      \<and> (\<forall>w f. (w,f)\<in>set fl \<longleftrightarrow> f=freq ws w \<and> f>0)
+     )"
+    (*>*)
+
+  text \<open>Tests:\<close>  
+  lemma \<open>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''c'',2),(''b'',2),(''a'',1)]\<close>  
+  (*<*)    
+    unfolding is_freq_list_def freq_def by auto
+  (*>*)
+  lemma \<open>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',2),(''a'',1)]\<close>  
+  (*<*)    
+    unfolding is_freq_list_def freq_def by auto
+  (*>*)
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',3),(''a'',1)]\<close>  
+  (*<*)    
+    unfolding is_freq_list_def freq_def by auto
+  (*>*)
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''a'',1),(''c'',2),(''b'',2)]\<close>  
+  (*<*)    
+    unfolding is_freq_list_def freq_def by auto
+  (*>*)
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',2),(''b'',2),(''a'',1)]\<close>
+  (*<*)    
+    unfolding is_freq_list_def freq_def by auto
+  (*>*)
+      
+      
+  section \<open>Refinement \#1\<close>  
+  (* Refinement #1: Fold over word list and maintain current frequency *)  
+  text \<open>Compute a function from words to their frequency by folding 
+    over the corpus, starting with @{term \<open>\<lambda>_. 0::nat\<close>}. \<close>  
+
+  definition incr1 :: "'a \<Rightarrow> ('a \<Rightarrow> nat) \<Rightarrow> 'a \<Rightarrow> nat"
+    (*<*)
+    where
+    "incr1 k f \<equiv> f(k := Suc (f k))"
+    (*>*)
+  definition "freq1 ws \<equiv> fold incr1 ws (\<lambda>_. 0)"  
     
-  definition "incr2 k m \<equiv> case RBT.lookup m k of None \<Rightarrow> RBT.insert k 1 m | Some v \<Rightarrow> RBT.insert k (Suc v) m"
+  lemma freq1_correct[simp]: "freq1 ws = freq ws"
+  (*<*)  
+  proof -
+    have "fold incr1 ws f k = freq ws k + f k" for f k
+      by (induction ws arbitrary: f) (auto simp: freq_def incr1_def)
+    thus ?thesis unfolding freq1_def by auto
+  qed
+  (*>*)
 
-  lemma incr2_abs[simp]: "RBT.lookup (incr2 k m) = incr1 k (RBT.lookup m)"
-    unfolding incr2_def incr1_def
-    by (auto split: option.split)  
+  section \<open>Refinement \#2\<close>  
+  (* Refinement #2: Frequency map by RBT *)
+  text \<open>
+    Use red black trees to implement the mapping from words to frequencies.
+    Words that do not occur in the corpus must not be mapped!
+
+    Use the RBT implementation from \<open>HOL/Library/RBT\<close>!
+    It provides, e.g., @{const RBT.empty}, @{const RBT.lookup}, @{const RBT.insert}.
+  \<close>  
+  definition abs_fm :: "('a::linorder,nat) rbt \<Rightarrow> 'a \<Rightarrow> nat" where
+    "abs_fm t k \<equiv> case RBT.lookup t k of None \<Rightarrow> 0 | Some v \<Rightarrow> v"
+  definition inv_fm :: "('a::linorder,nat) rbt \<Rightarrow> bool" where
+    "inv_fm t \<equiv> (0 \<notin> ran (RBT.lookup t))"
     
-  definition "freq2 ws \<equiv> fold incr2 ws RBT.empty"
-  
-  lemma freq2_abs[simp]: "RBT.lookup (freq2 ws) = freq1 ws"  
-  proof -
-    have "RBT.lookup (fold incr2 ws t) = fold incr1 ws (RBT.lookup t)" for t
-      by (induction ws arbitrary: t) auto  
-    thus ?thesis unfolding freq2_def freq1_def by auto
-  qed
+  lemma empty2_correct[simp]:
+    "abs_fm RBT.empty = (\<lambda>_. 0)" "inv_fm RBT.empty"
+    (*<*)
+    by (auto simp: abs_fm_def inv_fm_def)
+    (*>*)
     
-  export_code freq2 in SML module_name Freq
-  
-
-  definition "fsort ws \<equiv> rev (sort_key (freq ws) (remdups ws))"
-  definition "fsort2 ws \<equiv> let t = freq2 ws in rev (sort_key (abs_freq1 (RBT.lookup t)) (remdups ws))"
+  definition incr2 :: "'a::linorder \<Rightarrow> ('a, nat) rbt \<Rightarrow> ('a, nat) rbt"
+  (*<*)
+    where
+    "incr2 k t \<equiv> case RBT.lookup t k of 
+    None \<Rightarrow> RBT.insert k 1 t
+  | Some v \<Rightarrow> RBT.insert k (Suc v) t"
+  (*>*)
+      
+  lemma incr2_correct[simp]:
+    "inv_fm t \<Longrightarrow> abs_fm (incr2 k t) = incr1 k (abs_fm t)"
+    "inv_fm t \<Longrightarrow> inv_fm (incr2 k t)"
+  (*<*)
+    by (auto simp: inv_fm_def abs_fm_def incr2_def incr1_def ran_def split: option.splits)
+  (*>*)
     
-    
-  definition "rdfreq ws \<equiv> fold (\<lambda>x (m,l). (add_mset x m, if x\<in>#m then l else x#l)) ws ({#},[])"
-    
-  lemma rdfreq_correct:
-    assumes "rdfreq ws = (m,l)"
-    shows "m=mset ws" "distinct l" "set l = set ws"
+  text \<open> Now we have refined the operations, we can refine the algorithm that uses the operations:\<close>
+  definition "freq2 ws \<equiv> fold incr2 ws RBT.empty"  
+      
+  lemma freq2_correct[simp]: "abs_fm (freq2 ws) = freq1 ws" "inv_fm (freq2 ws)"
+  (*<*)  
   proof -
-    {
-      fix m\<^sub>0 l\<^sub>0
-      assume "fold (\<lambda>x (m,l). (add_mset x m, if x\<in>#m then l else x#l)) ws (m\<^sub>0,l\<^sub>0) = (m,l)"
-         and "set_mset m\<^sub>0 = set l\<^sub>0" "distinct l\<^sub>0" 
-      hence "m = m\<^sub>0 + mset ws \<and> distinct l \<and> set l = set l\<^sub>0 \<union> set ws"
-        apply (induction ws arbitrary: m\<^sub>0 l\<^sub>0 m l)
-        apply (fastforce split: if_splits)+
-        done
-    } 
-    from this[of "{#}" "[]"] show "m=mset ws" "distinct l" "set l = set ws" 
-      using assms by (auto simp: rdfreq_def)
+    have "abs_fm (fold incr2 ws t) = fold incr1 ws (abs_fm t) \<and> inv_fm (fold incr2 ws t)"
+      if "inv_fm t" for t
+      using that
+      by (induction ws arbitrary: t) auto  
+    from this[of RBT.empty] show "abs_fm (freq2 ws) = freq1 ws" "inv_fm (freq2 ws)"
+      unfolding freq2_def freq1_def by auto
   qed  
+  (*>*)
+      
+  
+  (*<*)  (* NOT PART OF EXERCISE *)
+  (* Simple abstract implementation *)  
+  definition "fsort_simple ws \<equiv> rev (sort_key snd (map (\<lambda>w. (w,freq ws w)) (remdups ws)))"
+   
+  lemma insort_key_map: 
+    "insort_key f (g k) (map g l) = map g (insort_key (f o g) k l)"
+    by (induction l) auto
+    
+  lemma sort_key_map: "sort_key f (map g l) = map g (sort_key (f o g) l)"  
+    by (induction l) (auto simp: o_def insort_key_map)
+    
+  lemma fsort_simple_is_freq_list: "is_freq_list ws (fsort_simple ws)"
+    unfolding is_freq_list_def fsort_simple_def
+    apply (safe; simp?; (auto; fail)?)
+    subgoal by (simp add: rev_map[symmetric] sort_key_map o_def)
+    subgoal by (simp add: rev_map)
+    subgoal by (auto simp: freq_def) []  
+    subgoal by (auto simp: freq_def) []  
+    done
+  (*>*)
     
-  xxx, ctd here:
-    still not accurate, as result after sort may be different ! 
-    
-    
+  subsection \<open>Extracting Result from RBT\<close>
+  text \<open>Extract the desired result 
+    --- list of pairs of words and their frequencies, sorted by frequency --- 
+    from the red black tree. Use @{const RBT.entries}.
+  \<close>  
+      
+  definition fsort :: "'a::linorder list \<Rightarrow> ('a \<times> nat) list"
+  (*<*)  
+    where "fsort ws \<equiv> 
+      let fr = freq2 ws in 
+        rev (sort_key snd (RBT.entries fr))"
+  (*>*)
+
+  (*<*)  
+  lemma distinct_map_insort[simp]: 
+    "distinct (map f (insort_key g k l)) \<longleftrightarrow> distinct (map f (k#l))"
+    by (induction l arbitrary: k) (auto simp: set_insort_key)
     
-  (* TODO: Use RBT.keys/RBT.entries instead of remdups! *)  
+  lemma distinct_map_sort[simp]: "distinct (map f (sort_key g l)) \<longleftrightarrow> distinct (map f l)"
+    by (induction l) auto
+
+  (* For this proof, we have to derive the following from the freq2-correct lemma.
+    This is required as we work on red-black trees directly
+  *)
+  lemma freq2_eq_Some_iff[simp]: "RBT.lookup (freq2 ws) w = Some f \<longleftrightarrow> (f>0 \<and> f = freq ws w)"
+  proof -
+    note X = freq2_correct[of ws, unfolded abs_fm_def]
+    note Y = X(1)[THEN fun_cong, of w]
+    note Z = X(2)[unfolded inv_fm_def]  
+    from Y Z show ?thesis
+      apply (auto split: option.splits simp: ran_def)
+      using neq0_conv by fastforce
+  qed      
+  (*>*)
+     
+  text \<open>Prove that your function is correct. 
+    Hint: You will need to prove some auxiliary lemmas on standard list functions.
+      Use \<open>find_theorems\<close> to search for existing lemmas.
+    Hint: A lemma of the form @{text \<open>RBT.lookup (freq2 ws) w = Some f \<longleftrightarrow> \<dots>\<close>},
+      derived from @{thm [source] freq2_correct freq1_correct} may be useful!
+  \<close>  
+  lemma fsort_correct: "is_freq_list ws (fsort ws)"
+  (*<*)  
+    unfolding is_freq_list_def fsort_def Let_def
+    apply safe  
+    subgoal by (simp add: rev_map[symmetric] RBT.distinct_entries)
+    subgoal by (auto simp: rev_map)
+    subgoal by (simp add: RBT.lookup_in_tree[symmetric])
+    subgoal by (simp add: RBT.lookup_in_tree[symmetric])
+    subgoal by (simp add: RBT.lookup_in_tree[symmetric])
+    done
+  (*>*)
+
+
+  section \<open>Code Generation\<close>    
+  text \<open>Now we can use Isabelle/HOL's code generator to actually extract
+    functional code from our Isabelle formalization.
     
-  lemma [code]: "fsort ws = fsort2 ws"  
-    unfolding fsort_def fsort2_def
-    by simp  
-    
-  definition fsort_string :: "String.literal list \<Rightarrow> String.literal list" 
+    First, we derive a specialized versions with strings:
+  \<close>    
+  definition fsort_string :: "String.literal list \<Rightarrow> (String.literal \<times> nat) list"
     where "fsort_string \<equiv> fsort"
       
-  export_code fsort_string in SML module_name Fsort file "export.sml"
+  text \<open>Then we can use the code generator in different ways.\<close>    
+      
+  text \<open>By the value command\<close>
+  value [code] "fsort_string [STR ''foo'', STR ''bar'', STR ''foo'', STR ''bara'']"
       
-    
-  value "fsort_string [STR ''foo'', STR ''bar'', STR ''foo'', STR ''bar'']"
-      
-  SML_file "export.sml"  
-  SML_file "fsort.sml"  
-    
+  text \<open>Export code to file\<close>  
+  export_code fsort_string in SML module_name Fsort file "export.sml"
+  text \<open>We can load the file into JEdit's ML IDE: \<close>  
+  SML_file "export.sml"
+  text \<open>And use it from within some wrapper code for parsing a corpus and printing the result: \<close>  
+  SML_file "fsort.sml"
+
+  text \<open>Use code directly with Isabelle's builtin ML interpreter 
+    \begin{verbatim}
+  ML_val {* see template file *}  
+    \end{verbatim}
+  \<close>
+  (* Directly as Isabelle/ML command *)  
+(*<*)
   ML_val \<open>
     (* Read file to string *)
     fun file_to_string name = let
@@ -104,11 +248,16 @@
     fun fs fname = @{code fsort_string}
       (String.tokens (not o Char.isAlpha) (String.map (Char.toLower) (file_to_string fname)))
 
-    val r = fs "/home/lammich/MASC-3.0.0/data/written/non-fiction/CUP2.txt"
+    val r1 = fs "/home/lammich/MASC-3.0.0/data/written/non-fiction/CUP2.txt"
+    val r2 = fs "/home/lammich/MASC-3.0.0/data/written/twitter/tweets2.txt"
   \<close>  
-    
-    
-    
-    
+(*>*)
+
+  text \<open>The code generator also supports other target languages\<close>  
+  export_code fsort_string in Haskell
+  export_code fsort_string in Scala
+  export_code fsort_string in OCaml
   
+(*<*)    
 end
+(*>*)
--- a/Exercises/ex14/export.sml	Mon Jul 31 09:31:07 2017 +0200
+++ b/Exercises/ex14/export.sml	Mon Jul 31 09:34:31 2017 +0200
@@ -1,16 +1,10 @@
 structure Fsort : sig
-  val fsort_string : string list -> string list
+  type nat
+  val fsort_string : string list -> (string * nat) list
 end = struct
 
 datatype nat = Nat of IntInf.int;
 
-val zero_nata : nat = Nat (0 : IntInf.int);
-
-type 'a zero = {zero : 'a};
-val zero = #zero : 'a zero -> 'a;
-
-val zero_nat = {zero = zero_nata} : nat zero;
-
 fun integer_of_nat (Nat x) = x;
 
 fun less_eq_nat m n = IntInf.<= (integer_of_nat m, integer_of_nat n);
@@ -38,12 +32,6 @@
 
 val linorder_nat = {order_linorder = order_nat} : nat linorder;
 
-type 'a equal = {equal : 'a -> 'a -> bool};
-val equal = #equal : 'a equal -> 'a -> 'a -> bool;
-
-val equal_literal = {equal = (fn a => fn b => ((a : string) = b))} :
-  string equal;
-
 val ord_literal =
   {less_eq = (fn a => fn b => ((a : string) <= b)),
     less = (fn a => fn b => ((a : string) < b))}
@@ -69,8 +57,6 @@
 
 datatype ('b, 'a) rbt = RBT of ('b, 'a) rbta;
 
-fun eq A_ a b = equal A_ a b;
-
 fun plus_nat m n = Nat (IntInf.+ (integer_of_nat m, integer_of_nat n));
 
 val one_nat : nat = Nat (1 : IntInf.int);
@@ -85,8 +71,10 @@
 
 fun equal_nat m n = (((integer_of_nat m) : IntInf.int) = (integer_of_nat n));
 
+val zero_nat : nat = Nat (0 : IntInf.int);
+
 fun nth (x :: xs) n =
-  (if equal_nat n zero_nata then x else nth xs (minus_nat n one_nat));
+  (if equal_nat n zero_nat then x else nth xs (minus_nat n one_nat));
 
 fun fold f (x :: xs) s = fold f xs (f x s)
   | fold f [] s = s;
@@ -255,9 +243,18 @@
   rbt_lookup ((ord_preorder o preorder_order o order_linorder) A_)
     (impl_of A_ x);
 
-fun incr2 A_ k m =
-  (case lookup A_ m k of NONE => insert A_ k one_nat m
-    | SOME v => insert A_ k (suc v) m);
+fun gen_entries kvts (Branch (c, l, k, v, r)) =
+  gen_entries (((k, v), r) :: kvts) l
+  | gen_entries ((kv, t) :: kvts) Empty = kv :: gen_entries kvts t
+  | gen_entries [] Empty = [];
+
+fun entriesa x = gen_entries [] x;
+
+fun entries A_ x = entriesa (impl_of A_ x);
+
+fun incr2 A_ k t =
+  (case lookup A_ t k of NONE => insert A_ k one_nat t
+    | SOME f => insert A_ k (plus_nat f one_nat) t);
 
 fun freq2 A_ ws = fold (incr2 A_) ws (empty A_);
 
@@ -294,7 +291,7 @@
 fun gen_length n (x :: xs) = gen_length (suc n) xs
   | gen_length n [] = n;
 
-fun size_list x = gen_length zero_nata x;
+fun size_list x = gen_length zero_nat x;
 
 fun part B_ f pivot (x :: xs) =
   let
@@ -328,25 +325,10 @@
         sort_key B_ f lts @ eqs @ sort_key B_ f gts
       end);
 
-fun abs_freq1 B_ m k = (case m k of NONE => zero B_ | SOME v => v);
-
-fun member A_ [] y = false
-  | member A_ (x :: xs) y = eq A_ x y orelse member A_ xs y;
-
-fun remdups A_ [] = []
-  | remdups A_ (x :: xs) =
-    (if member A_ xs x then remdups A_ xs else x :: remdups A_ xs);
+fun snd (x1, x2) = x2;
 
-fun fsort2 (A1_, A2_) ws =
-  let
-    val t = freq2 A2_ ws;
-  in
-    rev (sort_key linorder_nat (abs_freq1 zero_nat (lookup A2_ t))
-          (remdups A1_ ws))
-  end;
+fun fsort A_ ws = rev (sort_key linorder_nat snd (entries A_ (freq2 A_ ws)));
 
-fun fsort (A1_, A2_) ws = fsort2 (A1_, A2_) ws;
-
-fun fsort_string x = fsort (equal_literal, linorder_literal) x;
+fun fsort_string x = fsort linorder_literal x;
 
 end; (*struct Fsort*)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/ex14/tmpl14.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,160 @@
+text {* \ExerciseSheet{14}{28.~7.~2017} *}
+theory tmpl14
+imports 
+  "~~/src/HOL/Library/Multiset"
+  "~~/src/HOL/Library/Code_Target_Nat"
+  "~~/src/HOL/Library/RBT"
+  "~~/src/HOL/Library/Char_ord"
+  "~~/src/HOL/Library/Code_Char"
+begin
+
+  
+  text \<open>
+    \Exercise{Word Frequency --- Down to ML code}
+
+    Your task is to develop a program that reads a corpus and
+    prints the words in the corpus together with their frequencies,
+    sorted by descending frequencies.
+
+    Except input and output, your program shall be formalized in Isabelle/HOL.
+    A corpus is described as @{typ \<open>'a list\<close>}, 
+    and the result is described by @{typ \<open>('a \<times> nat) list\<close>}
+  \<close>  
+
+  text \<open>The frequency of a word in a corpus can be specified as:\<close>
+  definition freq :: "'a list \<Rightarrow> 'a \<Rightarrow> nat"
+    where "freq ws = count (mset ws)"
+    
+  text \<open>
+    Specify a predicate that characterizes a correct result.
+    Note: If words have the same frequency, any order is allowed.
+  \<close>  
+  consts is_freq_list :: "'a list \<Rightarrow> ('a \<times> nat) list \<Rightarrow> bool" 
+
+  text \<open>Tests:\<close>  
+  lemma \<open>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''c'',2),(''b'',2),(''a'',1)]\<close>  
+    oops
+  lemma \<open>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',2),(''a'',1)]\<close>  
+    oops
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',3),(''a'',1)]\<close>  
+    oops
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''a'',1),(''c'',2),(''b'',2)]\<close>  
+    oops
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',2),(''b'',2),(''a'',1)]\<close>
+    oops
+      
+      
+  section \<open>Refinement \#1\<close>  
+  (* Refinement #1: Fold over word list and maintain current frequency *)  
+  text \<open>Compute a function from words to their frequency by folding 
+    over the corpus, starting with @{term \<open>\<lambda>_. 0::nat\<close>}. \<close>  
+
+  consts incr1 :: "'a \<Rightarrow> ('a \<Rightarrow> nat) \<Rightarrow> 'a \<Rightarrow> nat"
+  definition "freq1 ws \<equiv> fold incr1 ws (\<lambda>_. 0)"  
+    
+  lemma freq1_correct[simp]: "freq1 ws = freq ws"
+    oops
+
+  section \<open>Refinement \#2\<close>  
+  (* Refinement #2: Frequency map by RBT *)
+  text \<open>
+    Use red black trees to implement the mapping from words to frequencies.
+    Words that do not occur in the corpus must not be mapped!
+
+    Use the RBT implementation from \<open>HOL/Library/RBT\<close>!
+    It provides, e.g., @{const RBT.empty}, @{const RBT.lookup}, @{const RBT.insert}.
+  \<close>  
+  definition abs_fm :: "('a::linorder,nat) rbt \<Rightarrow> 'a \<Rightarrow> nat" where
+    "abs_fm t k \<equiv> case RBT.lookup t k of None \<Rightarrow> 0 | Some v \<Rightarrow> v"
+  definition inv_fm :: "('a::linorder,nat) rbt \<Rightarrow> bool" where
+    "inv_fm t \<equiv> (0 \<notin> ran (RBT.lookup t))"
+    
+  lemma empty2_correct[simp]:
+    "abs_fm RBT.empty = (\<lambda>_. 0)" "inv_fm RBT.empty"
+    oops
+    
+  definition incr2 :: "'a::linorder \<Rightarrow> ('a, nat) rbt \<Rightarrow> ('a, nat) rbt"
+    where "incr2 k t = t"
+      
+  lemma incr2_correct[simp]:
+    "inv_fm t \<Longrightarrow> abs_fm (incr2 k t) = incr1 k (abs_fm t)"
+    "inv_fm t \<Longrightarrow> inv_fm (incr2 k t)"
+    oops
+      
+  text \<open> Now we have refined the operations, we can refine the algorithm that uses the operations:\<close>
+  definition "freq2 ws \<equiv> fold incr2 ws RBT.empty"  
+      
+  lemma freq2_correct[simp]: "abs_fm (freq2 ws) = freq1 ws" "inv_fm (freq2 ws)"
+    oops
+      
+    
+  subsection \<open>Extracting Result from RBT\<close>
+  text \<open>Extract the desired result 
+    --- list of pairs of words and their frequencies, sorted by frequency --- 
+    from the red black tree. Use @{const RBT.entries}.
+  \<close>  
+      
+  definition fsort :: "'a::linorder list \<Rightarrow> ('a \<times> nat) list"
+    where "fsort ws \<equiv> []"
+
+     
+  text \<open>Prove that your function is correct. 
+    Hint: You will need to prove some auxiliary lemmas on standard list functions.
+      Use \<open>find_theorems\<close> to search for existing lemmas.
+    Hint: A lemma of the form @{text \<open>RBT.lookup (freq2 ws) w = Some f \<longleftrightarrow> \<dots>\<close>},
+      derived from @{text \<open>freq2_correct freq1_correct\<close>} may be useful!
+  \<close>  
+  lemma fsort_correct: "is_freq_list ws (fsort ws)"
+    oops
+
+
+  section \<open>Code Generation\<close>    
+  text \<open>Now we can use Isabelle/HOL's code generator to actually extract
+    functional code from our Isabelle formalization.
+    
+    First, we derive a specialized versions with strings:
+  \<close>    
+  definition fsort_string :: "String.literal list \<Rightarrow> (String.literal \<times> nat) list"
+    where "fsort_string \<equiv> fsort"
+      
+  text \<open>Then we can use the code generator in different ways.\<close>    
+      
+  text \<open>By the value command\<close>
+  value [code] "fsort_string [STR ''foo'', STR ''bar'', STR ''foo'', STR ''bara'']"
+      
+  text \<open>Export code to file\<close>  
+  export_code fsort_string in SML module_name Fsort file "export.sml"
+  text \<open>We can load the file into JEdit's ML IDE: \<close>  
+  SML_file "export.sml"
+  text \<open>And use it from within some wrapper code for parsing a corpus and printing the result: \<close>  
+  SML_file "fsort.sml"
+
+  text \<open>Use code directly with Isabelle's builtin ML interpreter 
+    \begin{verbatim}
+  ML_val {* see template file *}  
+    \end{verbatim}
+  \<close>
+  (* Directly as Isabelle/ML command *)  
+  ML_val \<open>
+    (* Read file to string *)
+    fun file_to_string name = let
+      val f = TextIO.openIn name
+      val s = TextIO.inputAll f
+      val _ = TextIO.closeIn f
+    in s end
+
+    fun fs fname = @{code fsort_string}
+      (String.tokens (not o Char.isAlpha) (String.map (Char.toLower) (file_to_string fname)))
+
+    val r1 = fs "/home/lammich/MASC-3.0.0/data/written/non-fiction/CUP2.txt"
+    val r2 = fs "/home/lammich/MASC-3.0.0/data/written/twitter/tweets2.txt"
+  \<close>  
+
+  text \<open>The code generator also supports other target languages\<close>  
+  export_code fsort_string in Haskell
+  export_code fsort_string in Scala
+  export_code fsort_string in OCaml
+  
+(*<*)    
+end
+(*>*)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/ex14/tut14.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,211 @@
+text {* \ExerciseSheet{14}{28.~7.~2017} *}
+theory tut14
+imports 
+  "~~/src/HOL/Library/Multiset"
+  "~~/src/HOL/Library/Code_Target_Nat"
+  "~~/src/HOL/Library/RBT"
+  "~~/src/HOL/Library/Char_ord"
+  "~~/src/HOL/Library/Code_Char"
+begin
+
+  
+  text \<open>
+    \Exercise{Word Frequency --- Down to ML code}
+
+    Your task is to develop a program that reads a corpus and
+    prints the words in the corpus together with their frequencies,
+    sorted by descending frequencies.
+
+    Except input and output, your program shall be formalized in Isabelle/HOL.
+    A corpus is described as @{typ \<open>'a list\<close>}, 
+    and the result is described by @{typ \<open>('a \<times> nat) list\<close>}
+  \<close>  
+
+  text \<open>The frequency of a word in a corpus can be specified as:\<close>
+  definition freq :: "'a list \<Rightarrow> 'a \<Rightarrow> nat"
+    where "freq ws = count (mset ws)"
+    
+  text \<open>
+    Specify a predicate that characterizes a correct result.
+    Note: If words have the same frequency, any order is allowed.
+  \<close>  
+  definition is_freq_list :: "'a list \<Rightarrow> ('a \<times> nat) list \<Rightarrow> bool" 
+    where
+      "is_freq_list ws fl \<equiv> 
+         distinct (map fst fl)
+      \<and> (\<forall>w f. (w,f)\<in>set fl \<longleftrightarrow> freq ws w = f \<and> f>0 )  
+      \<and> sorted (rev (map snd fl))
+      "
+
+  text \<open>Tests:\<close>  
+  lemma \<open>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''c'',2),(''b'',2),(''a'',1)]\<close>  
+    by (auto simp: is_freq_list_def freq_def)
+  lemma \<open>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',2),(''a'',1)]\<close>  
+    by (auto simp: is_freq_list_def freq_def)
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',3),(''a'',1)]\<close>  
+    by (auto simp: is_freq_list_def freq_def)
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''a'',1),(''c'',2),(''b'',2)]\<close>  
+    by (auto simp: is_freq_list_def freq_def)
+  lemma \<open>\<not>is_freq_list [''a'',''b'',''b'',''c'',''c''] [(''b'',2),(''c'',2),(''b'',2),(''a'',1)]\<close>
+    by (auto simp: is_freq_list_def freq_def)
+      
+      
+  section \<open>Refinement \#1\<close>  
+  (* Refinement #1: Fold over word list and maintain current frequency *)  
+  text \<open>Compute a function from words to their frequency by folding 
+    over the corpus, starting with @{term \<open>\<lambda>_. 0::nat\<close>}. \<close>  
+
+  term "Map.empty"  
+  term "f(x:=y)"  
+    
+  definition incr1 :: "'a \<Rightarrow> ('a \<Rightarrow> nat) \<Rightarrow> 'a \<Rightarrow> nat"
+    where "incr1 w fm \<equiv> fm(w:=fm w + 1)"
+  definition "freq1 ws \<equiv> fold incr1 ws (\<lambda>_. 0)"  
+    
+  lemma freq1_correct[simp]: "freq1 ws = freq ws"
+  proof -
+    have "fold incr1 ws fm = (\<lambda>w. count (mset ws) w + fm w)" for fm
+      by (induction ws arbitrary: fm) (auto simp: incr1_def)
+    from this[of "\<lambda>_. 0"] show ?thesis      
+      unfolding freq1_def freq_def by auto
+  qed      
+    
+
+  section \<open>Refinement \#2\<close>  
+  (* Refinement #2: Frequency map by RBT *)
+  text \<open>
+    Use red black trees to implement the mapping from words to frequencies.
+    Words that do not occur in the corpus must not be mapped!
+
+    Use the RBT implementation from \<open>HOL/Library/RBT\<close>!
+    It provides, e.g., @{const RBT.empty}, @{const RBT.lookup}, @{const RBT.insert}.
+  \<close>  
+  definition abs_fm :: "('a::linorder,nat) rbt \<Rightarrow> 'a \<Rightarrow> nat" where
+    "abs_fm t k \<equiv> case RBT.lookup t k of None \<Rightarrow> 0 | Some v \<Rightarrow> v"
+  definition inv_fm :: "('a::linorder,nat) rbt \<Rightarrow> bool" where
+    "inv_fm t \<equiv> (0 \<notin> ran (RBT.lookup t))"
+
+  lemma empty2_correct[simp]:
+    "abs_fm RBT.empty = (\<lambda>_. 0)" "inv_fm RBT.empty"
+    unfolding abs_fm_def inv_fm_def by auto
+    
+  term RBT.lookup term RBT.insert    
+      
+  definition incr2 :: "'a::linorder \<Rightarrow> ('a, nat) rbt \<Rightarrow> ('a, nat) rbt"
+    where "incr2 k t = (
+      case RBT.lookup t k of 
+        None \<Rightarrow> RBT.insert k 1 t 
+      | Some f \<Rightarrow> RBT.insert k (f+1) t)"
+      
+  lemma incr2_correct[simp]:
+    "inv_fm t \<Longrightarrow> abs_fm (incr2 k t) = incr1 k (abs_fm t)"
+    "inv_fm t \<Longrightarrow> inv_fm (incr2 k t)"
+    unfolding inv_fm_def abs_fm_def incr2_def incr1_def
+    by (auto simp: ran_def split: option.split)  
+      
+  text \<open> Now we have refined the operations, we can refine the algorithm that uses the operations:\<close>
+  definition "freq2 ws \<equiv> fold incr2 ws RBT.empty"  
+      
+  lemma freq2_correct[simp]: 
+    shows
+    "abs_fm (freq2 ws) = freq1 ws" (is ?G1) 
+    and "inv_fm (freq2 ws)" (is ?G2)
+  proof -
+    have "abs_fm (fold incr2 ws t) = fold incr1 ws (abs_fm t) 
+        \<and> inv_fm (fold incr2 ws t)" if "inv_fm t" for t
+      using that
+      by (induction ws arbitrary: t) (auto)  
+    from this show ?G1 ?G2    
+      unfolding freq2_def freq1_def
+      by auto  
+  qed      
+    
+  subsection \<open>Extracting Result from RBT\<close>
+  text \<open>Extract the desired result 
+    --- list of pairs of words and their frequencies, sorted by frequency --- 
+    from the red black tree. Use @{const RBT.entries}.
+  \<close>  
+
+  term "RBT.entries (freq2 ws)" 
+  term sort_key  
+  definition fsort :: "'a::linorder list \<Rightarrow> ('a \<times> nat) list"
+    where "fsort ws \<equiv> rev (sort_key snd (RBT.entries (freq2 ws)))"
+
+     
+  text \<open>Prove that your function is correct. 
+    Hint: You will need to prove some auxiliary lemmas on standard list functions.
+      Use \<open>find_theorems\<close> to search for existing lemmas.
+    Hint: A lemma of the form @{text \<open>RBT.lookup (freq2 ws) w = Some f \<longleftrightarrow> \<dots>\<close>},
+      derived from @{text \<open>freq2_correct freq1_correct\<close>} may be useful!
+  \<close>  
+    
+  lemma [simp]: "(w, f) \<in> set (RBT.entries (freq2 ws)) \<longleftrightarrow> freq ws w = f \<and> f>0"
+    using freq2_correct(1)[of ws, THEN fun_cong[where x=w]]
+    using freq2_correct(2)[of ws]  
+    unfolding abs_fm_def inv_fm_def
+    apply (auto split: option.splits simp: ran_def lookup_in_tree[symmetric])
+    using neq0_conv by fastforce  
+    
+    
+  lemma fsort_correct: "is_freq_list ws (fsort ws)"
+    unfolding is_freq_list_def
+    apply (intro conjI)
+    subgoal unfolding fsort_def
+      apply (simp add: rev_map[symmetric])
+      by (metis RBT.distinct_entries distinct_map distinct_sort set_sort)
+    subgoal unfolding fsort_def
+      by auto
+    subgoal unfolding fsort_def
+      by (auto simp: rev_map)
+    done      
+
+  section \<open>Code Generation\<close>    
+  text \<open>Now we can use Isabelle/HOL's code generator to actually extract
+    functional code from our Isabelle formalization.
+    
+    First, we derive a specialized versions with strings:
+  \<close>    
+  definition fsort_string :: "String.literal list \<Rightarrow> (String.literal \<times> nat) list"
+    where "fsort_string \<equiv> fsort"
+      
+  text \<open>Then we can use the code generator in different ways.\<close>    
+      
+  text \<open>By the value command\<close>
+  value [code] "fsort_string [STR ''foo'', STR ''bar'', STR ''foo'', STR ''bara'']"
+      
+  text \<open>Export code to file\<close>  
+  export_code fsort_string in SML module_name Fsort file "export.sml"
+  text \<open>We can load the file into JEdit's ML IDE: \<close>  
+  SML_file "export.sml"
+  text \<open>And use it from within some wrapper code for parsing a corpus and printing the result: \<close>  
+  SML_file "fsort.sml"
+
+  text \<open>Use code directly with Isabelle's builtin ML interpreter 
+    \begin{verbatim}
+  ML_val {* see template file *}  
+    \end{verbatim}
+  \<close>
+  (* Directly as Isabelle/ML command *)  
+  ML_val \<open>
+    (* Read file to string *)
+    fun file_to_string name = let
+      val f = TextIO.openIn name
+      val s = TextIO.inputAll f
+      val _ = TextIO.closeIn f
+    in s end
+
+    fun fs fname = @{code fsort_string}
+      (String.tokens (not o Char.isAlpha) (String.map (Char.toLower) (file_to_string fname)))
+
+    val r1 = fs "/home/lammich/MASC-3.0.0/data/written/non-fiction/CUP2.txt"
+    val r2 = fs "/home/lammich/MASC-3.0.0/data/written/twitter/tweets2.txt"
+  \<close>  
+
+  text \<open>The code generator also supports other target languages\<close>  
+  export_code fsort_string in Haskell
+  export_code fsort_string in Scala
+  export_code fsort_string in OCaml
+  
+(*<*)    
+end
+(*>*)
Binary file Exercises/exam.pdf has changed
--- a/Exercises/exam/Q_Balanced_Insert.thy	Mon Jul 31 09:31:07 2017 +0200
+++ b/Exercises/exam/Q_Balanced_Insert.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -27,7 +27,7 @@
     list into an initially empty search tree:
   \<close>
   definition from_list :: "'a::linorder list \<Rightarrow> 'a tree" where 
-    "from_list l = fold ins l \<langle>\<rangle>"
+    "from_list l = fold ins l Leaf"
 
   text \<open>  
     Your task is to specify a function @{term_type preprocess}, 
--- a/Exercises/exam/Q_Induction.thy	Mon Jul 31 09:31:07 2017 +0200
+++ b/Exercises/exam/Q_Induction.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -21,7 +21,7 @@
 "lvs (Nd r s t) = lvs r + lvs s + lvs t"
 
 text \<open>There is a linear relationship between the size (\<open>sz\<close>) and the number of
-leaves (\<open>lvs\<close>) of a tree. Find this relationship and prove \<open>lfs t = a * sz t + b\<close>
+leaves (\<open>lvs\<close>) of a tree. Find this relationship and prove \<open>lvs t = a * sz t + b\<close>
 for the correct \<open>a\<close> and \<open>b\<close>.\<close>
 
 (*<*)
--- a/Exercises/exam/Q_Tree_Same_Struct.thy	Mon Jul 31 09:31:07 2017 +0200
+++ b/Exercises/exam/Q_Tree_Same_Struct.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -83,3 +83,5 @@
 end
 (*>*)  
 text_raw \<open>\blankpage\<close>
+text_raw \<open>\blankpage\<close>
+text_raw \<open>\blankpage\<close>
Binary file Exercises/hwsol.pdf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/document/build	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+${ISABELLE_TOOL} latex -o sty root.tex && \
+${ISABELLE_TOOL} latex -o pdf root.tex && \
+${ISABELLE_TOOL} latex -o pdf root.tex && \
+${ISABELLE_TOOL} latex -o pdf root.tex && \
+cp root.pdf ../../../$2.pdf
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/document/exercise.sty	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,51 @@
+
+\newcommand{\Lecture}{Functional Data Structures}
+\newcommand{\Semester}{SS 2017}
+\newcommand{\Prof}{Prof.~Tobias~Nipkow,~Ph.D.}
+\newcommand{\Tutor}{Dr. Peter Lammich}
+
+\newcounter{sheet}
+\newcounter{homework}
+
+\newlength{\abslength}\setlength{\abslength}{2mm plus 1mm minus 1mm}
+\newcommand{\abs}{\par\vspace{\abslength}}
+
+\newlength{\TUMBr}\settowidth{\TUMBr}{{\bf Technische Universit{\"a}t M{\"u}nchen}}
+\newcommand{\Header}[5]{{\bf
+ \makebox[\TUMBr]{Technische Universit{\"a}t M{\"u}nchen} \hfill #3\\
+ \makebox[\TUMBr]{Institut f{\"u}r Informatik} \hfill #4\\
+ \makebox[\TUMBr]{#1} \hfill #5\\
+ \makebox[\TUMBr]{#2}}\abs}
+
+\newcommand{\Title}[1]{%
+  \begin{center}{\LARGE\bf\Lecture}\\[1ex]{\bf Exercise Sheet #1}\end{center}}
+
+\newcommand{\ExerciseSheet}[2]{%
+  \pagestyle{empty}%
+  \setcounter{sheet}{#1}%
+  \vspace*{-2cm}\Header{\Prof}{\Tutor}{\Semester}{#2}{}\vspace*{1cm}%
+  \Title{#1}\abs}
+
+\newcounter{exercise}
+\newcommand{\Exercise}[1]{%
+  \refstepcounter{exercise}%
+  \pagebreak[3]%
+  \relax%
+  \vspace{0.8em}%
+  \subsection*{{Exercise \arabic{sheet}.\arabic{exercise}\ \ \normalfont\sffamily #1}}}
+
+\newcommand{\Homework}[2]{%
+  \pagebreak[3]%
+  \relax%
+  \vspace{0.8em}%
+  \subsection*{{Homework \arabic{sheet}\ \ \normalfont\sffamily #1}}%
+  \emph{Submission until Friday, #2, 11:59am.}}
+
+\newcommand{\NumHomework}[2]{%
+  \refstepcounter{homework}%
+  \pagebreak[3]%
+  \relax%
+  \vspace{0.8em}%
+  \subsection*{{Homework \arabic{sheet}.\arabic{homework}\ \ \normalfont\sffamily #1}}%
+  \emph{Submission until Friday, #2, 11:59am.}}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/document/root.tex	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,71 @@
+\documentclass[11pt,a4paper]{scrartcl}
+\usepackage{isabelle,isabellesym}
+% \usepackage{exercise}
+\usepackage{amsmath}
+
+% further packages required for unusual symbols (see also
+% isabellesym.sty), use only when needed
+
+\usepackage{amssymb}
+  %for \<leadsto>, \<box>, \<diamond>, \<sqsupset>, \<mho>, \<Join>,
+  %\<lhd>, \<lesssim>, \<greatersim>, \<lessapprox>, \<greaterapprox>,
+  %\<triangleq>, \<yen>, \<lozenge>
+
+%\usepackage[greek,english]{babel}
+  %option greek for \<euro>
+  %option english (default language) for \<guillemotleft>, \<guillemotright>
+
+\usepackage[latin1]{inputenc}
+  %for \<onesuperior>, \<onequarter>, \<twosuperior>, \<onehalf>,
+  %\<threesuperior>, \<threequarters>, \<degree>
+
+\usepackage[only,bigsqcap]{stmaryrd}
+  %for \<Sqinter>
+
+%\usepackage{eufrak}
+  %for \<AA> ... \<ZZ>, \<aa> ... \<zz> (also included in amssymb)
+
+%\usepackage{textcomp}
+  %for \<cent>, \<currency>
+
+% this should be the last package used
+\usepackage{pdfsetup}
+
+% urls in roman style, theory text in math-similar italics
+\urlstyle{rm}
+\isabellestyle{it}
+
+% for uniform font size
+%\renewcommand{\isastyle}{\isastyleminor}
+
+\begin{document}
+
+% sane default for proof documents
+\parindent 0pt\parskip 0.5ex
+
+
+\renewcommand{\isachardoublequote}{`\"}
+\renewcommand{\isachardoublequoteopen}{``}
+\renewcommand{\isachardoublequoteclose}{''}
+\renewcommand{\isacharunderscore}{\_}
+\renewcommand{\isacharunderscorekeyword}{\_}
+
+\newcommand{\Homework}[2]{\section*{#1}}
+\newcommand{\NumHomework}[2]{\section*{#1}}
+
+\newcommand{\hwsol}[1]{\clearpage{\huge\center{Solution for Homework #1}}\\[3em]}
+
+
+% generated text of all theories
+\input{session}
+
+% optional bibliography
+%\bibliographystyle{abbrv}
+%\bibliography{root}
+
+\end{document}
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: t
+%%% End:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol01.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,77 @@
+text_raw \<open>\hwsol{1}\<close>
+theory hwsol01
+imports Main
+begin
+fun snoc :: "'a list \<Rightarrow> 'a \<Rightarrow> 'a list"  where
+"snoc [] x = [x]" |
+"snoc (y # ys) x = y # (snoc ys x)" 
+
+fun reverse :: "'a list \<Rightarrow> 'a list"  where
+"reverse [] = []" |
+"reverse (x # xs) = snoc (reverse xs) x" 
+
+
+text {* \NumHomework{Maximum Value in List}{May 5} *}
+
+text \<open>
+  Submit your solution via \url{https://vmnipkow3.in.tum.de}.
+  Submit a theory file that runs in Isabelle-2016-1 {\bfseries without errors}.
+  
+  General hints:
+  \begin{itemize}
+    \item If you cannot prove a lemma, that you need for a subsequent
+    proof, assume this lemma by using sorry.
+    \item Define the functions as simple as possible.
+      In particular, do not try to make them tail recursive by 
+      introducing extra accumulator parameters --- this will 
+      complicate the proofs!
+    \item All proofs should be straightforward, and take only a few 
+      lines.
+  \end{itemize}  
+
+  Define a function that returns the maximal element of a list of natural numbers.
+  The result for the empty list shall be $0$.
+\<close>
+fun lmax :: "nat list \<Rightarrow> nat" 
+
+  where
+  "lmax [] = 0"
+| "lmax (a#xs) = max a (lmax xs)"
+
+
+text \<open>Define a function that checks whether an element is contained in a list\<close>  
+fun lcont :: "'a \<Rightarrow> 'a list \<Rightarrow> bool" 
+
+where
+    "lcont x [] \<longleftrightarrow> False"
+  | "lcont x (y#ys) \<longleftrightarrow> (if x=y then True else lcont x ys)"  
+  
+  
+text \<open>Show that the maximum is greater or equal to every element of the list.\<close>
+lemma max_greater: "lcont x xs \<Longrightarrow> x\<le>lmax xs"
+
+  by (induction xs) (auto split: if_splits)
+  
+text \<open>Hint: If you see an \<open>if then else\<close> term in your premises, 
+  try to pass the option \<open>split: if_splits\<close> to @{method auto} or @{method simp},
+  e.g. \<open>apply (auto split: if_splits)\<close>
+\<close>
+  
+text \<open>Prove that reversing the list does not affect its maximum.
+  Note that we use the @{const reverse} function from exercise 4 here.
+\<close>
+
+lemma [simp]: "lmax (snoc xs a) = max a (lmax xs)"
+  by (induction xs) auto
+
+lemma "lmax (reverse xs) = lmax xs"
+
+  by (induction xs) (auto)
+
+text \<open>Hint: Induction. You may need an auxiliary lemma about 
+  @{const lmax} and @{const snoc}.\<close>
+
+
+end
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol02.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,151 @@
+text_raw \<open>\hwsol{2}\<close>
+
+theory hwsol02
+imports Complex_Main
+begin
+
+
+
+
+    
+text \<open>\NumHomework{Distinct lists}{May 12}
+  Submit your solution via \url{https://vmnipkow3.in.tum.de}.
+  Submit a theory file that runs in Isabelle-2016-1 {\bfseries without errors}.
+
+  Define a function \<open>contains\<close>, that checks whether an element is contained 
+  in a list. Define the function directly, not using \<open>set\<close>.
+\<close>    
+fun contains :: "'a \<Rightarrow> 'a list \<Rightarrow> bool"
+  
+  where
+  "contains x [] = False"
+| "contains x (y#ys) \<longleftrightarrow> x=y \<or> contains x ys"  
+  
+   
+text \<open>Define a predicate \<open>ldistinct\<close> to characterize \emph{distinct} lists, i.e., 
+  lists whose elements are pairwise disjoint. Hint: Use the function contains.\<close>
+fun ldistinct :: "'a list \<Rightarrow> bool" 
+  
+  where
+  "ldistinct [] = True"
+| "ldistinct (x#xs) \<longleftrightarrow> \<not>contains x xs \<and> ldistinct xs"  
+  
+  
+text \<open>Show that a reversed list is distinct if and only if the 
+  original list is distinct. Hint: You may require multiple 
+  auxiliary lemmas.\<close>
+  
+lemma [simp]: "contains x (ys@[y]) \<longleftrightarrow> x=y \<or> contains x ys"  
+  by (induction ys) auto
+  
+lemma [simp]: "ldistinct (xs@[x]) \<longleftrightarrow> ldistinct xs \<and> \<not>contains x xs"  
+  by (induction xs) auto
+  
+lemma [simp]: "contains x (rev ys) \<longleftrightarrow> contains x ys"
+  by (induction ys) auto
+    
+lemma "ldistinct (rev xs) \<longleftrightarrow> ldistinct xs"
+  by (induction xs) (auto) 
+    
+text {* \NumHomework{More on fold}{May 12} *}
+
+text \<open>Isabelle's fold function implements a left-fold. Additionally, 
+  Isabelle also provides a right-fold \<open>foldr\<close>.
+
+  Use both functions to specify the length of a list.
+\<close>  
+  
+thm fold.simps
+thm foldr.simps  
+  
+definition length_fold :: "'a list \<Rightarrow> nat"  
+   where
+  "length_fold l \<equiv> fold (\<lambda>_. Suc) l 0"
+  
+
+definition length_foldr :: "'a list \<Rightarrow> nat"  
+   where
+  "length_foldr l \<equiv> foldr (\<lambda>_. Suc) l 0"
+  
+
+  
+lemma aux2: "fold (\<lambda>_. Suc) l a = length l + a"  
+  by (induction l arbitrary: a) auto  
+  
+    
+lemma "length_fold l = length l"  
+  
+  unfolding length_fold_def by (simp add: aux2)
+    
+
+lemma "length_foldr l = length l"  
+  
+  unfolding length_foldr_def by (induction l) auto
+    
+
+
+text {* \NumHomework{List Slices}{May 12} 
+  Specify a function \<open>slice xs s l\<close>, that, for a list
+  \<open>xs=[x\<^sub>0,...,x\<^sub>n]\<close> returns the slice starting at s with length l, i.e.,
+  \<open>[x\<^sub>s,...,x\<^bsub>s+len-1\<^esub>]\<close>.
+
+  If \<open>s\<close> or \<open>len\<close> is out of range, return a shorter (or the empty) list.
+*}
+
+  
+fun slice :: "'a list \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> 'a list" 
+  where
+  
+  "slice (x#xs) (Suc n) l = slice xs n l"
+| "slice (x#xs) 0 (Suc l) = x # slice xs 0 l"  
+| "slice _ _ _ = []"  
+    
+text \<open>Hint: Use pattern matching instead of \<open>if\<close>-expressions. For example, instead
+  of writing \<open>f x = (if x>0 then \<dots> else \<dots>)\<close> you should define two equations
+  \<open>f 0 = \<dots>\<close> and \<open>f (Suc n) = \<dots>\<close>.
+\<close>  
+  
+text \<open>Some test cases, which should all hold, i.e., yield \<open>True\<close>\<close>
+value "slice [0,1,2,3,4,5,6::int] 2 3 = [2,3,4]" -- \<open>In range\<close>
+value "slice [0,1,2,3,4,5,6::int] 2 10 = [2,3,4,5,6]" -- \<open>Length out of range\<close>
+value "slice [0,1,2,3,4,5,6::int] 10 10 = []" -- \<open>Start index out of range\<close>
+  
+  
+text \<open>Show that the length of a list slice is always less than or equal to 
+  the specified length:\<close>  
+lemma "length (slice xs s l) \<le> l"
+  
+  by (induction xs s l rule: slice.induct) auto  
+    
+  
+text \<open>Show that, if the start position and length are in range, the length 
+  of the slice is equal to the specified length\<close>
+lemma "length xs \<ge> s + l \<Longrightarrow> length (slice xs s l) = l"
+  
+  by (induction xs s l rule: slice.induct) auto  
+
+
+    
+text \<open>Show that concatenation of two adjacent slices can be expressed as 
+  a single slice:\<close>
+lemma "slice xs s l1 @ slice xs (s+l1) l2 = slice xs s (l1+l2)"
+  
+  by (induction xs s l1 rule: slice.induct) auto  
+
+
+text \<open>Show that a slice of a distinct list is distinct.\<close>    
+    
+lemma aux1: "contains x (slice xs s l) \<Longrightarrow> contains x xs"    
+  by (induction xs s l rule: slice.induct) auto  
+    
+      
+lemma "ldistinct xs \<Longrightarrow> ldistinct (slice xs s l)"
+    
+  by (induction xs s l rule: slice.induct) (auto simp: aux1)
+    
+    
+    
+
+end
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol03.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,154 @@
+text_raw \<open>\hwsol{3}\<close>
+
+theory hwsol03
+  imports "../../../Public/Demos/BST_Demo"
+begin
+      
+text \<open>
+  \Homework{BSTs with Duplicates}{May 19}
+
+  \<^item> Have a look at @{const bst_eq} in \<open>~~/src/HOL/Library/Tree\<close>, which defines BSTs with duplicate elements.
+  \<^item> Warmup: Show that @{const isin} and @{const ins} are also correct for @{const bst_eq}.
+\<close>
+lemma "bst_eq t \<Longrightarrow> isin t x = (x \<in> set_tree t)"
+
+apply(induction t)
+apply auto
+done
+
+  
+lemma bst_eq_ins: "bst_eq t \<Longrightarrow> bst_eq (ins x t)"
+
+apply(induction t)
+apply (auto simp: set_tree_ins)
+done
+
+
+text \<open>  
+  \<^item> Define a function \<open>ins_eq\<close> to insert into a BST with duplicates.
+\<close>
+fun ins_eq :: "'a::linorder \<Rightarrow> 'a tree \<Rightarrow> 'a tree" 
+
+  where
+"ins_eq x Leaf = Node Leaf x Leaf" |
+"ins_eq x (Node l a r) =
+  (if x < a then Node (ins_eq x l) a r 
+   else Node l a (ins_eq x r))"
+
+  
+  
+text \<open>  
+  \<^item> Show that \<open>ins_eq\<close> preserves the invariant @{const \<open>bst_eq\<close>}
+\<close>
+  
+
+lemma set_tree_ins_eq: "set_tree (ins_eq x t) = insert x (set_tree t)"
+apply(induction t)
+apply auto
+done
+
+    
+lemma bst_eq_ins_eq: "bst_eq t \<Longrightarrow> bst_eq (ins_eq x t)"
+
+apply(induction t)
+apply (auto simp: set_tree_ins_eq)
+done
+
+  
+  
+  
+text \<open>  
+  \<^item> Define a function \<open>count_tree\<close> to count how often a given element occurs in a tree
+\<close>
+fun count_tree :: "'a \<Rightarrow> 'a tree \<Rightarrow> nat" 
+
+  where
+  "count_tree x Leaf = 0"
+| "count_tree x (Node l y r) = count_tree x l + (if x=y then 1 else 0) + count_tree x r"  
+
+  
+text \<open>  
+  \<^item> Show that the \<open>ins_eq\<close> function inserts the desired element, and does not
+    affect other elements.
+\<close>
+lemma "count_tree x (ins_eq x t) = Suc (count_tree x t)"  
+
+  by (induction t) auto
+
+
+lemma "x\<noteq>y \<Longrightarrow> count_tree y (ins_eq x t) = count_tree y t"  
+
+  by (induction t) auto
+
+  
+  
+text \<open>  
+  The next exercise is a bonus exercise, yielding bonus points.
+  Bonus points count as achieved points, but not for the maximum 
+  achievable points, when computing the percentage of the achieved homework 
+  points.
+
+  \<^item> Bonus (5p): Use BSTs with duplicates to sort a list (cf.\ Exercise 3). 
+    Prove that the resulted list is sorted, and contains exactly the 
+    same number of each element as the original list.
+    Hint: Use a \<open>count\<close> function for lists, and relate it with the 
+    \<open>count_tree\<close>-function for trees.
+\<close>      
+
+
+fun count where
+  "count x [] = 0"
+| "count x (y#ys) = (if x=y then Suc (count x ys) else count x ys)"  
+  
+lemma count_append[simp]: "count x (xs@ys) = count x xs + count x ys"  
+  by (induction xs) auto
+  
+lemma [simp]: "x\<noteq>y \<Longrightarrow> count x (inorder (ins_eq y t)) = count x (inorder t)"  
+  apply (induction t)
+  apply auto  
+  done  
+  
+lemma [simp]: "count x (inorder (ins_eq x t)) = Suc (count x (inorder t))"    
+  apply (induction t)
+  apply auto  
+  done  
+
+lemma "count x (inorder t) = count_tree x t"
+  apply (induction t)
+  apply auto  
+  done  
+  
+definition "mk_tree_eq l = fold ins_eq l Leaf"  
+  
+lemma bst_mk_tree_eq_aux: "bst_eq t \<Longrightarrow> bst_eq (fold ins_eq l t)"
+  apply (induction l arbitrary: t) apply (auto simp: bst_eq_ins_eq) done
+  
+lemma bst_eq_mk_tree_eq: "bst_eq (mk_tree_eq l)"
+  by (simp add: mk_tree_eq_def bst_mk_tree_eq_aux)
+
+lemma count_mktree_eq_aux: "count x (inorder (fold ins_eq l t)) = count x l + count x (inorder t)"
+  apply (induction l arbitrary: t)
+  apply auto  
+  done  
+
+    
+definition bst_eq_sort :: "'a::linorder list \<Rightarrow> 'a list" 
+
+  where "bst_eq_sort l = inorder (mk_tree_eq l)"
+
+    
+theorem count_bst_eq_sort: "count x (bst_eq_sort l) = count x l"
+
+  by (auto simp: bst_eq_sort_def mk_tree_eq_def count_mktree_eq_aux)  
+
+  
+theorem sorted_bst_eq_sort: "sorted (bst_eq_sort l)"
+
+  by (auto simp: bst_eq_sort_def bst_eq_mk_tree_eq bst_eq_imp_sorted)  
+
+      
+    
+
+end
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol04.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,85 @@
+text_raw \<open>\hwsol{4}\<close>
+
+theory hwsol04
+  imports "../../../Public/Demos/BST_Demo"
+begin
+
+
+    
+text \<open>
+  \Homework{Delete Minimum}{May 26}
+
+  Define a function to return and delete the minimum element from a 
+    non-empty BST. You may omit the equation for the empty tree.
+\<close>    
+fun del_min :: "'a tree \<Rightarrow> 'a * 'a tree" where
+  
+"del_min (Node l a r) =
+   (if l = Leaf then (a,r) else let (a',l') = del_min l in (a', Node l' a r))"
+
+
+text \<open>
+  Show that your function preserves the search tree property.
+  Hint: An auxiliary lemma of the form \<open>t\<noteq>Leaf \<Longrightarrow> del_min t = (x,t') \<Longrightarrow> \<dots>\<close>
+  relating \<open>set_tree t\<close> and \<open>set_tree t'\<close> may be helpful.
+\<close>
+
+lemma del_min_set: "t\<noteq>Leaf \<Longrightarrow> del_min t = (x,t') \<Longrightarrow> set_tree t = insert x (set_tree t')"
+  apply (induction t arbitrary: t') 
+  apply (auto split: if_splits prod.splits)
+  done
+    
+    
+lemma "\<lbrakk>t\<noteq>Leaf; bst t\<rbrakk> \<Longrightarrow> bst (snd (del_min t))" 
+  
+  apply (induction t)
+  apply (auto split: prod.split simp: del_min_set) 
+  done  
+
+
+text \<open>Show that your function returns the first element of the inorder traversal,
+  and a tree whose inorder traversal corresponds to the tail of the original inorder traversal.
+  Hint: You may need auxiliary lemmas. Some subgoals may require more \<open>force\<close>ful methods than \<open>auto\<close>.
+\<close>
+  
+lemma [simp]: "inorder t = [] \<longleftrightarrow> t=Leaf" 
+  by (induction t) auto
+    
+
+lemma "t\<noteq>Leaf \<Longrightarrow> del_min t = (x,t') 
+  \<Longrightarrow> case inorder t of (y#ys) \<Rightarrow> x=y \<and> inorder t' = ys"    
+  
+  apply (induction t arbitrary: t')
+  apply (simp split: prod.splits list.splits if_splits)
+  apply (force split: prod.splits list.splits if_splits)
+  done
+    
+    
+text \<open>Define a function \<open>del_min2\<close> that uses so called continuations: 
+  The second argument is a function which is applied to the result.
+  (i.e. the minimum element and the tree of remaining elements) 
+
+  Do not use \<open>del_min\<close> for the definition, but define \<open>del_min2\<close> recursively, passing 
+  down (modified) continuations.
+\<close>    
+
+fun del_min2 :: "'a tree \<Rightarrow> ('a  \<Rightarrow> 'a tree \<Rightarrow> 'a tree) \<Rightarrow> 'a tree"
+  
+   where
+"del_min2 (Node l a r) nd =
+   (if l = Leaf then nd a r else del_min2 l (\<lambda>a' l'. nd a' (Node l' a r)))"
+
+
+text \<open>Show that your function definition corresponds to \<open>del_min\<close>\<close>
+lemma del_min2_del_min:
+   "t \<noteq> Leaf \<Longrightarrow> del_min2 t f = (let (a,t') = del_min t in f a t')"
+  
+apply(induction t arbitrary: f)
+apply (auto split: prod.splits)
+done
+
+    
+
+end
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol05.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,58 @@
+text_raw \<open>\hwsol{5}\<close>
+
+theory hwsol05
+  imports 
+    Complex_Main 
+    "~~/src/HOL/Library/Tree"
+begin
+
+fun path :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a \<Rightarrow> 'a list \<Rightarrow> 'a \<Rightarrow> bool" 
+  where
+  "path G u [] v \<longleftrightarrow> u=v"
+| "path G u (x#xs) v \<longleftrightarrow> G u x \<and> path G x xs v"  
+
+lemma path_append[simp]: "path G u (p1@p2) v \<longleftrightarrow> (\<exists>w. path G u p1 w \<and> path G w p2 v)"  
+  by (induction p1 arbitrary: u) auto  
+  
+    
+text \<open>
+  \NumHomework{Simple Paths}{June 2}
+  This homework is worth 5 bonus points.
+
+  A simple path is a path without loops, or, in other words, a path 
+  where no node occurs twice. (Note that the first node of the path is 
+  not included, such that there may be a simple path from \<open>u\<close> to \<open>u\<close>.)
+
+  Show that for every path, there is a corresponding simple path:
+\<close>    
+lemma exists_simple_path:
+  assumes "path G u p v"    
+  shows "\<exists>p'. path G u p' v \<and> distinct p'"  
+  using assms  
+proof (induction p rule: length_induct)
+  case (1 p)
+  assume IH: "\<forall>pp. length pp < length p \<longrightarrow> path G u pp v 
+                  \<longrightarrow> (\<exists>p'. path G u p' v \<and> distinct p')"  
+  assume PREM: "path G u p v"
+  show "\<exists>p'. path G u p' v \<and> distinct p'" 
+  text \<open>Fill in your proof here.\<close>  
+    
+  proof cases
+    assume "distinct p"
+    with PREM show ?thesis by auto
+  next
+    assume A: "\<not>distinct p"
+    from not_distinct_decomp[OF A]
+    obtain xs ys zs y where [simp]: "p = xs @ [y] @ ys @ [y] @ zs" by blast
+    then have PP: "path G u (xs@y#zs) v" using PREM by auto
+    have "length (xs@y#zs) < length p" by auto
+    with IH PP obtain p' where P': "path G u p' v" "distinct p'"
+      by blast
+    thus ?thesis by blast
+  qed
+    
+qed
+
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol06.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,146 @@
+text_raw \<open>\hwsol{6}\<close>
+
+theory hwsol06
+  imports 
+    Complex_Main 
+    "~~/src/HOL/Library/Multiset" 
+begin
+
+(* From Sorting.thy *)  
+hide_const List.sorted List.insort List.insort_key
+
+fun sorted :: "'a::linorder list \<Rightarrow> bool" where
+"sorted [] = True" |
+"sorted (x # xs) = ((\<forall>y\<in>set xs. x \<le> y) & sorted xs)"
+
+lemma sorted_append:
+  "sorted (xs@ys) = (sorted xs & sorted ys & (\<forall>x \<in> set xs. \<forall>y \<in> set ys. x\<le>y))"
+by (induct xs) (auto)
+  
+  
+
+  
+      
+text \<open>\Homework{Quicksort}{2.~6.~2017}
+  We extend the notion of a sorting algorithm, by 
+  providing a key function that maps the actual list elements to a linearly 
+  ordered type. The elements shall be sorted according to their keys.
+\<close>
+
+fun sorted_key :: "('a \<Rightarrow> 'b::linorder) \<Rightarrow> 'a list \<Rightarrow> bool" where
+  "sorted_key k [] = True"
+| "sorted_key k (x # xs) = ((\<forall>y\<in>set xs. k x \<le> k y) & sorted_key k xs)"
+
+text \<open>Quicksort can be defined as follows: 
+  (Note that we use \<open>nat\<close> for the keys, as this causes less trouble when 
+  writing Isar proofs than a generic \<open>'b::linorder\<close>)\<close>
+fun qsort :: "('a \<Rightarrow> nat) \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+  "qsort k [] = []"
+| "qsort k (p#xs) = qsort k [x\<leftarrow>xs. k x<k p]@p#qsort k [x\<leftarrow>xs. \<not>k x<k p]"
+text \<open>The syntax @{term \<open>[x\<leftarrow>xs. P x]\<close>} is a shortcut 
+  notation for @{term \<open>filter (\<lambda>x. P x) xs\<close>}.\<close>
+  
+text \<open>Show that quicksort is a sorting algorithm:\<close>  
+lemma qsort_preserves_mset: "mset (qsort k xs) = mset xs"
+  
+  apply (induction k xs rule: qsort.induct)
+  by (auto)
+
+
+  
+lemma qsort_preserves_set: "set (qsort k xs) = set xs"
+  by (metis qsort_preserves_mset set_mset_mset)
+    
+lemma sorted_key_append:
+  "sorted_key k (xs@ys) = (sorted_key k xs & sorted_key k ys & (\<forall>x \<in> set xs. \<forall>y \<in> set ys. k x\<le>k y))"
+    by (induct xs) (auto)
+
+       
+lemma qsort_sorts: "sorted_key k (qsort k xs)"
+  
+  apply (induction k xs rule: qsort.induct)
+  apply (auto simp: sorted_key_append qsort_preserves_set)
+  done
+
+
+
+text \<open>The following is a cost function for the comparsions of quicksort: \<close>    
+fun c_qsort :: "('a \<Rightarrow> nat) \<Rightarrow> 'a list \<Rightarrow> nat" where
+  "c_qsort k [] = 0"
+| "c_qsort k (p#xs) 
+    = c_qsort k [x\<leftarrow>xs. k x<k p] + c_qsort k [x\<leftarrow>xs. k x\<ge>k p] + 2*length xs"
+
+
+text \<open>Show that the number of required comparisons is at most \<open>(length xs)\<^sup>2\<close>.
+
+  Hints: 
+    \<^item> Do an induction on the length of the list,
+      and, afterwards, a case distinction on the list constructors.
+    \<^item> It might be useful to prove \<open>a\<^sup>2+b\<^sup>2 \<le> (a+b)\<^sup>2\<close> for \<open>a b :: nat\<close>
+    \<^item> Have a look at the lemma @{thm [source] sum_length_filter_compl}
+\<close>  
+  
+lemmas length_induct_rule = measure_induct_rule[where f=length, case_names shorter]
+  
+lemma "c_qsort k xs \<le> (length xs)\<^sup>2"
+proof (induction xs rule: length_induct_rule)
+  case (shorter xs) thm shorter.IH
+  show ?case proof (cases xs)
+    case Nil
+    then show ?thesis by auto
+  next
+    case (Cons x xs')
+    text \<open>Insert your proof here\<close>  
+  
+    note Cons[simp]    
+    let ?left = "[xa\<leftarrow>xs' . k xa < k x]"
+    let ?right = "[xa\<leftarrow>xs' . k xa \<ge> k x]"
+    have R_ALT: "?right = [xa\<leftarrow>xs' . \<not> k xa < k x]"
+      by (induction xs') auto
+
+    from shorter.IH have IH: "c_qsort k ys \<le> (length ys)\<^sup>2" if "length ys \<le> length xs'" for ys
+      using that by auto
+
+    have X1: "c_qsort k ?left \<le> (length ?left)\<^sup>2"
+      by (rule IH) auto
+
+    have X2: "c_qsort k ?right \<le> (length ?right)\<^sup>2"
+      by (rule IH) auto
+
+    have "c_qsort k xs = c_qsort k ?left + c_qsort k ?right + 2 * length xs'" by simp
+    also have "\<dots> \<le> (length ?left)\<^sup>2 + (length ?right)\<^sup>2 + 2 * length xs'" using X1 X2 by simp
+    also have "\<dots> \<le> (length ?left + length ?right)\<^sup>2 + 2 * length xs'"
+      by (auto simp: eval_nat_numeral field_simps)
+    also have "\<dots> \<le> (length xs')\<^sup>2 + 2 * length xs'"
+      by (auto simp: R_ALT sum_length_filter_compl)
+    also have "\<dots> \<le> (length xs)\<^sup>2"
+      by (auto simp: eval_nat_numeral)
+    finally show ?thesis .
+
+  qed
+qed
+    
+text \<open>For 3 bonus points, show that quicksort is stable. 
+  You will probably run into subgoals containing terms like  
+  @{term \<open>[x\<leftarrow>xs . k x < k p \<and> k x = a]\<close>}.
+  Try to find a simpler form for them. (Cases on \<open>a<k p\<close>)!
+\<close>     
+lemma qsort_stable: "[x\<leftarrow>qsort k xs . k x = a] = [x\<leftarrow>xs . k x = a]"  
+  
+proof -
+  have [simp]: "[x\<leftarrow>xs . k x < k p \<and> k x = a] = (if a<k p then [x\<leftarrow>xs. k x = a] else [])" for k :: "'a \<Rightarrow> nat" and xs p   
+    by (induction xs) auto
+  have [simp]: "[x\<leftarrow>xs . \<not>k x < k p \<and> k x = a] = (if k p \<le> a then [x\<leftarrow>xs. k x = a] else [])" for k :: "'a \<Rightarrow> nat" and xs p   
+    by (induction xs) auto
+      
+  show ?thesis
+    apply (induction k xs rule: qsort.induct)
+    apply (auto)
+    done  
+      
+qed      
+
+    
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol07.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,80 @@
+text_raw \<open>\hwsol{7}\<close>
+
+theory hwsol07
+  imports 
+    Complex_Main 
+    "~~/src/HOL/Library/Tree"
+begin
+  
+    
+  
+text \<open>
+  \Homework{Cost for \<open>remdups\<close>}{16.~6.~2017}
+
+  The following function removes all duplicates from a list.
+  It uses the auxiliary function \<open>member\<close> to determine 
+  whether an element is contained in a list.
+\<close>  
+
+fun member :: "'a \<Rightarrow> 'a list \<Rightarrow> bool" where
+  "member x [] \<longleftrightarrow> False"
+| "member x (y#ys) \<longleftrightarrow> (if x=y then True else member x ys)"
+  
+fun rem_dups :: "'a list \<Rightarrow> 'a list" where
+  "rem_dups [] = []" |
+  "rem_dups (x # xs) = (if member x xs then rem_dups xs else x # rem_dups xs)"
+  
+text \<open>
+  Show that this function is equal to the HOL standard function @{const \<open>remdups\<close>}
+\<close>  
+  
+lemma member_correct: "member x xs \<longleftrightarrow> x\<in>set xs" by (induction xs) auto
+    
+lemma rem_dups_correct: "rem_dups xs = remdups xs"
+  
+  by (induction xs) (auto simp: member_correct)
+    
+
+text \<open>Define the timing functions for @{const \<open>member\<close>} and @{const rem_dups}, 
+  as described on the slides:\<close>
+fun t_member :: "'a \<Rightarrow> 'a list \<Rightarrow> nat" 
+  
+  where
+  "t_member x [] = 1"
+| "t_member x (y#ys) = 1 + (if x=y then 1 else t_member x ys)"
+  
+  
+fun t_rem_dups :: "'a list \<Rightarrow> nat" 
+  
+  where
+  "t_rem_dups [] = 1" |
+  "t_rem_dups (x # xs) = 1 + t_member x xs + (if member x xs then t_rem_dups xs else 1 + t_rem_dups xs)"
+  
+    
+text \<open>Estimate \<open>t_rem_dups xs\<close> to be quadratic in the length of \<open>xs\<close>.
+  Hint: The estimate @{term \<open>(length xs + 1)\<^sup>2\<close>} should work.
+\<close>
+
+lemma t_member_est: "t_member x xs \<le> length xs + 1"
+  by (induction xs) auto
+  
+lemma "t_rem_dups xs \<le> (length xs+1)\<^sup>2"
+proof (induction xs)
+  case Nil
+  then show ?case by simp
+next
+  case (Cons x xs)
+  have "t_rem_dups (x # xs) \<le> 2 + t_member x xs + t_rem_dups xs"  
+    by auto
+  also have "\<dots> \<le> 3 + length xs + t_rem_dups xs" using t_member_est by auto
+  also have "\<dots> \<le> 3 + length xs + (length xs + 1)\<^sup>2" using Cons.IH by auto
+  also have "\<dots> = 4 + 3*length xs + (length xs)\<^sup>2" by (auto simp: eval_nat_numeral)
+  also have "\<dots> \<le> 4 + 4*length xs + (length xs)\<^sup>2" by auto
+  also have "\<dots> = (length (x # xs) + 1)\<^sup>2" by (auto simp: eval_nat_numeral)
+  finally show ?case .
+qed
+  
+  
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol08.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,242 @@
+text_raw \<open>\hwsol{8}\<close>
+
+theory hwsol08
+  imports 
+    Complex_Main 
+    "../../../Public/Demos/BST_Demo"
+    "~~/src/HOL/Library/Multiset" 
+    (*"~~/src/HOL/Library/List_lexord"*)
+    "~~/src/HOL/Data_Structures/Tree23_Set"
+begin
+  
+  
+locale set_interface =
+  fixes invar :: "'s \<Rightarrow> bool" and \<alpha> :: "'s \<Rightarrow> 'a set"
+  fixes empty :: 's
+  assumes empty_invar: "invar empty" and empty_\<alpha>: "\<alpha> empty = {}"
+  
+  fixes is_in :: "'s \<Rightarrow> 'a \<Rightarrow> bool"  
+  assumes is_in_\<alpha>: "invar s \<Longrightarrow> is_in s x \<longleftrightarrow> x \<in> \<alpha> s"
+    
+  fixes ins :: "'a \<Rightarrow> 's \<Rightarrow> 's"  
+  assumes ins_invar: "invar s \<Longrightarrow> invar (ins x s)" and ins_\<alpha>: "invar s \<Longrightarrow> \<alpha> (ins x s) = Set.insert x (\<alpha> s)"
+   
+  fixes to_list :: "'s \<Rightarrow> 'a list" 
+  assumes to_list_\<alpha>: "invar s \<Longrightarrow> set (to_list s) = \<alpha> s"
+begin  
+
+    
+end  
+
+  
+  
+text \<open>
+  \NumHomework{Estimating the Size of 2-3-Trees}{23.~6.~2017}
+
+    Show that for 2-3-trees, we have:
+    @{text [display] \<open> log\<^sub>3 ( s(t) + 1 ) \<le> h(t) \<le> log\<^sub>2 (s(t) + 1)\<close>}
+
+    Hint: It helps to first raise the two sides of the 
+      inequation to the 2nd/3rd power. 
+      Use sledgehammer and find-theorems to search for the appropriate lemmas.
+\<close>  
+
+  
+lemma height_est_upper_aux: "bal t \<Longrightarrow> 2 ^ height t \<le> size t + 1"
+  by (induction t) auto
+
+    
+lemma height_est_upper: "bal t \<Longrightarrow> height t \<le> log 2 (size t + 1)"
+  
+  using height_est_upper_aux le_log2_of_power by blast
+    
+
+  
+lemma height_est_lower_aux:
+  assumes "bal t"  
+  shows "size t + 1 \<le> 3^(height t)"
+  using assms  
+  by (induction t) auto
+    
+
+lemma height_est_lower: "bal t \<Longrightarrow> log 3 (size t + 1) \<le> height t"
+  
+proof -
+  assume A: "bal t"
+  from log_le_cancel_iff[of 3 "size t + 1" "3^height t"]
+    and height_est_lower_aux[OF A]
+  have "log 3 (size t + 1) \<le> log 3 (3 ^ height t)"
+    apply simp
+    by (metis of_nat_Suc real_of_nat_le_numeral_power_cancel_iff)
+  also have "\<dots> = height t" by (simp add: log_nat_power)
+  finally show ?thesis .
+qed      
+    
+
+text \<open>Define a function to count the number of leaves of a 2-3-tree\<close>  
+fun num_leaves :: "_ tree23 \<Rightarrow> nat" 
+  
+  where
+  "num_leaves \<langle>\<rangle> = 1"
+| "num_leaves \<langle>l,_,r\<rangle> = num_leaves l + num_leaves r"  
+| "num_leaves \<langle>l,_,m,_,r\<rangle> = num_leaves l + num_leaves m + num_leaves r"  
+  
+  
+text \<open>Define a function to determine whether a tree only consists of 2-nodes 
+  and leaves:\<close>  
+fun is_2_tree :: "_ tree23 \<Rightarrow> bool" 
+  
+  where
+  "is_2_tree \<langle>\<rangle> \<longleftrightarrow> True"
+| "is_2_tree \<langle>l,_,r\<rangle> \<longleftrightarrow> is_2_tree l \<and> is_2_tree r"  
+| "is_2_tree _ \<longleftrightarrow> False"  
+  
+
+lemma 
+  assumes "bal t" 
+  assumes "is_2_tree t"  
+  shows "size t + 1 = 2^height t"
+  using assms by (induction t) auto  
+    
+  
+  
+lemma is_2_tree_imp_num_leaves:
+  assumes "bal t" 
+  assumes "is_2_tree t"  
+  shows "num_leaves t = 2^height t"
+  using assms by (induction t) auto  
+  
+lemma num_leaves_lower:
+  assumes "bal t"
+  shows "num_leaves t \<ge> 2^height t"
+  using assms 
+  by (induction t) auto
+    
+lemma num_leaves_imp_is_two_tree:
+  assumes "bal t"
+  assumes "num_leaves t = 2^height t"
+  shows "is_2_tree t"  
+  using assms 
+  apply (induction t)
+  apply auto
+  apply (metis (no_types, lifting) Nat.le_diff_conv2 add_diff_cancel_right' le_add2 le_antisym mult_2 nat_add_left_cancel_le num_leaves_lower)  
+  apply (metis (no_types, lifting) Nat.le_diff_conv2 add_diff_cancel_left' le_add1 le_antisym mult_2 num_leaves_lower)
+  by (smt Nat.add_diff_assoc2 add.commute add_diff_cancel_right' diff_is_0_eq diff_zero le_add1 mult_2 nat.simps(3) num_leaves_lower numeral_2_eq_2 power_eq_0_iff)
+    
+
+text \<open>Show that a 2-3-tree has only 2 nodes, if and only if its number of leafs is 2 to the power of its height!
+
+  Hint: The \<open>\<longrightarrow>\<close> direction is quite easy, the \<open>\<longleftarrow>\<close> direction requires a bit more work!
+\<close>    
+lemma "bal t \<Longrightarrow> is_2_tree t \<longleftrightarrow> num_leaves t = 2^height t"
+  
+  using is_2_tree_imp_num_leaves num_leaves_imp_is_two_tree by blast
+    
+    
+  
+text \<open>
+  \NumHomework{Deforestation}{23.~6.~2017}
+
+    A disadvantage of using the generic algorithms from the set interface for 
+    binary trees (and other data structures) is that they construct an 
+    intermediate list containing the elements of one tree.
+
+    Define a function that folds over the in-order traversal of a binary tree 
+    directly, without constructing an intermediate list, and show that it is 
+    correct.
+
+    Note: Optimizations like this are called deforestation, as they get rid 
+      of intermediate tree-structured data (in our case: lists which are degenerated trees).
+\<close>  
+  
+fun fold_tree :: "('a \<Rightarrow> 's \<Rightarrow> 's) \<Rightarrow> 'a tree \<Rightarrow> 's \<Rightarrow> 's" 
+  
+  where
+  "fold_tree f \<langle>\<rangle> s = s"
+| "fold_tree f \<langle>l,x,r\<rangle> s = fold_tree f r (f x (fold_tree f l s))"  
+  
+  
+lemma "fold_tree f t s = fold f (Tree.inorder t) s"  
+  
+  by (induction t arbitrary: s) auto  
+    
+  
+  
+text \<open>
+  \NumHomework{Bit-Vectors}{23.~6.~2017}
+  {\bf Bonus Homework (3p)}
+
+  A bit-vector is a list of Booleans that encodes a finite set of 
+  natural numbers as follows: A number \<open>i\<close> is in the set, 
+  if \<open>i\<close> is less than the length of the list and the \<open>i\<close>th element of the list 
+  is true.
+
+  For 3 bonus points, define the operations empty, member, insert, and to-list
+  on bit-vectors, and instantiate the set-interface from Exercise~1!
+\<close>  
+  
+type_synonym bv = "bool list"
+  
+definition bv_\<alpha> :: "bv \<Rightarrow> nat set" 
+  where "bv_\<alpha> l = { i. i<length l \<and> l!i }"
+    
+definition bv_empty :: bv 
+  
+  where "bv_empty = []"  
+
+    
+definition bv_member :: "bv \<Rightarrow> nat \<Rightarrow> bool" 
+  
+  where "bv_member l x \<longleftrightarrow> x<length l \<and> l!x"
+
+    
+definition bv_ins :: "nat \<Rightarrow> bv \<Rightarrow> bv" 
+  
+  where "bv_ins x l = (
+    let l = (if x<length l then l else l@replicate (x - length l + 1) False)
+    in l[x := True]
+  )"  
+
+    
+definition bv_to_list :: "bv \<Rightarrow> nat list" 
+  
+  where "bv_to_list l \<equiv> filter (\<lambda>i. l!i) [0..<length l]"
+
+    
+  
+lemma bv_ins_\<alpha>: "bv_\<alpha> (bv_ins x l) = Set.insert x (bv_\<alpha> l)"  
+  apply (rule)
+  subgoal  
+    unfolding bv_\<alpha>_def bv_ins_def
+    apply (auto simp: nth_list_update nth_append nth_Cons')
+    using Suc_less_eq less_Suc_eq_le by fastforce
+  subgoal
+    unfolding bv_\<alpha>_def bv_ins_def
+    by (auto simp: nth_list_update nth_append nth_Cons')
+  done
+  
+    
+lemma bv_to_list_\<alpha>: "set (bv_to_list l) = bv_\<alpha> l"  
+  apply (induction l)
+  unfolding bv_\<alpha>_def bv_to_list_def
+  apply (auto simp: nth_Cons')
+  using less_antisym apply blast  
+  using less_antisym apply blast  
+  done  
+  
+    
+interpretation bv_set: set_interface "\<lambda>_. True" bv_\<alpha> bv_empty bv_member bv_ins bv_to_list
+  
+  apply unfold_locales
+  subgoal by simp  
+  subgoal unfolding bv_\<alpha>_def bv_empty_def by auto
+  subgoal unfolding bv_\<alpha>_def bv_member_def by auto
+  subgoal by simp
+  subgoal by (simp add: bv_ins_\<alpha>)    
+  subgoal by (simp add: bv_to_list_\<alpha>)    
+  done
+  
+  
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol09.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,122 @@
+text_raw \<open>\hwsol{9}\<close>
+
+theory hwsol09
+  imports "../../../Public/Thys/Trie1"
+begin
+  
+    
+text \<open>
+  \NumHomework{Shrunk Trees}{30.~6.~2017}
+
+  Have a look at the @{const delete2} function for tries. It maintains a 
+  ``shrunk'' - property on tries. Identify this property, define a predicate 
+  for it, and show that it is indeed maintained by empty, insert, and delete2!
+\<close>    
+
+fun shrunk :: "trie \<Rightarrow> bool" 
+  
+  where
+  "shrunk Leaf \<longleftrightarrow> True"
+| "shrunk (Node v (l,r)) \<longleftrightarrow> shrunk l \<and> shrunk r \<and> (\<not>v \<longrightarrow> (l,r)\<noteq>(Leaf,Leaf))"
+  
+
+lemma "shrunk Leaf"
+ 
+  by simp 
+
+  
+  
+lemma [simp]: "insert ks t \<noteq> Leaf"
+  by (induction ks t rule: insert.induct) auto  
+  
+    
+lemma "shrunk t \<Longrightarrow> shrunk (insert ks t)"
+  
+  by (induction ks t rule: insert.induct) auto  
+  
+  
+lemma "shrunk t \<Longrightarrow> shrunk (delete2 ks t)"    
+  
+  by (induction t arbitrary: ks) (auto split: list.split)
+  
+    
+  
+text \<open>
+  \NumHomework{Refining Delete}{30.~6.~2017}
+
+  Refine the delete function to intermediate tries and further down 
+  to Patricia tries.
+\<close>    
+    
+datatype itrie = LeafI | UnaryI bool itrie | BinaryI bool "itrie * itrie"
+
+fun abs_itrie :: "itrie \<Rightarrow> trie" -- \<open>Abstraction to tries\<close>  
+  where
+  "abs_itrie LeafI = Leaf"
+| "abs_itrie (UnaryI True t) = Node False (Leaf, abs_itrie t)"
+| "abs_itrie (UnaryI False t) = Node False (abs_itrie t, Leaf)"
+| "abs_itrie (BinaryI v (l,r)) = Node v (abs_itrie l, abs_itrie r)"  
+  
+  
+fun deleteI :: "bool list \<Rightarrow> itrie \<Rightarrow> itrie" where
+  
+  "deleteI ks LeafI = LeafI"
+| "deleteI [] (UnaryI x t) = UnaryI x t"
+| "deleteI (k#ks) (UnaryI x t) = (if k=x then UnaryI x (deleteI ks t) else UnaryI x t)"
+| "deleteI [] (BinaryI _ lr) = BinaryI False lr"  
+| "deleteI (k#ks) (BinaryI v (l,r)) = BinaryI v (if k then (l,deleteI ks r) else (deleteI ks l,r))"  
+  
+
+  
+  lemma [simp]: "abs_itrie (UnaryI k t) = Node False (if k then (Leaf, abs_itrie t) else (abs_itrie t, Leaf))"
+    by auto
+  
+  
+lemma "abs_itrie (deleteI ks t) = delete ks (abs_itrie t)"
+  
+  by (induction ks t rule: deleteI.induct) auto  
+  
+fun unaryP :: "bool \<Rightarrow> ptrie \<Rightarrow> ptrie" where
+  "unaryP x (NodeP xs v lr) = NodeP (x#xs) v lr"
+  
+fun size1P :: "ptrie \<Rightarrow> nat" where
+  "size1P LeafP = 0"
+| "size1P (NodeP ps v (l,r)) = 1 + size ps + size1P l + size1P r"
+  
+lemma [measure_function]: "is_measure size1P" by (rule is_measure_trivial) 
+  
+fun absI_ptrie :: "ptrie \<Rightarrow> itrie" where
+  "absI_ptrie LeafP = LeafI"  
+| "absI_ptrie (NodeP [] v (l,r)) = BinaryI v (absI_ptrie l, absI_ptrie r)"
+| "absI_ptrie (NodeP (x#xs) v (l,r)) = UnaryI x (absI_ptrie (NodeP xs v (l,r)))"
+
+lemma unaryP_refines[simp]: "t\<noteq>LeafP \<Longrightarrow> absI_ptrie (unaryP k t) = UnaryI k (absI_ptrie t)"    
+  by (cases t) auto
+    
+    
+fun pdelete :: "bool list \<Rightarrow> ptrie \<Rightarrow> ptrie"
+  
+  where  
+  "pdelete ks LeafP = LeafP"
+| "pdelete [] (NodeP (x#xs) v lr) = NodeP (x#xs) v lr"
+| "pdelete (k#ks) (NodeP (x#xs) v lr) = (
+      if k=x then unaryP x (pdelete ks (NodeP xs v lr))
+      else NodeP (x#xs) v lr)"
+| "pdelete [] (NodeP [] _ lr) = NodeP [] False lr"  
+| "pdelete (k#ks) (NodeP [] v (l,r)) = NodeP [] v (if k then (l,pdelete ks r) else (pdelete ks l,r))"  
+  
+lemma [simp]: "t\<noteq>LeafP \<Longrightarrow> unaryP k t \<noteq> LeafP" by (cases t) auto
+  
+
+lemma [simp]: "pdelete ks t = LeafP \<longleftrightarrow> t=LeafP"  
+  by (induction ks t rule: pdelete.induct) auto  
+  
+  
+lemma "absI_ptrie (pdelete ks t) = deleteI ks (absI_ptrie t)"  
+
+  by (induction ks t rule: pdelete.induct) auto
+  
+    
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol10.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,101 @@
+text_raw \<open>\hwsol{10}\<close>
+
+theory hwsol10
+imports 
+    "../../../Public/Thys/Leftist_Heap"    
+begin
+  
+  
+text\<open>
+\Homework{Constructing a Heap from a List of Elements}{7.~7.~2017}
+
+The naive solution of starting with the empty heap and inserting the elements one by one
+can be improved by repeatedly merging heaps of roughly equal size.
+Start by turning the list of elements into a list of singleton heaps.
+Now make repeated passes over the list,
+merging adjacent pairs of heaps in each pass (thus halving the list length)
+until only a single heap is left.
+It can be shown that this takes linear time.
+
+Define a function \<open>heap_of_list ::\<close> @{typ "'a list \<Rightarrow> 'a lheap"} and prove its functional
+correctness.
+\<close>
+
+  
+fun mset_forest :: "'a lheap list \<Rightarrow> 'a multiset" 
+  where
+"mset_forest [] = {#}" |
+"mset_forest (x # xs) = mset_tree x + mset_forest xs"
+
+fun merge_adjacent :: "'a::ord lheap list \<Rightarrow> 'a lheap list" where
+"merge_adjacent [] = []" |
+"merge_adjacent [t] = [t]" |
+"merge_adjacent (t\<^sub>1 # t\<^sub>2 # ts) = merge t\<^sub>1 t\<^sub>2 # merge_adjacent ts"
+
+text \<open>For the termination proof of \<open>merge_forest\<close> below.\<close>
+lemma length_merge_adjacent[simp]: "length (merge_adjacent ts) = (length ts + 1) div 2"
+  by (induction ts rule: merge_adjacent.induct) auto
+
+lemma mset_merge_adjacent: "mset_forest (merge_adjacent ts) = mset_forest ts"
+by (induction ts rule: merge_adjacent.induct) (auto simp: mset_merge)
+
+fun merge_forest :: "'a::ord lheap list \<Rightarrow> 'a lheap" where
+"merge_forest [] = Leaf" |
+"merge_forest [x] = x" |
+"merge_forest xs = merge_forest (merge_adjacent xs)"
+
+lemma mset_merge_forest: "mset_tree (merge_forest ts) = mset_forest ts"
+by (induction ts rule: merge_forest.induct) (auto simp: mset_merge mset_merge_adjacent)
+
+  
+  
+definition heap_of_list :: "'a::ord list \<Rightarrow> 'a lheap" 
+  
+  where "heap_of_list xs = merge_forest [Node 1 Leaf x Leaf . x \<leftarrow> xs]"
+  
+
+lemma mset_heap_of_list: "mset_tree (heap_of_list xs) = mset xs"
+  
+  by (induction xs) (auto simp: heap_of_list_def mset_merge_forest)
+  
+  
+  
+lemma heap_merge_adjacent: 
+  "\<forall>h\<in>set hs. heap h \<Longrightarrow> h\<in>set (merge_adjacent hs) \<Longrightarrow> heap h"  
+  by (induction hs rule: merge_adjacent.induct) (auto simp: heap_merge)
+  
+lemma heap_merge_forest: "\<forall>h\<in>set hs. heap h \<Longrightarrow> heap (merge_forest hs)"  
+  apply (induction hs rule: merge_forest.induct)
+  apply (auto simp: heap_merge heap_merge_adjacent)
+  done
+  
+  
+lemma heap_heap_of_list: "heap (heap_of_list xs)"  
+  
+  apply (induction xs) 
+  apply (auto simp: heap_of_list_def heap_merge_forest)
+  done  
+  
+  
+  
+lemma ltree_merge_adjacent: 
+  "\<forall>h\<in>set hs. ltree h \<Longrightarrow> h\<in>set (merge_adjacent hs) \<Longrightarrow> ltree h"  
+  by (induction hs rule: merge_adjacent.induct) (auto simp: ltree_merge)
+  
+lemma ltree_merge_forest: "\<forall>h\<in>set hs. ltree h \<Longrightarrow> ltree (merge_forest hs)"  
+  apply (induction hs rule: merge_forest.induct)
+  apply (auto simp: ltree_merge ltree_merge_adjacent)
+  done
+  
+  
+    
+lemma ltree_ltree_of_list: "ltree (heap_of_list xs)"  
+  
+  apply (induction xs) 
+  apply (auto simp: heap_of_list_def ltree_merge_forest)
+  done  
+  
+    
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol11.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,80 @@
+text_raw \<open>\hwsol{11}\<close>
+
+theory hwsol11
+imports 
+    "../../../Public/Thys/Heap_Prelim"    
+begin
+
+type_synonym rank = nat
+type_synonym snat = "rank list"
+
+abbreviation invar :: "snat \<Rightarrow> bool" where "invar s \<equiv> strictly_ascending s"  
+definition \<alpha> :: "snat \<Rightarrow> nat" where "\<alpha> s = (\<Sum>i\<leftarrow>s. 2^i)"
+  
+  
+lemma \<alpha>_Nil[simp]: "\<alpha> [] = 0"
+  unfolding \<alpha>_def by auto
+  
+lemma \<alpha>_Cons[simp]: "\<alpha> (r#rs) = 2^r + \<alpha> rs"
+  unfolding \<alpha>_def by auto
+
+lemma \<alpha>_append[simp]: "\<alpha> (rs\<^sub>1@rs\<^sub>2) = \<alpha> rs\<^sub>1 + \<alpha> rs\<^sub>2"
+  unfolding \<alpha>_def by auto
+  
+  
+text \<open>
+  \NumHomework{Largest Representable Number}{14.~7.~2017}
+
+  Assume we use numbers \<open>{0..<K}\<close> to represent the ranks in a sparse binary number.
+  Define \<open>max_snat K\<close> to be the largest representable sparse binary number (its value should be \<open>2\<^sup>K-1\<close>), and
+  prove that your definition is correct.
+\<close>  
+
+definition max_snat :: "nat \<Rightarrow> snat" 
+  
+  where "max_snat K = [0..<K]"
+  
+  
+lemma "invar (max_snat K)"
+  
+  unfolding max_snat_def by (induction K) auto
+  
+  
+lemma \<alpha>_max_snat: "\<alpha> (max_snat K) = 2^K - 1"
+  
+  unfolding \<alpha>_def max_snat_def
+  by (simp add: interv_sum_list_conv_sum_set_nat power2sum)
+  
+
+lemma max_snat_bounded: "set (max_snat K) \<subseteq> {0..<K}"
+  
+  unfolding max_snat_def by auto
+  
+    
+lemma max_snat_max:
+  assumes "invar rs"
+  assumes "set rs \<subseteq> {0..<K}"  
+  shows "\<alpha> rs \<le> \<alpha> (max_snat K)"
+  
+  unfolding \<alpha>_max_snat 
+  using assms
+proof (induction rs arbitrary: K rule: rev_induct)
+  case Nil
+  then show ?case by simp
+next
+  case (snoc r rs)
+  from snoc.prems have "invar rs" (*"\<forall>r'\<in>set rs. r'<r"*) "set rs \<subseteq> {0..<r}" by auto
+  from snoc.IH[OF this] have IH: "\<alpha> rs \<le> 2 ^ r - 1" .    
+    
+  from snoc.prems have "r<K" by auto
+  hence "r+1 \<le> K" by auto
+      
+  have "\<alpha> (rs @ [r]) = \<alpha> rs + 2^r" unfolding \<alpha>_def by auto
+  also have "\<dots> \<le> 2^r - 1 + 2^r" using IH by auto
+  also have "\<dots> = 2^(r+1) - 1" by auto
+  also note \<open>r+1 \<le> K\<close>
+  finally show ?case by (auto simp: diff_le_mono)
+qed    
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,75 @@
+text_raw \<open>\hwsol{12}\<close>
+
+theory hwsol12
+imports Complex_Main
+begin
+  
+
+text \<open>
+  \Homework{Dynamic Tables with real-valued Potential}{21.~7.~2017}
+
+In file \<open>Thys/Amortized_Examples\<close> in the repository there is a formalization
+of dynamic tables in locale \<open>Dyn_Tab\<close> with the potential function \<open>\<Phi> (n,l) = 2*n - l\<close>
+and a discussion of why this is tricky. The standard definition you find in textbooks
+does not rely on cut-off subtraction on \<open>nat\<close> but uses standard real numbers:\<close>
+
+type_synonym tab = "nat \<times> nat"
+  
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Start with the locale \<open>Dyn_Tab\<close> in file \<open>Thys/Amortized_Examples\<close>
+but use the above definition of \<open>\<Phi> :: tab \<Rightarrow> real\<close>. A number of proofs will now fail
+because the invariant is now too weak.
+Find a stronger invariant such that all the proofs work again.\<close>
+
+
+locale Dyn_Tab
+begin
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n=0 \<and> l = 0 \<or> l < 2*n \<and> n \<le> l)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+
+  
+end
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsol/hwsol13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,93 @@
+text_raw \<open>\hwsol{13}\<close>
+
+theory hwsol13
+imports "../../../Public/Thys/Skew_Heap"
+begin
+  
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation.
+Restrict yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+
+"get_min (Some(Hp x _)) = x"
+
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+"merge (Hp x lx) (Hp y ly) = 
+    (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+
+
+
+
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h" 
+| "merge_pairs (h1 # h2 # hs) =
+ Some(let h = merge h1 h2 in case merge_pairs hs of None \<Rightarrow> h | Some h' \<Rightarrow> merge h h')"
+
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+
+  "del_min None = None"
+| "del_min (Some(Hp x hs)) = merge_pairs hs"
+
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+
+"mset_heap None = {#}" |
+"mset_heap (Some h) = mset_hp h"
+
+text \<open>and prove the following functional correctness theorems and any lemmas required,
+but excluding preservation of the invariant:\<close>
+
+theorem get_min_in: "get_min (Some h) \<in> set_hp(h)"
+
+by(cases h)(auto)
+
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+
+by(cases h)(auto)
+
+lemma mset_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge Let_def split: option.split)
+
+
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+
+by(cases h) (auto simp: mset_merge_pairs)
+
+
+text \<open>It is recommended to start with the original theory and modify it as much as needed.
+
+Note that function @{const set_hp} is defined automatically by the definition of type \<open>hp\<close>.\<close>
+
+  
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Biendarra_Julian_julian.biendarra@tum.de_588/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+julian.biendarra@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Biendarra_Julian_julian.biendarra@tum.de_588/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,67 @@
+(** Score: 5/5
+*)
+(*<*)
+theory hw12
+imports Complex_Main
+begin
+(*>*)
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> l \<le> 2 * n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - (real l)"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+(*<*)
+end
+(*>*)  
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Biendarra_Julian_julian.biendarra@tum.de_588/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Erhard_Julian_ga48kog@mytum.de_604/Amortized_Examples.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,329 @@
+(** Score: 4/5
+  File contains Isabelle error, l.276: -1
+
+  don't submit files with errors!
+  why not just delete the irrelevant parts, such that I can find your 
+  solution more quickly?
+
+*)
+section "Amortized Complexity: Classical Examples"
+
+theory Amortized_Examples
+imports Complex_Main
+begin
+
+subsection "Binary Counter"
+
+locale Counter
+begin
+
+type_synonym counter = "bool list"
+
+definition init :: counter where
+"init = []"
+
+fun incr :: "counter \<Rightarrow> counter" where
+"incr [] = [True]" |
+"incr (False # bs) = True # bs" |
+"incr (True # bs) = False # incr bs"
+
+fun t_incr :: "counter \<Rightarrow> nat" where
+"t_incr [] = 1" |
+"t_incr (False # bs) = 1" |
+"t_incr (True # bs) = t_incr bs + 1"
+
+definition \<Phi> :: "counter \<Rightarrow> int" where
+"\<Phi> bs = length(filter id bs)"
+
+lemma \<Phi>_non_neg: "\<Phi> bs \<ge> 0"
+by(simp add: \<Phi>_def)
+
+lemma \<Phi>_init: "\<Phi> init = 0"
+by(simp add: \<Phi>_def init_def)
+
+lemma a_incr: "t_incr bs + \<Phi>(incr bs) - \<Phi> bs = 2"
+apply(induction bs rule: incr.induct)
+apply (simp_all add: \<Phi>_def)
+done
+
+(* Application: Doing n increments *)  
+  
+fun n_increments where
+  "n_increments 0 bs = bs"
+| "n_increments (Suc n) bs = n_increments n (incr bs)"  
+  
+fun t_n_increments :: "nat \<Rightarrow> counter \<Rightarrow> nat" where
+  "t_n_increments 0 bs = 1"
+| "t_n_increments (Suc n) bs = t_incr bs + t_n_increments n (incr bs)"
+  
+(* Generalized lemma with arbitrary start state. 
+  Telescoping sum is done implicitly in this proof. *)
+lemma t_n_increments_aux:
+  "t_n_increments n bs = 1 + 2*n + \<Phi> bs - \<Phi> (n_increments n bs)"
+proof (induction n bs rule: n_increments.induct)
+  case (1 bs)
+  then show ?case by simp
+next
+  case (2 n bs)
+  then show ?case 
+    using a_incr[of bs] by auto
+qed
+
+(* Estimation for initial state *)  
+lemma t_n_increments: "t_n_increments n init \<le> 1+2*n"
+  using 
+    t_n_increments_aux[of n init] 
+    \<Phi>_non_neg[of "n_increments n init"] (* Exploit that potential cannot be negative *)
+    \<Phi>_init
+  by auto
+  
+  
+end
+
+
+subsection "Dynamic tables: insert only"
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> l \<le> 2 *  n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - (real l)"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+
+subsection "Queue"
+
+locale Queue
+begin
+
+text \<open>Very simplified model, dequeue returns no result.\<close>
+(* REMARK: Using \<open>unit list\<close> would simplify model even more. *)  
+  
+type_synonym 'a queue = "'a list * 'a list"
+
+definition init :: "'a queue" where
+"init = ([],[])"
+
+fun enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue" where
+"enq x (xs,ys) = (x#xs, ys)"
+
+fun deq :: "'a queue \<Rightarrow> 'a queue" where
+"deq (xs,ys) = (if ys = [] then ([], tl(rev xs)) else (xs, tl ys))"
+
+text \<open>Time: we count only the number of newly allocated list cells.\<close>
+
+fun t_enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> nat" where
+"t_enq x (xs,ys) = 1"
+
+text \<open>We assume that function \<open>rev\<close> has linear complexity.\<close>
+
+fun t_deq :: "'a queue \<Rightarrow> nat" where
+"t_deq (xs,ys) = (if ys = [] then length xs else 0)"
+
+fun \<Phi> :: "'a queue \<Rightarrow> int" where
+"\<Phi> (xs,ys) = length xs"
+
+lemma \<Phi>_non_neg: "\<Phi> q \<ge> 0"
+by(cases q) simp
+
+lemma \<Phi>_init: "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_enq: "t_enq x q + \<Phi>(enq x q) - \<Phi> q = 2"
+by(cases q) auto
+
+lemma a_deq: "t_deq q + \<Phi>(deq q) - \<Phi> q = 0"
+by(cases q) auto
+
+text \<open>
+  Estimating the cost of a sequence of enqueue and dequeue operations.
+  Note: The cost of a dequeue operation on the empty list is just 0, thus
+    that we do not care about the queue being actually non-empty if we 
+    call \<open>deq\<close>.
+\<close>  
+
+lemma "t_deq init = 0" by (auto simp: init_def)
+
+datatype 'a opr = ENQ 'a | DEQ    
+    
+fun execute :: "'a queue \<Rightarrow> 'a opr list \<Rightarrow> 'a queue" where
+  "execute q [] = q"
+| "execute q (ENQ x#ops) = execute (enq x q) ops"  
+| "execute q (DEQ#ops) = execute (deq q) ops"  
+  
+fun t_execute :: "'a queue \<Rightarrow> 'a opr list \<Rightarrow> nat" where
+  "t_execute q [] = 0"
+| "t_execute q (ENQ x#ops) = t_enq x q + t_execute (enq x q) ops"
+| "t_execute q (DEQ#ops) = t_deq q + t_execute (deq q) ops"
+  
+lemma  "t_execute q ops \<le> 2*length ops + \<Phi> q - \<Phi> (execute q ops)"
+  apply (induction q ops rule: execute.induct)
+  apply auto  
+  done
+    
+(* Note: The simplifier re-proves a_enq and a_deq here, as the definitions of 
+  the operations and potential are in the simpset by default.
+
+  This may be nice for simple properties, but for more complex properties,
+  it will just result in very deep unfolding, exploding the subgoals and thus
+  rendering them intractable.
+
+  Thus, we clean up the simpset to not unfold below our abstraction boundary,
+  which is the operations and the potential:
+*)  
+lemmas [simp del] = \<Phi>.simps enq.simps deq.simps t_enq.simps t_deq.simps
+  
+(* This proof structure will also work for more complicated estimates! *)
+lemma t_execute_aux: "t_execute q ops \<le> 2*length ops + \<Phi> q - \<Phi> (execute q ops)"
+proof (induction q ops rule: execute.induct)
+  case (1 q)
+  then show ?case by simp
+next
+  case (2 q x ops)
+  then show ?case using a_enq[of x q] by simp
+next
+  case (3 q ops)
+  then show ?case using a_deq[of q] by simp 
+qed
+   
+  
+lemma t_execute: "t_execute init ops \<le> 2*length ops"    
+  using t_execute_aux[of init ops] \<Phi>_non_neg[of "execute init ops"] 
+  by (auto simp: \<Phi>_init)
+  
+end
+
+
+subsection "Dynamic tables: insert and delete"
+
+locale Dyn_Tab2 = Dyn_Tab
+begin
+
+fun del :: "tab \<Rightarrow> tab" where
+"del (n,l) = (n-1, if n=1 then 0 else if 4*(n-1) < l then l div 2 else l)"
+
+fun t_del :: "tab \<Rightarrow> nat" where
+"t_del (n,l) = (if n=1 then 1 else if 4*(n-1) < l then n else 1)"
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = (if 2*n < l then l/2 - n else 2*n - l)"
+
+lemma \<Phi>_non_negative: "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+by(cases t) auto
+
+lemma \<Phi>_init: "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+by (cases t) (auto split: if_splits)
+
+lemma a_del: "invar t \<Longrightarrow> t_del t + \<Phi>(del t) - \<Phi> t \<le> 2"
+by (cases t) (auto split: if_splits)
+
+lemma init_invar: "invar init" by (auto simp: init_def)
+lemma ins_invar: "invar t \<Longrightarrow> invar (ins t)"  
+  by (cases t) (auto)
+  
+lemma del_invar: "invar t \<Longrightarrow> invar (del t)"  
+  by (cases t) (auto)
+  
+text \<open>Establish reasonable abstraction boundary\<close>    
+lemmas [simp del] = ins.simps t_ins.simps del.simps t_del.simps \<Phi>.simps 
+  
+datatype opr = INS | DEL    
+    
+fun execute :: "tab \<Rightarrow> opr list \<Rightarrow> tab" where
+  "execute t [] = t"
+| "execute t (INS#ops) = execute (ins t) ops"  
+| "execute t (DEL#ops) = execute (del t) ops"  
+  
+fun t_execute :: "tab \<Rightarrow> opr list \<Rightarrow> nat" where
+  "t_execute t [] = 1"
+| "t_execute t (INS#ops) = t_ins t + t_execute (ins t) ops"
+| "t_execute t (DEL#ops) = t_del t + t_execute (del t) ops"
+  
+lemma execute_invar: "invar t \<Longrightarrow> invar (execute t ops)"
+  by (induction t ops rule: execute.induct) (auto simp: ins_invar del_invar)
+  
+(*
+  To use the amortized complexity estimate here,
+  we have to additionally keep track of the invariant.
+*)  
+lemma t_execute_aux: "invar t \<Longrightarrow> t_execute t ops \<le> 1 + 3*length ops + \<Phi> t - \<Phi> (execute t ops)"
+proof (induction t ops rule: execute.induct)
+  case (1 t)
+  then show ?case by simp
+next
+  case (2 t ops)
+  then show ?case
+    using a_ins[of t]
+    by (auto simp: ins_invar)
+      
+next
+  case (3 t ops)
+  then show ?case
+    using a_del[of t]
+    by (auto simp: del_invar)
+
+qed
+  
+lemma t_execute: "t_execute init ops \<le> 1 + 3*length ops"  
+  using 
+    t_execute_aux[of init ops] 
+    \<Phi>_non_negative[OF execute_invar, of init ops]
+    init_invar
+    \<Phi>_init
+  by auto  
+  
+end
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Erhard_Julian_ga48kog@mytum.de_604/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+ga48kog@mytum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Erhard_Julian_ga48kog@mytum.de_604/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.LIY5H1Dhik'
+Files in /tmp/eval-604-OvvpRv: Amortized_Examples.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Groer_Markus_markus.grosser@tum.de_597/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+markus.grosser@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Groer_Markus_markus.grosser@tum.de_597/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,65 @@
+(** Score: 5/5
+*)
+theory hw12
+  imports Complex_Main
+begin
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+  "invar (n,l) = ((n \<ge> l/2) \<and> (n \<le> l))" \<comment> \<open>
+  I spent more time thinking about whether I missed something than on the actual homework @{text \<dots>}
+\<close>
+
+definition init :: tab where
+  "init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+  "ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+  "t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+  by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+  apply(cases t)
+  apply(auto)
+  done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+  "\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+  apply(cases t)
+  apply(auto)
+  done
+
+lemma "\<Phi> init = 0"
+  by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+  apply(cases t)
+  apply(auto split: if_splits)
+  done
+
+end
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Groer_Markus_markus.grosser@tum.de_597/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.4lbWLNqwAj'
+Files in /tmp/eval-597-Ar4dsM: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Haslbeck_Maximilian_max.haslbeck@mytum.de_582/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+max.haslbeck@mytum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Haslbeck_Maximilian_max.haslbeck@mytum.de_582/ex12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,53 @@
+(** Score: 5/5
+*)
+theory ex12
+imports "../Thys/Amortized_Examples"
+begin
+type_synonym tab = "nat \<times> nat"
+
+locale Dyn_Tab
+begin
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> 2 * n \<ge> l)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+  "\<Phi> (n,l) = 2 * (real n) - real l"
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Haslbeck_Maximilian_max.haslbeck@mytum.de_582/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.zCkuBpf1yB'
+Files in /tmp/eval-582-7BZw2v: ex12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hellauer_Fabian_f.hellauer@tum.de_610/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+f.hellauer@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hellauer_Fabian_f.hellauer@tum.de_610/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,63 @@
+(** Score: 5/5
+*)
+theory hw12
+imports Complex_Main
+begin
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (l \<in> {n..2*n})"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+  
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hellauer_Fabian_f.hellauer@tum.de_610/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.WpfyOmWl7j'
+Files in /tmp/eval-610-nYh1sB: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hu_Shuwei_shuwei.hu@tum.de_573/Homework12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,47 @@
+(** Score: 5/5
+*)
+(* Shuwei Hu *)
+
+theory Homework12
+  imports Complex_Main
+begin
+  
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) \<longleftrightarrow> (n \<le> l) \<and> (l \<le> n+n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - (real l)"
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+  
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hu_Shuwei_shuwei.hu@tum.de_573/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+shuwei.hu@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hu_Shuwei_shuwei.hu@tum.de_573/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hutzler_Matthias_ga95luy@mytum.de_602/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+ga95luy@mytum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hutzler_Matthias_ga95luy@mytum.de_602/ex12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,87 @@
+(** Score: 5/5
+  insert was sufficient for this homework.
+*)
+theory ex12
+  imports Complex_Main
+begin
+
+
+  (* Homework 12 *)
+
+(* locale Dyn_Tab copied from Thys/Amortized_Examples and then modified *)  
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) \<longleftrightarrow> n \<le> l \<and> l \<le> 2*n"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - (real l)"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+  
+  
+  (* I am not sure about the scope of this homework.
+     Should the "locale Dyn_Tab2" part be adjusted too? At first I thought so,
+     but then I realised that the definition for the potential \<Phi> from the
+     exercise sheet makes negative potentials unavoidable in presence of the
+     del function from Dyn_Tab2. *)
+
+locale Dyn_Tab2 = Dyn_Tab
+begin
+
+fun del :: "tab \<Rightarrow> tab" where
+"del (n,l) = (n-1, if n=1 then 0 else if 4*(n-1) < l then l div 2 else l)"
+
+(* The definitions of ins and del lead to negative potentials
+   (\<Phi> as given on the exercise sheet) in certain cases. *)
+lemma negative_\<Phi>_example: "\<Phi> (del (del (ins (ins (ins init))))) = -2"
+  unfolding init_def
+    by simp
+  
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Hutzler_Matthias_ga95luy@mytum.de_602/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.vU51WwZNWG'
+Files in /tmp/eval-602-FLVy1u: ex12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Keinholz_Jonas_jonas.keinholz@tum.de_572/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+jonas.keinholz@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Keinholz_Jonas_jonas.keinholz@tum.de_572/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,47 @@
+(** Score: 5/5
+*)
+theory hw12
+  imports Complex_Main
+begin
+
+section \<open>Homework 12 Dynamic Tables with real-valued Potential\<close>
+
+locale Dyn_Tab
+begin
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+  "invar (n,l) \<longleftrightarrow> n \<le> l \<and> l \<le> 2 * n"
+
+definition init :: tab where
+  "init = (0,0)"
+
+fun ins :: "tab \<Rightarrow> tab" where
+  "ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+fun t_ins :: "tab \<Rightarrow> nat" where
+  "t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+  by (simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar (ins t)"
+  by (cases t) auto
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+  "\<Phi> (n,l) = 2 * (real n) - (real l)"
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+  by (cases t) auto
+
+lemma "\<Phi> init = 0"
+  unfolding init_def by auto
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+  by (cases t) (auto split: if_splits)
+
+end
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Keinholz_Jonas_jonas.keinholz@tum.de_572/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.iRwpDnvnBK'
+Files in /tmp/eval-572-JTIOJv: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Kurz_Friedrich_friedrich.kurz@tum.de_606/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+friedrich.kurz@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Kurz_Friedrich_friedrich.kurz@tum.de_606/hw_12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,62 @@
+(** Score: 5/5
+*)
+theory hw_12
+  imports "../../../Public/Thys/Amortized_Examples"
+begin
+  
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (real n \<le> real l & 2*(real n) \<ge> real l)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+  apply(cases t)
+  apply(auto)
+  done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+  "\<Phi> (n, l) = 2 * (real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+  
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Kurz_Friedrich_friedrich.kurz@tum.de_606/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.QZEOO6HM4F'
+Files in /tmp/eval-606-j00vOy: hw_12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Madge_Pimentel_Fabio_fabio.madge@tum.de_594/Amortized_ExamplesX.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,242 @@
+(** Score: 5/5
+  why not simply deleting the irrelevant stuff, such that I can find your solution more easily?
+*)
+
+section "Amortized Complexity: Classical Examples"
+
+theory Amortized_ExamplesX
+imports Complex_Main
+begin
+
+subsection "Binary Counter"
+
+locale Counter
+begin
+
+type_synonym counter = "bool list"
+
+definition init :: counter where
+"init = []"
+
+fun incr :: "counter \<Rightarrow> counter" where
+"incr [] = [True]" |
+"incr (False # bs) = True # bs" |
+"incr (True # bs) = False # incr bs"
+
+fun t_incr :: "counter \<Rightarrow> nat" where
+"t_incr [] = 1" |
+"t_incr (False # bs) = 1" |
+"t_incr (True # bs) = t_incr bs + 1"
+
+definition \<Phi> :: "counter \<Rightarrow> int" where
+"\<Phi> bs = length(filter id bs)"
+
+lemma \<Phi>_non_neg: "\<Phi> bs \<ge> 0"
+by(simp add: \<Phi>_def)
+
+lemma \<Phi>_init: "\<Phi> init = 0"
+by(simp add: \<Phi>_def init_def)
+
+lemma a_incr: "t_incr bs + \<Phi>(incr bs) - \<Phi> bs = 2"
+apply(induction bs rule: incr.induct)
+apply (simp_all add: \<Phi>_def)
+done
+
+(* Application: Doing n increments *)  
+  
+fun n_increments where
+  "n_increments 0 bs = bs"
+| "n_increments (Suc n) bs = n_increments n (incr bs)"  
+  
+fun t_n_increments :: "nat \<Rightarrow> counter \<Rightarrow> nat" where
+  "t_n_increments 0 bs = 1"
+| "t_n_increments (Suc n) bs = t_incr bs + t_n_increments n (incr bs)"
+  
+(* Generalized lemma with arbitrary start state. 
+  Telescoping sum is done implicitly in this proof. *)
+lemma t_n_increments_aux:
+  "t_n_increments n bs = 1 + 2*n + \<Phi> bs - \<Phi> (n_increments n bs)"
+proof (induction n bs rule: n_increments.induct)
+  case (1 bs)
+  then show ?case by simp
+next
+  case (2 n bs)
+  then show ?case 
+    using a_incr[of bs] by auto
+qed
+
+(* Estimation for initial state *)  
+lemma t_n_increments: "t_n_increments n init \<le> 1+2*n"
+  using 
+    t_n_increments_aux[of n init] 
+    \<Phi>_non_neg[of "n_increments n init"] (* Exploit that potential cannot be negative *)
+    \<Phi>_init
+  by auto
+  
+  
+end
+
+
+subsection "Dynamic tables: insert only"
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> l \<le> 2 * n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+  by auto
+
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2 * (real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+  apply(simp)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+  apply(cases t)
+  apply(auto split: if_splits)
+  done
+
+end
+
+
+subsection "Queue"
+
+locale Queue
+begin
+
+text \<open>Very simplified model, dequeue returns no result.\<close>
+(* REMARK: Using \<open>unit list\<close> would simplify model even more. *)  
+  
+type_synonym 'a queue = "'a list * 'a list"
+
+definition init :: "'a queue" where
+"init = ([],[])"
+
+fun enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue" where
+"enq x (xs,ys) = (x#xs, ys)"
+
+fun deq :: "'a queue \<Rightarrow> 'a queue" where
+"deq (xs,ys) = (if ys = [] then ([], tl(rev xs)) else (xs, tl ys))"
+
+text \<open>Time: we count only the number of newly allocated list cells.\<close>
+
+fun t_enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> nat" where
+"t_enq x (xs,ys) = 1"
+
+text \<open>We assume that function \<open>rev\<close> has linear complexity.\<close>
+
+fun t_deq :: "'a queue \<Rightarrow> nat" where
+"t_deq (xs,ys) = (if ys = [] then length xs else 0)"
+
+fun \<Phi> :: "'a queue \<Rightarrow> int" where
+"\<Phi> (xs,ys) = length xs"
+
+lemma \<Phi>_non_neg: "\<Phi> q \<ge> 0"
+by(cases q) simp
+
+lemma \<Phi>_init: "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_enq: "t_enq x q + \<Phi>(enq x q) - \<Phi> q = 2"
+by(cases q) auto
+
+lemma a_deq: "t_deq q + \<Phi>(deq q) - \<Phi> q = 0"
+by(cases q) auto
+
+text \<open>
+  Estimating the cost of a sequence of enqueue and dequeue operations.
+  Note: The cost of a dequeue operation on the empty list is just 0, thus
+    that we do not care about the queue being actually non-empty if we 
+    call \<open>deq\<close>.
+\<close>  
+
+lemma "t_deq init = 0" by (auto simp: init_def)
+
+datatype 'a opr = ENQ 'a | DEQ    
+    
+fun execute :: "'a queue \<Rightarrow> 'a opr list \<Rightarrow> 'a queue" where
+  "execute q [] = q"
+| "execute q (ENQ x#ops) = execute (enq x q) ops"  
+| "execute q (DEQ#ops) = execute (deq q) ops"  
+  
+fun t_execute :: "'a queue \<Rightarrow> 'a opr list \<Rightarrow> nat" where
+  "t_execute q [] = 0"
+| "t_execute q (ENQ x#ops) = t_enq x q + t_execute (enq x q) ops"
+| "t_execute q (DEQ#ops) = t_deq q + t_execute (deq q) ops"
+  
+lemma  "t_execute q ops \<le> 2*length ops + \<Phi> q - \<Phi> (execute q ops)"
+  apply (induction q ops rule: execute.induct)
+  apply auto  
+  done
+    
+(* Note: The simplifier re-proves a_enq and a_deq here, as the definitions of 
+  the operations and potential are in the simpset by default.
+
+  This may be nice for simple properties, but for more complex properties,
+  it will just result in very deep unfolding, exploding the subgoals and thus
+  rendering them intractable.
+
+  Thus, we clean up the simpset to not unfold below our abstraction boundary,
+  which is the operations and the potential:
+*)  
+lemmas [simp del] = \<Phi>.simps enq.simps deq.simps t_enq.simps t_deq.simps
+  
+(* This proof structure will also work for more complicated estimates! *)
+lemma t_execute_aux: "t_execute q ops \<le> 2*length ops + \<Phi> q - \<Phi> (execute q ops)"
+proof (induction q ops rule: execute.induct)
+  case (1 q)
+  then show ?case by simp
+next
+  case (2 q x ops)
+  then show ?case using a_enq[of x q] by simp
+next
+  case (3 q ops)
+  then show ?case using a_deq[of q] by simp 
+qed
+   
+  
+lemma t_execute: "t_execute init ops \<le> 2*length ops"    
+  using t_execute_aux[of init ops] \<Phi>_non_neg[of "execute init ops"] 
+  by (auto simp: \<Phi>_init)
+  
+end
+
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Madge_Pimentel_Fabio_fabio.madge@tum.de_594/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+fabio.madge@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Madge_Pimentel_Fabio_fabio.madge@tum.de_594/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.sJIsrFcOMI'
+Files in /tmp/eval-594-gwyznl: Amortized_Examples.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Ouyang_Lena_ga96vup@mytum.de_598/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+ga96vup@mytum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Ouyang_Lena_ga96vup@mytum.de_598/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,61 @@
+(** Score: 5/5
+*)
+theory hw12
+imports Complex_Main
+begin
+subsection "Dynamic tables: insert only"
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = ((n \<le> l) \<and> (l \<le> 2*n))"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - (real l)"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Ouyang_Lena_ga96vup@mytum.de_598/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.vujKdEsBER'
+Files in /tmp/eval-598-DpEGnX: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Rdle_Karl_Jonas_jonas.raedle@tum.de_605/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+jonas.raedle@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Rdle_Karl_Jonas_jonas.raedle@tum.de_605/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,51 @@
+(** Score: 5/5
+*)
+theory hw12
+imports
+  Complex_Main
+begin
+
+locale Dyn_Tab
+begin
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) \<longleftrightarrow> (n \<le> l) \<and> (l \<le> 2 * n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2 * (real n) - (real l)"
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+  
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Rdle_Karl_Jonas_jonas.raedle@tum.de_605/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.lw6Bkh4oHQ'
+Files in /tmp/eval-605-guP0Ih: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Rokopf_Simon_simon.rosskopf@tum.de_601/Amortized_ExamplesX.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,158 @@
+(** Score: 5/5
+  the solution was intended to be easy ... this, unfortunately, makes it a bit boring ;)
+*)
+
+theory Amortized_ExamplesX
+imports Complex_Main
+begin
+
+subsection "Dynamic tables: insert only"
+
+locale Dyn_Tab
+begin
+  
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+type_synonym tab = "nat \<times> nat"
+fun invar :: "tab \<Rightarrow> bool" where 
+(* Boring solution, just add what first offending lemma wants to definition ;) *)
+"invar (n,l) = (n \<le> l \<and> (2*(real n) - real l) \<ge> 0)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done 
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+  
+subsection "Dynamic tables: insert and delete"
+
+(*
+
+No longer possible to proof lemma del_invar. 
+Stuff above requires invariant to be strong enough to show (2*(real n) - real l) \<ge> 0. 
+If one can now proof del_invar, 
+then invariant must hold for (n,l) = (1,4) = del (del (ins (ins (ins init))))
+but it does not...
+ 
+locale Dyn_Tab2 = Dyn_Tab
+begin
+
+fun del :: "tab \<Rightarrow> tab" where
+"del (n,l) = (n-1, if n=1 then 0 else if 4*(n-1) < l then l div 2 else l)"
+
+fun t_del :: "tab \<Rightarrow> nat" where
+"t_del (n,l) = (if n=1 then 1 else if 4*(n-1) < l then n else 1)"
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = (if 2*n < l then l/2 - n else 2*n - l)"
+
+lemma \<Phi>_non_negative: "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+by(cases t) auto
+
+lemma \<Phi>_init: "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+by (cases t) (auto split: if_splits)
+
+lemma a_del: "invar t \<Longrightarrow> t_del t + \<Phi>(del t) - \<Phi> t \<le> 2"
+by (cases t) (auto split: if_splits)
+
+lemma init_invar: "invar init" by (auto simp: init_def)
+lemma ins_invar: "invar t \<Longrightarrow> invar (ins t)"  
+  by (cases t) (auto)
+  
+lemma del_invar: "invar t \<Longrightarrow> invar (del t)" 
+  by (cases t) (auto)
+
+text \<open>Establish reasonable abstraction boundary\<close>    
+lemmas [simp del] = ins.simps t_ins.simps del.simps t_del.simps \<Phi>.simps 
+  
+datatype opr = INS | DEL    
+    
+fun execute :: "tab \<Rightarrow> opr list \<Rightarrow> tab" where
+  "execute t [] = t"
+| "execute t (INS#ops) = execute (ins t) ops"  
+| "execute t (DEL#ops) = execute (del t) ops"  
+  
+fun t_execute :: "tab \<Rightarrow> opr list \<Rightarrow> nat" where
+  "t_execute t [] = 1"
+| "t_execute t (INS#ops) = t_ins t + t_execute (ins t) ops"
+| "t_execute t (DEL#ops) = t_del t + t_execute (del t) ops"
+  
+lemma execute_invar: "invar t \<Longrightarrow> invar (execute t ops)"
+  by (induction t ops rule: execute.induct) (auto simp: ins_invar del_invar)
+  
+(*
+  To use the amortized complexity estimate here,
+  we have to additionally keep track of the invariant.
+*)  
+lemma t_execute_aux: "invar t \<Longrightarrow> t_execute t ops \<le> 1 + 3*length ops + \<Phi> t - \<Phi> (execute t ops)"
+proof (induction t ops rule: execute.induct)
+  case (1 t)
+  then show ?case by simp
+next
+  case (2 t ops)
+  then show ?case
+    using a_ins[of t]
+    by (auto simp: ins_invar)
+      
+next
+  case (3 t ops)
+  then show ?case
+    using a_del[of t]
+    by (auto simp: del_invar)
+
+qed
+  
+lemma t_execute: "t_execute init ops \<le> 1 + 3*length ops"  
+  using 
+    t_execute_aux[of init ops] 
+    \<Phi>_non_negative[OF execute_invar, of init ops]
+    init_invar
+    \<Phi>_init
+  by auto  
+  
+end
+*)
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Rokopf_Simon_simon.rosskopf@tum.de_601/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+simon.rosskopf@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Rokopf_Simon_simon.rosskopf@tum.de_601/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Saporta_Antoine_Jacques_antoine.saporta@tum.de_580/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+antoine.saporta@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Saporta_Antoine_Jacques_antoine.saporta@tum.de_580/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,63 @@
+(** Score: 5/5
+*)
+(*<*)
+theory hw12
+imports Complex_Main
+begin
+(*>*)  
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> l \<le> 2*n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+
+(*<*)  
+end
+(*>*)  
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Saporta_Antoine_Jacques_antoine.saporta@tum.de_580/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Schffeler_Maximilian_maximilian.schaeffeler@tum.de_611/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+maximilian.schaeffeler@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Schffeler_Maximilian_maximilian.schaeffeler@tum.de_611/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,61 @@
+(** Score: 5/5
+*)
+theory hw12
+imports Complex_Main
+begin
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> 2*n \<ge> l)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Schffeler_Maximilian_maximilian.schaeffeler@tum.de_611/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.Ci4f3jckge'
+Files in /tmp/eval-611-XU4W1w: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Somogyi_Daniel_daniel.somogyi@tum.de_578/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+daniel.somogyi@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Somogyi_Daniel_daniel.somogyi@tum.de_578/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,62 @@
+(** Score: 5/5
+*)
+theory hw12
+  imports Complex_Main
+    
+begin
+  subsection "Dynamic tables: insert only"
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = ((n \<le> l) \<and> (if l = 0 then (n = 0) else (l \<le> 2*n)))"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma"invar t \<Longrightarrow> invar(ins t)"
+  by(cases t) auto
+  
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma
+   "invar t \<Longrightarrow> \<Phi> t \<ge> 0" 
+  by(cases t)(auto split:if_splits)
+    
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+end
+  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Somogyi_Daniel_daniel.somogyi@tum.de_578/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.bK1RNA1o7U'
+Files in /tmp/eval-578-p4ZoRZ: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Stevens_Lukas_lukas.stevens@tum.de_574/Ex12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,62 @@
+(** Score: 5/5
+*)
+theory Ex12
+  imports Complex_Main
+begin
+  
+locale Dyn_Tab
+begin
+  
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+  
+type_synonym tab = "nat \<times> nat"
+  
+fun invar :: "tab \<Rightarrow> bool" where
+  "invar (n,l) = (n \<le> l \<and> 2 * n \<ge> l)"
+  
+definition init :: tab where
+  "init = (0,0)"
+  
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+  "ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+  
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+  "t_ins (n,l) = (if n<l then 1 else n+1)"
+  
+lemma "invar init"
+  by(simp add: init_def)
+    
+lemma "invar t \<Longrightarrow> invar(ins t)"
+  apply(cases t)
+  apply(auto)
+  done
+    
+fun \<Phi> :: "tab \<Rightarrow> real" where
+  "\<Phi> (n,l) = 2*(real n) - real l"
+  
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+  
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+  apply(cases t)
+  apply(auto)
+  done
+    
+lemma "\<Phi> init = 0"
+  by(simp add: init_def)
+    
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+  apply(cases t)
+  apply(auto split: if_splits)
+  done    
+end
+  
+end
+  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Stevens_Lukas_lukas.stevens@tum.de_574/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+lukas.stevens@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Stevens_Lukas_lukas.stevens@tum.de_574/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.KYWCgOsZm2'
+Files in /tmp/eval-574-0x5b0D: Ex12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Stwe_Daniel_daniel.stuewe@tum.de_603/HW12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,62 @@
+(** Score: 5/5
+*)
+theory HW12
+imports Complex_Main
+begin
+
+subsection "Dynamic tables: insert only"
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) = (n \<le> l \<and> l \<le> n*2)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) =  2 * (real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto) 
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: )
+done
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Stwe_Daniel_daniel.stuewe@tum.de_603/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+daniel.stuewe@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Stwe_Daniel_daniel.stuewe@tum.de_603/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.7Jrpb8mkcx'
+Files in /tmp/eval-603-LBPOFL: HW12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Totakura_Sree_Harsha_sreeharsha.totakura@mytum.de_599/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+sreeharsha.totakura@mytum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Totakura_Sree_Harsha_sreeharsha.totakura@mytum.de_599/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,66 @@
+(** Score: 5/5
+*)
+theory hw12
+  imports Complex_Main
+begin
+  
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+text \<open>The invariant needs to be extended with one more clause to specify that the length of the list
+will never be more than twice the number of elements.  This is because we only double the length
+once the list is full.\<close>
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) \<longleftrightarrow> (n \<le> l) \<and> (l \<le> 2 * n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma invar_init: "invar init"
+  by (simp add: init_def)
+
+lemma invar_ins: "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+text \<open>Careful: \<open>n\<close> and \<open>l\<close> are natural numbers.
+Thus \<open>2*n\<close> can be less than \<open>l\<close> (in which case \<open>2*n - l = 0\<close>!)
+because the invariant does not exclude this case, although it cannot arise.
+If you go through the proof of lemma \<open>a_ins\<close> in detail
+you will understand why this case also works out fine.\<close>
+
+lemma potential_ge_0: "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma potential_init_zero: "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+  apply(cases t)
+  apply auto
+done
+
+end
+
+end
+  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Totakura_Sree_Harsha_sreeharsha.totakura@mytum.de_599/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.C9lNgx77mu'
+Files in /tmp/eval-599-KbDMfv: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Wauligmann_Martin_martin.wauligmann@tum.de_593/SENTMAIL	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,1 @@
+martin.wauligmann@tum.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Wauligmann_Martin_martin.wauligmann@tum.de_593/hw12.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,56 @@
+(** Score: 5/5
+*)
+theory hw12
+imports Complex_Main
+begin
+
+locale Dyn_Tab
+begin
+
+text\<open>Because we are not interested in the elements of the dynamic table but merely its size
+we abstract it to a pair \<open>(n,l)\<close> where \<open>n\<close> is the number of elements in the table and \<open>l\<close>
+the size of the table.\<close>
+
+type_synonym tab = "nat \<times> nat"
+
+fun invar :: "tab \<Rightarrow> bool" where
+"invar (n,l) \<longleftrightarrow> (n \<le> l) \<and> (l \<le> 2*n)"
+
+definition init :: tab where
+"init = (0,0)"
+
+text\<open>Insertion: the element does not matter\<close>
+fun ins :: "tab \<Rightarrow> tab" where
+"ins (n,l) = (n+1, if n<l then l else if l=0 then 1 else 2*l)"
+
+text\<open>Time: if the table overflows, we count only the time for copying elements\<close>
+fun t_ins :: "nat \<times> nat \<Rightarrow> nat" where
+"t_ins (n,l) = (if n<l then 1 else n+1)"
+
+lemma "invar init"
+by(simp add: init_def)
+
+lemma "invar t \<Longrightarrow> invar(ins t)"
+apply(cases t)
+apply(auto)
+done
+
+fun \<Phi> :: "tab \<Rightarrow> real" where
+"\<Phi> (n,l) = 2*(real n) - real l"
+
+lemma "invar t \<Longrightarrow> \<Phi> t \<ge> 0"
+apply(cases t)
+apply(auto)
+done
+
+lemma "\<Phi> init = 0"
+by(simp add: init_def)
+
+lemma a_ins: "invar t \<Longrightarrow> t_ins t + \<Phi>(ins t) - \<Phi> t \<le> 3"
+apply(cases t)
+apply(auto split: if_splits)
+done
+
+end
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/Wauligmann_Martin_martin.wauligmann@tum.de_593/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.hmCTP05ckL'
+Files in /tmp/eval-593-vNTfz9: hw12.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/12/meta.csv	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,20 @@
+"572","jonas.keinholz@tum.de","Keinholz","Jonas","http://vmnipkow3.in.tum.de/web/submissions/572"
+"573","shuwei.hu@tum.de","Hu","Shuwei","http://vmnipkow3.in.tum.de/web/submissions/573"
+"574","lukas.stevens@tum.de","Stevens","Lukas","http://vmnipkow3.in.tum.de/web/submissions/574"
+"578","daniel.somogyi@tum.de","Somogyi","Daniel","http://vmnipkow3.in.tum.de/web/submissions/578"
+"580","antoine.saporta@tum.de","Saporta","Antoine Jacques","http://vmnipkow3.in.tum.de/web/submissions/580"
+"582","max.haslbeck@mytum.de","Haslbeck","Maximilian","http://vmnipkow3.in.tum.de/web/submissions/582"
+"588","julian.biendarra@tum.de","Biendarra","Julian","http://vmnipkow3.in.tum.de/web/submissions/588"
+"593","martin.wauligmann@tum.de","Wauligmann","Martin","http://vmnipkow3.in.tum.de/web/submissions/593"
+"594","fabio.madge@tum.de","Madge Pimentel","Fabio","http://vmnipkow3.in.tum.de/web/submissions/594"
+"597","markus.grosser@tum.de","Groer","Markus","http://vmnipkow3.in.tum.de/web/submissions/597"
+"598","ga96vup@mytum.de","Ouyang","Lena","http://vmnipkow3.in.tum.de/web/submissions/598"
+"599","sreeharsha.totakura@mytum.de","Totakura","Sree Harsha","http://vmnipkow3.in.tum.de/web/submissions/599"
+"601","simon.rosskopf@tum.de","Rokopf","Simon","http://vmnipkow3.in.tum.de/web/submissions/601"
+"602","ga95luy@mytum.de","Hutzler","Matthias","http://vmnipkow3.in.tum.de/web/submissions/602"
+"603","daniel.stuewe@tum.de","Stwe","Daniel","http://vmnipkow3.in.tum.de/web/submissions/603"
+"604","ga48kog@mytum.de","Erhard","Julian","http://vmnipkow3.in.tum.de/web/submissions/604"
+"605","jonas.raedle@tum.de","Rdle","Karl Jonas","http://vmnipkow3.in.tum.de/web/submissions/605"
+"606","friedrich.kurz@tum.de","Kurz","Friedrich","http://vmnipkow3.in.tum.de/web/submissions/606"
+"610","f.hellauer@tum.de","Hellauer","Fabian","http://vmnipkow3.in.tum.de/web/submissions/610"
+"611","maximilian.schaeffeler@tum.de","Schffeler","Maximilian","http://vmnipkow3.in.tum.de/web/submissions/611"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Biendarra_Julian_julian.biendarra@tum.de_613/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,73 @@
+(*<*)
+theory hw13
+imports "~~/src/HOL/Library/Multiset"
+begin
+(*>*)
+  
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+"get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    Some (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h" 
+| "merge_pairs (h1 # h2 # hs) = merge (merge (Some h1) (Some h2)) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs hs"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun pheap :: "('a :: linorder) heap \<Rightarrow> bool" where
+"pheap None = True" |
+"pheap (Some h) = php h"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap None = {#}" |
+"mset_heap (Some h) = mset_hp h"
+
+lemma get_min_in: "get_min (Some h) \<in> set_hp(h)"
+by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+by(cases h)(auto)
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min (Some h)#}"
+by(cases h) (auto simp: mset_merge_pairs)
+
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Biendarra_Julian_julian.biendarra@tum.de_613/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Erhard_Julian_ga48kog@mytum.de_623/Ex13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,120 @@
+theory Ex13
+imports "~~/src/HOL/Library/Multiset"
+begin
+
+subsection \<open>Definitions\<close>
+
+text
+\<open>This implementation follows Okasaki \cite{Okasaki}.
+It satisfies the invariant that \<open>Empty\<close> only occurs
+at the root of a pairing heap. The functional correctness proof does not
+require the invariant but the amortized analysis (elsewhere) makes use of it.\<close>
+
+
+datatype 'a hp =  Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+"get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then (Some (Hp x (Hp y ly # lx))) else (Some (Hp y (Hp x lx # ly))))"
+
+hide_const (open) insert
+
+fun insert :: "'a \<Rightarrow> ('a :: linorder) heap \<Rightarrow> 'a heap" where
+"insert x h = merge (Some (Hp x [])) h"
+
+fun merge_pairs :: "('a :: linorder) heap list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = h" 
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs (map Some hs)"
+
+
+subsection \<open>Correctness Proofs\<close>
+
+subsubsection \<open>Invariants\<close>
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+(*
+lemma pheap_merge: "php h1 \<Longrightarrow> php h2 \<Longrightarrow> php (merge (Some h1) (Some h2))"
+  sorry (*
+by (induction h1 h2 rule: merge.induct) fastforce+
+*)
+lemma pheap_insert: "pheap h \<Longrightarrow> pheap (insert x h)"
+  sorry (*
+by (auto simp: pheap_merge)
+*)
+lemma pheap_merge_pairs: "\<forall>h \<in> set hs. php h \<Longrightarrow> php (merge_pairs (map Some hs))"
+  sorry(*
+by(induction hs rule: merge_pairs.induct) (auto simp: pheap_merge)
+*)
+lemma pheap_del_min: "pheap h \<Longrightarrow> pheap (del_min h)"
+by(cases h) (auto intro!: pheap_merge_pairs)
+*)
+
+subsubsection \<open>Functional Correctness\<close>
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+  
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap None = {#}" |
+"mset_heap (Some (Hp x hs)) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+lemma get_min_in: "get_min (Some h) \<in> set_hp(h)"
+by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk>php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+by(cases h)(auto)
+
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_insert: "mset_heap (insert a h) = {#a#} + mset_heap h"
+by(cases h) (auto simp add: mset_merge insert_def add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_heap(mset hs))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+
+lemma mset_heap_mset_hp: "mset_heap (Some h) = mset_hp h"
+  by (cases h) auto
+lemma mset_hp_mset_heap: "mset_hp h = mset_heap (Some h)"
+  by (cases h) auto
+    
+lemma image_mset_heap_mset_hp: "image_mset mset_heap(mset (map Some xs)) = image_mset mset_hp(mset xs)"
+proof (induction xs)
+  case Nil
+  then show ?case by auto
+next
+  case (Cons a xs)
+  then show ?case
+  by (simp add: mset_heap_mset_hp)
+qed
+    
+thm "mset_hp.simps"
+    
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+proof (cases h)
+  case (Hp x xs)
+  have a: "mset_hp (Hp x xs) =  {#x#} + \<Union>#mset (map mset_hp xs) " by simp
+  from a  have c: "mset_hp (Hp x xs) - {#get_min(Some (Hp x xs))#} = \<Union>#mset (map mset_hp xs)" by simp
+  
+  have "mset_heap (del_min (Some (Hp x xs))) = mset_heap (merge_pairs (map Some xs)) " by simp
+  also have "... = Union_mset(image_mset mset_heap(mset (map Some xs)))" by (auto simp add: mset_merge_pairs)
+  also have "... = Union_mset(image_mset mset_hp(mset xs))" using image_mset_heap_mset_hp by metis
+  also have "... = \<Union>#mset (map mset_hp xs) " by auto 
+      
+  finally show ?thesis using c Hp by simp
+qed
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Erhard_Julian_ga48kog@mytum.de_623/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Gnther_Jochen_jochen.guenther@mytum.de_624/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,84 @@
+(*<*)
+theory hw13
+imports "~~/src/HOL/Library/Multiset"
+begin
+(*>*)
+  
+text \<open>Homework Pairing Heap 
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+subsection \<open>Definitions\<close>
+
+text
+\<open>This implementation follows Okasaki \cite{Okasaki}.
+It satisfies the invariant that \<open>Empty\<close> only occurs
+at the root of a pairing heap. The functional correctness proof does not
+require the invariant but the amortized analysis (elsewhere) makes use of it.\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) = x"  
+  
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some (Hp y (Hp x lx # ly)))"
+
+fun merge_pairs :: "('a :: linorder) heap list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = h" 
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs (map Some hs)"
+  
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}" |
+  "mset_heap (Some (Hp x hs)) = mset_hp (Hp x hs)"
+  
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)"
+  by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by(cases h)(auto)
+    
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+  by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+    
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_heap(mset hs))"
+  by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+    
+lemma aux: "image_mset mset_heap (image_mset Some (mset x2)) = image_mset mset_hp (mset x2)"
+  by (metis (no_types, hide_lams) hp.exhaust image_mset_cong mset_heap.simps(2) multiset.map_comp o_apply)
+(*  by (metis image_mset_cong mset_heap.simps(2) mset_hp.cases multiset.map_comp o_apply) *)
+
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  by(cases h) (auto simp: mset_merge_pairs aux)
+    
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Gnther_Jochen_jochen.guenther@mytum.de_624/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Groer_Markus_markus.grosser@tum.de_635/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,67 @@
+(* Original Author: Tobias Nipkow *)
+
+theory hw13
+  imports "~~/src/HOL/Library/Multiset"
+begin
+
+subsection \<open>Definitions\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+
+type_synonym 'a heap = "'a hp option"
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min None = undefined"
+| "get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+  "merge h None = h"
+| "merge None h = h"
+| "merge (Some (Hp x lx)) (Some (Hp y ly)) =
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some (Hp y (Hp x lx # ly)))"
+
+fun merge_pairs :: "('a :: linorder) heap list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = h"
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs (map Some hs)"
+
+subsection \<open>Correctness Proofs\<close>
+
+subsubsection \<open>Invariants\<close>
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+subsubsection \<open>Functional Correctness\<close>
+
+fun mset_hp :: "'a hp \<Rightarrow> 'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset (mset (map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}"
+| "mset_heap (Some h) = mset_hp h"
+
+lemma get_min_in: "get_min (Some h) \<in> set_hp h"
+  by (cases h) auto
+
+lemma get_min_min: "\<lbrakk>php h; x \<in> set_hp h\<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by (cases h) auto
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+  by (induction h1 h2 rule: merge.induct) (auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_heap(mset hs))"
+  by (induction hs rule: merge_pairs.induct) (auto simp: mset_merge)
+
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min (Some h)#}"
+  apply (cases h)
+  apply (simp add: mset_merge_pairs multiset.map_comp)
+  apply (metis comp_apply[of mset_heap Some] mset_heap.simps(2))
+  done \<comment> \<open>I am not very happy with this proof\<close>
+
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Groer_Markus_markus.grosser@tum.de_635/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Haslbeck_Maximilian_max.haslbeck@mytum.de_622/ex13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,136 @@
+(*<*)
+theory ex13
+imports "../Thys/Skew_Heap"
+begin
+(*>*)
+  
+text {* \ExerciseSheet{13}{21.~7.~2017} *}
+  
+  
+text \<open>
+\Exercise{Double-Ended Queues}
+
+Design a double-ended queue where all operations have constant-time amortized
+complexity. Prove functional correctness and constant-time amortized complexity.
+
+For your proofs, it is enough to count the number of newly allocated list cells.
+You may assume that operations @{term \<open>rev xs\<close>} and @{term \<open>xs@ys\<close>} allocate \<open>O(|xs|)\<close> 
+cells.
+
+Explanation: A double-ended queue is like a queue with two further operations:
+Function \<open>enq_front\<close> adds an element at the front (whereas \<open>enq\<close> adds an element at the back).
+Function \<open>deq_back\<close> removes an element at the back (whereas \<open>deq\<close> removes an element at the front).
+Here is a formal specification where the double ended queue is just a list:
+\<close>
+
+abbreviation (input) enq_list :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+"enq_list x xs \<equiv> xs @ [x]"
+
+abbreviation (input) enq_front_list :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+"enq_front_list x xs \<equiv> x # xs"
+
+abbreviation (input) deq_list :: "'a list \<Rightarrow> 'a list" where
+"deq_list xs \<equiv> tl xs"
+
+abbreviation (input) deq_back_list :: "'a list \<Rightarrow> 'a list" where
+"deq_back_list xs \<equiv> butlast xs"
+
+text\<open>
+Hint: You may want to start with the \<open>Queue\<close> implementation in \<open>Thys/Amortized_Examples\<close>.\<close>
+
+type_synonym 'a queue = unit
+  
+consts list_of :: "'a queue \<Rightarrow> 'a list" 
+  
+(* Definitions *)
+
+consts 
+  init :: "'a queue"
+  enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue"
+  enq_front :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue"
+  deq :: "'a queue \<Rightarrow> 'a queue"
+  deq_back :: "'a queue \<Rightarrow> 'a queue"
+
+lemma "list_of init = []" oops
+
+lemma "list_of(enq x q) = enq_list x (list_of q)" oops
+
+lemma "list_of(enq_front x q) = enq_front_list x (list_of q)" oops
+
+lemma "list_of q \<noteq> [] \<Longrightarrow> list_of(deq q) = deq_list (list_of q)" oops
+
+lemma "list_of q \<noteq> [] \<Longrightarrow> list_of(deq_back q) = deq_back_list (list_of q)" oops
+
+    
+(* Define timing functions, counting number of allocated list cells *)
+
+(* Define \<Phi>, and show the standard lemmas, and estimate the amortized 
+  complexity of the operations to be constant time *)    
+
+  
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+"merge (Hp x lx) (Hp y ly) = 
+    (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a hp" where
+  "merge_pairs [h] = h" |
+  "merge_pairs (h1 # h2 # []) = (merge h1 h2)" |
+  "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = None" |
+  "del_min (Some (Hp x [])) = None" |
+  "del_min (Some (Hp x hs)) = Some (merge_pairs hs)" 
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}" |
+  "mset_heap (Some h) = mset_hp h"
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+  by (induction h) (auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by (induction h) (auto)
+
+lemma mset_hp_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+  by (induction h1 h2 rule: merge.induct) (auto)
+
+lemma mset_hp_merge_pairs:
+  "hs \<noteq> [] \<Longrightarrow> mset_hp (merge_pairs hs) = Union_mset(mset(map mset_hp hs))"
+  by (induction hs rule: merge_pairs.induct) (auto simp add: mset_hp_merge)
+
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  by (induction "Some h" rule: del_min.induct) (auto simp add: mset_hp_merge_pairs)
+
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Haslbeck_Maximilian_max.haslbeck@mytum.de_622/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Hellauer_Fabian_f.hellauer@tum.de_616/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,73 @@
+theory hw13
+  imports "../../../Public/Thys/Skew_Heap"
+begin
+
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp a _)) = a"
+
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+"merge (Hp x lx) (Hp y ly) = (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+
+fun insert :: "'a \<Rightarrow> ('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "insert x None = Some (Hp x [])" |
+  "insert x (Some hp) = Some (merge (Hp x []) hp)"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a hp" where
+  "merge_pairs [h] = h" 
+| "merge_pairs [h1,h2] = merge h1 h2"
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = (if hs = [] then None else Some (merge_pairs hs))"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}" |
+  "mset_heap (Some hp) = mset_hp hp"
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "get_min (Some h) \<in> set_hp(h)" 
+  by (cases h) auto
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by (cases h) auto
+  
+lemma mset_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+  by(induction h1 h2 rule: merge.induct) auto
+
+lemma mset_merge_pairs: "hs \<noteq> [] \<Longrightarrow> mset_hp (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+  apply (induction hs rule: merge_pairs.induct)
+     apply (auto simp: mset_merge)
+    done
+
+lemma mset_del_min:
+  "mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  apply (cases h)
+  apply (auto simp: mset_merge_pairs)
+  done
+
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Hellauer_Fabian_f.hellauer@tum.de_616/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Hu_Shuwei_shuwei.hu@tum.de_614/Homework13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,51 @@
+theory Homework13
+imports "material/Thys/Skew_Heap"
+begin
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x hs)) = x"
+
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+"merge (Hp x lx) (Hp y ly) = 
+    (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a hp" where
+  "merge_pairs [h] = h"
+| "merge_pairs [h1, h2] = merge h1 h2"
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min (Some (Hp x hs)) = (if hs=[] then None else Some (merge_pairs hs))"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) \<longleftrightarrow> (\<forall>h\<in>set hs. (\<forall>y\<in>set_hp h. x \<le> y) \<and> php h)"
+  
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}"
+| "mset_heap (Some h) = mset_hp h"
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+  by (cases h) auto
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by (cases h) auto
+    
+lemma mset_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+  by (induction h1 h2 rule: merge.induct) (auto simp: add_ac)
+
+lemma mset_merge_pairs: "hs \<noteq> [] \<Longrightarrow> mset_hp (merge_pairs hs) = Union_mset(image_mset mset_hp (mset hs))"
+  by (induction hs rule: merge_pairs.induct) (auto simp: mset_merge)
+  
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  by (cases h) (auto simp: mset_merge_pairs)
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Hu_Shuwei_shuwei.hu@tum.de_614/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Hutzler_Matthias_ga95luy@mytum.de_650/ex13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,23 @@
+theory ex13
+  imports Complex_Main
+    "~~/src/HOL/Library/Multiset" 
+begin
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+fun get_min :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) = x"
+
+fun mset_hp :: "'a hp \<Rightarrow> 'a multiset" where
+  "mset_hp (Hp x l) = {#x#} + Union_mset(mset(map mset_hp l))"
+  
+fun mset_heap :: "'a heap \<Rightarrow> 'a multiset" where
+  "mset_heap None = {#}" |
+  "mset_heap (Some hp) = mset_hp hp"
+  
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x l) = (\<forall>h\<in> set l. (\<forall>y\<in>#mset_hp h. x\<le>y) \<and> php h)"
+  
+fun set_hp :: "'a hp \<Rightarrow> 'a set" where
+  "set_hp h = set_mset (mset_hp h)"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Hutzler_Matthias_ga95luy@mytum.de_650/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,4 @@
+Using temporary directory '/tmp/tmp.xhsmymVQmJ'
+Files in /tmp/eval-650-4okIhk: ex13.thy
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Keinholz_Jonas_jonas.keinholz@tum.de_612/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,60 @@
+theory hw13
+  imports "~~/src/HOL/Library/Multiset"
+begin
+
+subsection \<open>Definitions\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) =
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some (Hp y (Hp x lx # ly)))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h"
+| "merge_pairs (h1 # h2 # hs) = merge (merge (Some h1) (Some h2)) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs hs"
+
+subsection \<open>Correctness Proofs\<close>
+
+subsubsection \<open>Invariants\<close>
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) \<longleftrightarrow> (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+subsubsection \<open>Functional Correctness\<close>
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset (mset (map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}"
+| "mset_heap (Some h) = mset_hp h"
+
+lemma get_min_in: "get_min (Some h) \<in> set_hp h"
+  by (cases h) (auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp h \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by (cases h) (auto)
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+  by(induction h1 h2 rule: merge.induct) (auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset (image_mset mset_hp (mset hs))"
+  by (induction hs rule: merge_pairs.induct) (auto simp: mset_merge)
+
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min (Some h)#}"
+  by (cases h) (auto simp: mset_merge_pairs)
+
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Keinholz_Jonas_jonas.keinholz@tum.de_612/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Kurz_Friedrich_friedrich.kurz@tum.de_645/hw_13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,153 @@
+(*<*)
+theory hw_13
+imports "../../../Public/Thys/Skew_Heap"
+begin
+(*>*)
+  
+text {* \ExerciseSheet{13}{21.~7.~2017} *}
+  
+  
+text \<open>
+\Exercise{Double-Ended Queues}
+
+Design a double-ended queue where all operations have constant-time amortized
+complexity. Prove functional correctness and constant-time amortized complexity.
+
+For your proofs, it is enough to count the number of newly allocated list cells.
+You may assume that operations @{term \<open>rev xs\<close>} and @{term \<open>xs@ys\<close>} allocate \<open>O(|xs|)\<close> 
+cells.
+
+Explanation: A double-ended queue is like a queue with two further operations:
+Function \<open>enq_front\<close> adds an element at the front (whereas \<open>enq\<close> adds an element at the back).
+Function \<open>deq_back\<close> removes an element at the back (whereas \<open>deq\<close> removes an element at the front).
+Here is a formal specification where the double ended queue is just a list:
+\<close>
+
+abbreviation (input) enq_list :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+"enq_list x xs \<equiv> xs @ [x]"
+
+abbreviation (input) enq_front_list :: "'a \<Rightarrow> 'a list \<Rightarrow> 'a list" where
+"enq_front_list x xs \<equiv> x # xs"
+
+abbreviation (input) deq_list :: "'a list \<Rightarrow> 'a list" where
+"deq_list xs \<equiv> tl xs"
+
+abbreviation (input) deq_back_list :: "'a list \<Rightarrow> 'a list" where
+"deq_back_list xs \<equiv> butlast xs"
+
+text\<open>
+Hint: You may want to start with the \<open>Queue\<close> implementation in \<open>Thys/Amortized_Examples\<close>.\<close>
+
+type_synonym 'a queue = unit
+  
+consts list_of :: "'a queue \<Rightarrow> 'a list" 
+  
+(* Definitions *)
+
+consts 
+  init :: "'a queue"
+  enq :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue"
+  enq_front :: "'a \<Rightarrow> 'a queue \<Rightarrow> 'a queue"
+  deq :: "'a queue \<Rightarrow> 'a queue"
+  deq_back :: "'a queue \<Rightarrow> 'a queue"
+
+lemma "list_of init = []" oops
+
+lemma "list_of(enq x q) = enq_list x (list_of q)" oops
+
+lemma "list_of(enq_front x q) = enq_front_list x (list_of q)" oops
+
+lemma "list_of q \<noteq> [] \<Longrightarrow> list_of(deq q) = deq_list (list_of q)" oops
+
+lemma "list_of q \<noteq> [] \<Longrightarrow> list_of(deq_back q) = deq_back_list (list_of q)" oops
+
+    
+(* Define timing functions, counting number of allocated list cells *)
+
+(* Define \<Phi>, and show the standard lemmas, and estimate the amortized 
+  complexity of the operations to be constant time *)    
+
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+(*
+fun get   min :: “ ( ′a :: linorder ) heap \<Rightarrow> ′a” where 
+fun del min :: “ ′a :: linorder heap \<Rightarrow> ′a heap” 
+where fun php :: “(′a :: linorder) hp \<Rightarrow> bool” where
+fun mset hp :: “ ′a hp \<Rightarrow>′a multiset” where
+fun mset heap :: “ ′a heap \<Rightarrow>′a multiset” where
+*)
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min None = undefined"
+  | "get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+  "merge None h = h"
+| "merge h None = h"
+| "merge (Some (Hp x1 l1)) (Some (Hp x2 l2)) = (if x1 < x2
+  then (Some (Hp x1 (Hp x2 l2 # l1)))
+  else (Some (Hp x2 (Hp x1 l1 # l2)))
+)"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = (Some h)"
+| "merge_pairs (h1 # h2 # hs) = (merge (merge (Some h1) (Some h2)) (merge_pairs hs))"
+  
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = undefined"
+  | "del_min (Some (Hp x l)) = merge_pairs l"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+  
+fun mset_hp :: "'a hp \<Rightarrow> 'a multiset" where
+  "mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}"
+| "mset_heap (Some h) = mset_hp h"
+  
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+  apply(induction h)
+  apply(auto)
+  done
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  apply(induction h)
+  apply(auto)
+  done
+  
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+  unfolding image_mset_def
+  apply(induction hs rule: merge_pairs.induct)
+  subgoal by simp
+  subgoal by (metis comp_def comp_fun_commute.fold_mset_add_mset comp_fun_commute_mset_image fold_mset_empty merge_pairs.simps(2) mset_heap.simps(2) mset_single_iff_right sum_mset.singleton)   
+  subgoal sorry
+  done
+    
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  apply(induction h)
+  apply(auto simp add: mset_merge_pairs)
+  done
+
+(*<*)  
+end
+(*>*)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Kurz_Friedrich_friedrich.kurz@tum.de_645/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.Wv6lTfCF2D'
+Files in /tmp/eval-645-OjgXvL: hw_13.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Madge_Pimentel_Fabio_fabio.madge@tum.de_626/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Madge_Pimentel_Fabio_fabio.madge@tum.de_626/tmpl13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,80 @@
+(*<*)
+theory tmpl13
+imports "Skew_Heap"
+begin
+(*>*)
+  
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+  
+fun get_min :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp m _)) = m"
+  
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+  "merge (Hp l xs) (Hp r ys) = (if l \<le> r then Hp r (Hp l [] # xs @ ys) else Hp l (Hp r [] # xs @ ys))"
+  
+fun merge_list :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_list [] = None" |
+  "merge_list (x#xs) = combine_options merge (Some x) (merge_list xs)"
+  
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = None" | 
+  "del_min (Some (Hp m r)) = merge_list r"
+  
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp m r) =  {#m#} + Union_mset(mset(map mset_hp r))"
+  
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = Mempty" |
+  "mset_heap (Some hp) = mset_hp hp"
+  
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+  
+  (* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+  by(cases h)(auto)
+    
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp h \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by (cases h) auto
+    
+lemma mset_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+  by (induction h1 h2 rule: merge.induct) auto
+    
+lemma mset_merge_pairs: "mset_heap (merge_list hs) = Union_mset(image_mset mset_hp (mset hs))"
+  apply (induction hs rule: merge_list.induct)
+   apply simp_all
+proof -
+  fix x :: "'a hp" and xs :: "'a hp list"
+  assume a1: "mset_heap (merge_list xs) = \<Union>#image_mset mset_hp (mset xs)"
+  have f2: "\<And>h ha. mset_heap (combine_options merge (Some (h::'a hp)) (Some ha)) = mset_hp h + mset_hp ha"
+    by (simp add: mset_merge)
+  have "None = merge_list xs \<longrightarrow> mset_heap (combine_options merge (Some x) (merge_list xs)) = {#} + mset_hp x"
+    by simp
+  then show "mset_heap (combine_options merge (Some x) (merge_list xs)) = mset_hp x + \<Union>#image_mset mset_hp (mset xs)"
+    using a1 f2 by (metis mset_heap.simps option.exhaust union_commute)
+qed
+  
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  by (cases h) (auto simp: mset_merge_pairs)
+
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Ouyang_Lena_ga96vup@mytum.de_627/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,317 @@
+theory hw13
+imports Complex_Main
+  "~~/src/HOL/Library/Multiset"
+  "../../../../Desktop/fds/Thys/Priority_Queue"  
+  "../../../../Desktop/fds/Thys/Heap_Prelim"
+begin
+subsection \<open>Pairing_Heap\<close>
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"   
+(*renamed some functions with a two as a hack to prevent same name function clashes*)
+fun get_min2  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+"get_min2 (Some (Hp x y)) = x"
+fun merge2 :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge2 h None = h" |
+"merge2 None h = h" |
+"merge2 (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some (Hp y (Hp x lx # ly)))"
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h" 
+| "merge_pairs (h1 # h2 # hs) = merge2 (merge2 (Some h1) (Some h2)) (merge_pairs hs)"
+fun del_min2 :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min2 None = None"
+| "del_min2 (Some (Hp x hs)) = merge_pairs hs"
+
+subsection \<open>Correctness Proofs\<close>
+subsubsection \<open>Invariants\<close>
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+(*no preservation of invariant lemmas needed*)
+
+subsubsection \<open>Functional Correctness\<close>
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+fun mset_heap2 :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap2 None = {#}" |
+"mset_heap2 (Some (Hp x hs)) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+theorem get_min_in: "get_min2 (Some h) \<in> set_hp(h)"
+  by(cases h)(auto)
+lemma get_min_min: "\<lbrakk>php h; x \<in> set_hp(h)\<rbrakk> \<Longrightarrow> get_min2 (Some h) \<le> x"
+  by(cases h)(auto)
+lemma mset_merge: "mset_heap2 (merge2 h1 h2) = mset_heap2 h1 + mset_heap2 h2"
+  by(induction h1 h2 rule: merge2.induct)(auto simp: add_ac)
+lemma aux: "mset_heap2 (Some h1) = mset_hp h1"
+  by (cases h1) auto
+lemma mset_merge_pairs: "mset_heap2 (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+  by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge aux)
+lemma mset_del_min: "mset_heap2 (del_min2 (Some h)) = mset_hp h - {#get_min2 (Some h)#}"
+  by(cases h) (auto simp: mset_merge_pairs)
+
+text \<open>Project\<close>
+section \<open>Fibonacci Heaps\<close>    
+datatype 'a Node = Node (rank: nat) (root: 'a) (children: "'a Node list")
+type_synonym 'a Heap = "'a Node list"
+
+subsection \<open>Multiset\<close>
+fun mset_node :: "'a::linorder Node \<Rightarrow> 'a multiset" where
+  "mset_node (Node _ a c) = {#a#} + (\<Sum>t\<in>#mset c. mset_node t)"
+fun mset_heap :: "'a::linorder Heap \<Rightarrow> 'a multiset" where
+  "mset_heap x = (\<Sum>t\<in>#mset x. mset_node t)"
+  
+lemma mset_node[simp]: "mset_node (Node r a c) = {#a#} + mset_heap c" by auto
+lemma mset_node_nonempty[simp]: "mset_node t \<noteq> {#}" by (cases t) auto
+lemma mset_heap_nil[simp]: "mset_heap [] = {#}" by auto
+lemma mset_heap_cons[simp]: "mset_heap (t#ts) = mset_node t + mset_heap ts" by auto
+lemma mset_heap_empty_iff[simp]: "mset_heap ts = {#} \<longleftrightarrow> ts=[]" by auto
+lemma root_in_mset[simp]: "root t \<in># mset_node t" by (cases t) auto    
+lemma mset_heap_rev_eq[simp]: "mset_heap (rev ts) = mset_heap ts" by auto
+
+subsection \<open>Invariants\<close>  
+text \<open>FibHeap invariant:
+In a Fibonacci Heap the first element is the minimum,
+the rest doesn't have to be sorted after rank nor root\<close>
+fun "node_invar" :: "'a::linorder Node \<Rightarrow> bool" where
+  "node_invar (Node r a []) = (\<forall>t\<in>#mset []. node_invar t \<and> a \<le> root t)"|
+  "node_invar (Node r a (x#xs)) = (\<forall>t\<in>#mset (x#xs). node_invar t \<and> a \<le> root t \<and> root x \<le> root t)"
+fun heap_invar :: "'a::linorder Heap \<Rightarrow> bool" where
+  "heap_invar [] = True"|
+  "heap_invar (x#xs) = (\<forall>t\<in>#mset (x#xs). node_invar t \<and> root x \<le> root t)"
+definition invar :: "'a::linorder Heap \<Rightarrow> bool" where
+  "invar x = heap_invar x"
+
+subsection \<open>Operations\<close>
+fun insert :: "'a::linorder \<Rightarrow> 'a Heap \<Rightarrow> 'a Heap" where 
+  "insert a ((Node r x c)#xs) = (if a < x then (Node 0 a [])#(Node r x c)#xs else (Node r x c)#(Node 0 a [])#xs)"|
+  "insert a [] = [(Node 0 a [])]"
+
+lemma insert_heap_invar: "heap_invar ts \<Longrightarrow> heap_invar (insert t ts)"
+  by (induction t ts rule: insert.induct)(auto simp:less_eq_Suc_le[symmetric])
+lemma children_heap_invar:"node_invar (Node r a ts) \<Longrightarrow> heap_invar ts" by (cases ts) auto
+lemma heap_invar_cons: "heap_invar (x#xs) \<Longrightarrow> node_invar x \<and> (\<forall>t\<in>#mset (x#xs). root x \<le> root t)" by auto
+lemma insert_mset: "mset_heap (insert t ts) = {#t#} + mset_heap ts" by (induction t ts rule: insert.induct) auto 
+lemma insert_invar: "invar t \<Longrightarrow> invar (insert x t)" unfolding invar_def by (auto simp: insert_heap_invar)
+  
+fun merge :: "'a::linorder Heap \<Rightarrow> 'a Heap \<Rightarrow> 'a Heap" where
+  "merge xs [] = xs"
+| "merge [] xs = xs"
+| "merge (x#xs) (y#ys) = (if root x < root y then x#xs@y#ys else y#ys@x#xs)"
+  
+lemma merge_simp2: "merge [] xs = xs" by (cases xs) auto        
+lemma merge_heap_invar:
+  assumes "heap_invar xs"
+  assumes "heap_invar ys"
+  shows "heap_invar (merge xs ys)"
+  using assms by (induction xs ys rule: merge.induct) auto
+lemma merge_invar: "\<lbrakk> invar xs; invar ys \<rbrakk> \<Longrightarrow> invar (merge xs ys)"
+  unfolding invar_def by (auto simp: merge_heap_invar)  
+lemma merge_mset: "mset_heap (merge xs ys) = mset_heap xs + mset_heap ys"
+  by (induction xs ys rule: merge.induct) auto
+    
+fun get_min :: "'a::linorder Heap \<Rightarrow> 'a" where
+ "get_min (t#ts) = root t"
+ 
+lemma node_invar_root_min:
+  assumes "node_invar t"
+  assumes "x \<in># mset_node t" 
+  shows "root t \<le> x"  
+  using assms
+  proof (induction t arbitrary: x rule: mset_node.induct)
+    case (1 uu a c)
+    then show ?case sorry
+      (*proof -
+      have a: "node_invar (Node uu a c) \<Longrightarrow> (\<forall>t\<in>#mset c. a \<le> root t)" by (smt Node.sel(2) Node.sel(3) node_invar.elims(2))
+      then have "mset_node (Node uu a c) = {#a#} + (\<Sum>t\<in>#mset c. mset_node t)"
+        by (meson mset_node.simps)
+      also have "... = {#a#} + mset_heap c" by simp
+      also have "... = {#a#} + (\<Sum>t\<in>#mset c. mset_node t)" by simp
+      then have "x \<in># mset_node (Node uu a c) \<Longrightarrow> x \<in># {#a#} + (\<Sum>t\<in>#mset c. mset_node t)"
+        using "1.prems"(2) by auto
+      then have "(x \<in># {#a#}) \<or> (x \<in># (\<Sum>t\<in>#mset c. mset_node t))"
+        using "1.prems"(2) by auto
+      then show ?thesis
+      proof
+        assume "x \<in># {#a#}"
+        then have ?thesis by simp
+      next
+        assume "x \<in># (\<Sum>t\<in>#mset c. mset_node t)"
+        then have ?thesis using 1 a sorry
+      qed*)
+  qed
+ 
+lemma get_min_mset_aux:
+  assumes "ts\<noteq>[]"
+  assumes "heap_invar ts"
+  assumes "x \<in># mset_heap ts"  
+  shows "get_min ts \<le> x"
+  using assms  
+  by (induction ts arbitrary: x rule: get_min.induct)
+    (auto simp: node_invar_root_min intro: order_trans;
+      meson linear order_trans node_invar_root_min)+
+lemma get_min_mset: 
+  assumes "ts\<noteq>[]"
+  assumes "invar ts"
+  assumes "x \<in># mset_heap ts"  
+  shows "get_min ts \<le> x"
+  using assms unfolding invar_def by (auto simp: get_min_mset_aux)
+lemma get_min_member:    
+  assumes "ts\<noteq>[]"    
+  shows "get_min ts \<in># mset_heap ts"  
+  using assms by (induction ts rule: get_min.induct) auto
+lemma get_min:    
+  assumes "mset_heap ts \<noteq> {#}"
+  assumes "invar ts"
+  shows "get_min ts = Min_mset (mset_heap ts)"
+  apply rule
+  using assms get_min_member get_min_mset by auto
+
+fun merge_node ::"'a::linorder Node \<Rightarrow> 'a Node \<Rightarrow> 'a Node " where
+  "merge_node (Node r a c) (Node s b d) = (if a < b then (Node (s+1) a ((Node s b d)#c)) else
+    (Node (r+1) b ((Node r a c)#d)))"
+fun lookup :: "nat \<Rightarrow> 'a Node list \<Rightarrow> 'a Node option" where
+  "lookup x [] = None"|
+  "lookup x ((Node r a c)#xs) = (if r = x then Some (Node r a c) else lookup x xs)"
+fun consolidate :: "'a::linorder Heap \<Rightarrow> 'a Node list \<Rightarrow> 'a Heap" where
+  "consolidate [] l = l"|
+  "consolidate (x#xs) l = (
+    case lookup (rank x) l of None \<Rightarrow> consolidate xs (x#l)
+    |Some t \<Rightarrow> consolidate xs ((merge_node x t)#(filter (\<lambda>q. rank q \<noteq> rank x) l))
+  )"
+fun update_min :: "'a::linorder Heap \<Rightarrow>'a::linorder Heap \<Rightarrow> 'a Node \<Rightarrow> 'a::linorder Heap" where
+  "update_min h [] a = (a#h)"|
+  "update_min h (x#xs) a = (if root x < root a then update_min (a#h) xs x else update_min (x#h) xs a)"
+fun delete_min :: "'a::linorder Heap \<Rightarrow> 'a::linorder Heap" where
+  "delete_min [] = []"|
+  "delete_min (x#xs) = update_min [] (tl (consolidate ((children x)@xs) [])) (hd (consolidate ((children x)@xs) []))"
+lemma update_min_invar: "(\<forall>t\<in>#mset (xs). node_invar t) \<and> (\<forall>t\<in>#mset (h). node_invar t \<and> root t \<ge> root x) \<and> node_invar x
+  \<Longrightarrow> invar (update_min h xs x)"
+  unfolding invar_def apply (induction h xs x rule: update_min.induct)
+  by auto fastforce
+lemma delete_min_invar[simp]:
+  assumes "ts \<noteq> []"
+  assumes "invar ts"
+  shows "invar (delete_min ts)"
+  using assms update_min_invar unfolding invar_def sorry       
+lemma delete_min_mset:        
+  assumes "ts \<noteq> []"
+  shows "mset_heap ts = mset_heap (delete_min ts) + {# find_min ts #}"
+  using assms sorry
+
+subsection \<open>Complexity\<close>
+fun t_insert :: "'a::linorder \<Rightarrow> 'a Heap \<Rightarrow> nat" where
+  "t_insert a ((Node r x c)#xs) = 1"| (*(if, Node cons, # cons, Node cons, # cons)*)
+  "t_insert a [] = 1"
+lemma t_insert_simple_bound: "t_insert t ts \<le> 5" for t 
+  by (induction t ts rule: t_insert.induct) auto
+fun t_merge :: "'a::linorder Heap \<Rightarrow> 'a Heap \<Rightarrow> nat" where
+  "t_merge xs [] = 1"
+| "t_merge [] xs = 1"  
+| "t_merge (x#xs) (y#ys) = 4" (*(if, # cons, @ cons, # cons)*)
+lemma l_merge_estimate: 
+  "t_merge xs ys \<le> 4"
+  apply (induction xs ys rule: t_merge.induct)  
+  apply auto
+  done
+fun t_get_min :: "'a::linorder Heap \<Rightarrow> nat" where
+  "t_get_min (t#ts) = 1"
+fun t_merge_node ::"'a::linorder Node \<Rightarrow> 'a Node \<Rightarrow> nat" where
+  "t_merge_node a b = 1"
+fun t_lookup :: "nat \<Rightarrow> 'a Node list \<Rightarrow> nat" where
+  "t_lookup x [] = 1"|
+  "t_lookup x ((Node r a c)#xs) = 1 + (if r = x then 0 else t_lookup x xs)"
+fun t_consolidate :: "'a::linorder Heap \<Rightarrow> 'a Node list \<Rightarrow> nat" where
+  "t_consolidate [] l = 1"|
+  "t_consolidate (x#xs) l = t_lookup (rank x) l + (
+    case lookup (rank x) l of None \<Rightarrow> 1 + t_consolidate xs (x#l)
+    |Some t \<Rightarrow> 1 + t_consolidate xs ((merge_node x t)#(filter (\<lambda>q. rank q \<noteq> rank x) l))
+  )"
+fun t_update_min :: "'a::linorder Heap \<Rightarrow>'a::linorder Heap \<Rightarrow> 'a Node \<Rightarrow> nat" where
+  "t_update_min h [] a = 1"|
+  "t_update_min h (x#xs) a = 1 + (if root x < root a then t_update_min (a#h) xs x else t_update_min (x#h) xs a)"
+fun t_delete_min :: "'a::linorder Heap \<Rightarrow> nat" where
+  "t_delete_min [] = 1"|
+  "t_delete_min (x#xs) = 1 + t_consolidate ((children x)@xs) [] + t_update_min [] (tl (consolidate ((children x)@xs) [])) (hd (consolidate ((children x)@xs) []))"
+lemma sumrule:
+  fixes n::nat
+  shows"(\<Sum>i=0..n. i) = n*(n+1) div 2"
+  proof (induct n)
+  case 0
+    have "(\<Sum>i=0..0. i) = (0::nat)" by simp
+    also have "... = 0*(0+1) div 2" by simp
+    finally show ?case .
+  next
+  case (Suc n)
+    have "(\<Sum>i=0..Suc n. i) = (\<Sum>i=0..n. i) + (n+1)" by simp
+    also have "... = n*(n+1) div 2 + (n+1)" by (simp add : Suc.hyps)
+    also have "... = (n*(n+1) + 2 *(n+1)) div 2" by simp
+    also have "... = (Suc n*(Suc n+1)) div 2" by simp
+    finally show ?case .
+qed
+lemma t_get_min_estimate: "ts\<noteq>[] \<Longrightarrow> t_get_min ts = 1"  
+  by (induction ts rule: t_get_min.induct) auto
+lemma t_merge_node_estimate[simp]: "t_merge_node x y = 1" by auto
+lemma t_lookup_estimate[simp]: "t_lookup x l \<le> 1 + size l" apply (induction x l rule: t_lookup.induct) apply auto done
+lemma t_consolidate_estimate[simp]: "t_consolidate x l \<le> 1 + size l + 1 + (size x)^3"
+proof (induction x l rule: t_consolidate.induct)
+  case (1 l)
+  then show ?case by auto
+next
+  case (2 x xs l)
+  thm "2.IH"
+  then show ?case
+  proof (cases "lookup (rank x) l")
+    case None 
+    then have "t_consolidate (x#xs) l \<le> 1 + size l + 1 + t_consolidate xs (x#l)" using t_lookup_estimate by auto
+    then show ?thesis sorry
+next
+    case (Some a)
+    then show ?thesis sorry     
+qed                    
+    (*"t_consolidate (x#xs) l = t_lookup (rank x) l + (
+    case lookup (rank x) l of None \<Rightarrow> 1 + t_consolidate xs (x#l)
+    |Some t \<Rightarrow> 1 + t_consolidate xs ((merge_node x t)#(filter (\<lambda>q. rank q \<noteq> rank x) l))
+  )"*)
+qed
+lemma t_update_min_estimate:"t_update_min h x a \<le> 1 + size x" 
+  by(induction h x a rule: t_update_min.induct) auto
+lemma t_delete_min_estimate:
+  fixes ts
+  defines "n \<equiv> size (mset_heap ts)"
+  assumes "invar ts"
+  assumes "ts\<noteq>[]"
+  shows "t_delete_min (x#xs) = 4 + (size ((children x)@xs))^3 + size ((children x)@xs)" 
+  using assms unfolding invar_def sorry
+
+(*TODO: amortized*)
+    
+subsection \<open>Instantiating the Priority Queue Locale\<close>
+interpretation fibheap:
+  Priority_Queue "[]" "op = []" insert get_min delete_min invar mset_heap
+proof (unfold_locales, goal_cases)
+  case 1
+  then show ?case by simp
+next
+  case (2 q)
+  then show ?case by auto
+next
+  case (3 q x)
+  then show ?case using insert_mset by auto
+next
+  case (4 q)
+  then show ?case using delete_min_mset sorry    
+next
+  case (5 q)
+  then show ?case using get_min[of q] by auto
+next 
+  case 6 
+  then show ?case by (auto simp add: invar_def)
+next
+  case (7 q x)
+  then show ?case by (auto simp: insert_invar)
+next
+  case (8 q)
+  then show ?case by auto
+qed
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Ouyang_Lena_ga96vup@mytum.de_627/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,6 @@
+Using temporary directory '/tmp/tmp.LQO20FAA1T'
+Files in /tmp/eval-627-tKoPGK: hw13.thy
+Submission did not check in Isabelle!
+Test case check_build:	Failed
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Rdle_Karl_Jonas_jonas.raedle@tum.de_621/hw13_sub.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,71 @@
+(*<*)
+theory hw13_sub
+  imports "../../../Public/Thys/Skew_Heap"
+begin
+(*>*)
+  
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+  "merge h None = h" |
+  "merge None h = h" |
+  "merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+      (if x < y then Some (Hp x ((Hp y ly)# lx)) 
+                else Some (Hp y ((Hp x lx)# ly)))"  
+  
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None" |
+  "merge_pairs [h] = Some h" |
+  "merge_pairs (h1 # h2 # hs) = merge (merge (Some h1) (Some h2)) (merge_pairs hs)"  
+  
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None" |
+  "del_min (Some (Hp x hs)) = merge_pairs hs"
+  
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall> h \<in> set hs. (\<forall> y \<in> set_hp h. x < y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+  "mset_hp (Hp x hs) =  {#x#} + Union_mset(mset(map mset_hp hs))"  
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}" |
+  "mset_heap (Some hp) = mset_hp hp"
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+  by (cases h) (auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+apply (cases h) by fastforce
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by (induction h1 h2 rule: merge.induct) (auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+by (induction hs rule: merge_pairs.induct) (auto simp: mset_merge)    
+    
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  by(cases h) (auto simp: mset_merge_pairs)
+
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Rdle_Karl_Jonas_jonas.raedle@tum.de_621/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Rokopf_Simon_simon.rosskopf@tum.de_630/Pairing_Heap.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,75 @@
+
+theory Pairing_Heap
+imports "~~/src/HOL/Library/Multiset"
+begin
+
+subsection \<open>Definitions\<close>
+
+text
+\<open>This implementation follows Okasaki \cite{Okasaki}.
+It satisfies the invariant that \<open>Empty\<close> only occurs
+at the root of a pairing heap. The functional correctness proof does not
+require the invariant but the amortized analysis (elsewhere) makes use of it.\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+fun set_heap :: "'a heap \<Rightarrow> 'a set" where
+  "set_heap None = {}"
+| "set_heap (Some hp) = set_hp hp"
+  
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+"get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some (Hp y (Hp x lx # ly)))"
+
+hide_const (open) insert
+
+fun merge_pairs :: "('a :: linorder) heap list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = h" 
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs (map Some hs)"
+
+
+subsection \<open>Correctness Proofs\<close>
+
+subsubsection \<open>Invariants\<close>
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+
+subsubsection \<open>Functional Correctness\<close>
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap None = {#}" |
+"mset_heap (Some (Hp x hs)) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+lemma get_min_in: "get_min (Some h) \<in> set_hp(h)"
+by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+by(cases h)(auto)
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_heap(mset hs))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min (Some h)#}"
+apply (cases h) apply (auto simp: mset_merge_pairs) (* lol *)
+  by (smt image_mset.compositionality image_mset_cong mset_heap.elims mset_hp.simps o_def option.sel option.simps(3))
+
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Rokopf_Simon_simon.rosskopf@tum.de_630/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Saporta_Antoine_Jacques_antoine.saporta@tum.de_620/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,84 @@
+(*<*)
+theory hw13
+imports "~~/src/HOL/Library/Multiset"
+begin
+(*>*)
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+"get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some (Hp y (Hp x lx # ly)))"
+
+hide_const (open) insert
+
+fun insert :: "'a \<Rightarrow> ('a :: linorder) heap \<Rightarrow> 'a heap" where
+"insert x h = merge (Some (Hp x [])) h"
+
+fun merge_pairs :: "('a :: linorder) heap list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = h" 
+| "merge_pairs (h1 # h2 # hs) = merge (merge h1 h2) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs (map (\<lambda>h. Some h) hs)"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow> 'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))" 
+
+fun mset_heap :: "'a heap \<Rightarrow> 'a multiset" where
+"mset_heap None = {#}" |
+"mset_heap (Some hp) = mset_hp hp"
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+  by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by(cases h)(auto)
+  
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_insert: "mset_heap (insert a h) = {#a#} + mset_heap h"
+by(cases h) (auto simp add: mset_merge insert_def add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_heap(mset hs))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+
+lemma aux: "image_mset mset_heap (image_mset Some (mset hs)) = image_mset mset_hp (mset hs)"
+using multiset.map_comp comp_def multiset.map_cong mset_heap.simps(2)
+by metis
+
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+by(cases h) (auto simp: mset_merge_pairs aux)
+
+
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Saporta_Antoine_Jacques_antoine.saporta@tum.de_620/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Schffeler_Maximilian_maximilian.schaeffeler@tum.de_643/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,58 @@
+theory hw13
+imports "~~/src/HOL/Library/Multiset"
+begin
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+  
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x l)) = x"
+| "get_min None = undefined"
+
+fun merge :: "('a :: linorder) hp  \<Rightarrow> 'a hp  \<Rightarrow> 'a hp" where
+"merge (Hp x lx) (Hp y ly) = 
+    (if x < y then (Hp x (Hp y ly # lx)) else (Hp y (Hp x lx # ly)))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h"
+| "merge_pairs (h1 # h2 # hs) = 
+    (case (merge_pairs hs) of None \<Rightarrow> (Some (merge h1 h2))
+        | Some h \<Rightarrow> Some (merge (merge h1 h2) h))"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs hs"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> (php h))"
+
+fun mset_hp :: "'a hp \<Rightarrow> 'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap None = {#}"
+|"mset_heap (Some h) = mset_hp h"
+
+theorem get_min_in: "get_min (Some h) \<in> set_hp(h)"
+  apply (induction h)
+  by auto
+ 
+lemma get_min_min: "php h \<Longrightarrow> x\<in>set_hp(h) \<Longrightarrow> get_min (Some h) \<le> x"
+  apply (induction h) by (auto)
+ 
+lemma mset_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+  apply (induction h1 h2 rule: merge.induct) by auto
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+  apply (induction hs rule: merge_pairs.induct)
+  apply (auto split: option.split)
+  apply (smt add_cancel_right_right comm_monoid_mset.distrib image_mset_cong mset_merge set_mset_mset sum_mset.comm_monoid_mset_axioms sum_mset_def)
+  by (simp add: mset_merge)
+    
+lemma mset_del_min: "mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  apply (induction h rule: mset_hp.induct)
+  by (simp add: mset_merge_pairs)
+
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Schffeler_Maximilian_maximilian.schaeffeler@tum.de_643/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Somogyi_Daniel_daniel.somogyi@tum.de_625/FiboHeap.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,430 @@
+section \<open>Fibonacci Heap\<close>
+  
+text\<open>for the whole file: theorems are important things to show, lemmas are
+  auxiliary used by larger theorems \<close>
+  
+theory FiboHeap
+
+imports
+  Complex_Main
+  "Demos/BinHeap"
+  "~~/src/HOL/Library/Rewrite"
+begin
+text \<open>A Fibonacci Heap is technically like a Binomial
+  Heap, just a bit more relaxed. In detail:
+  - We still have a collection of Binomial Trees
+  - The Heap property is fulfilled in every tree
+  - We can have more than one tree of the same size
+  - The Binomial Trees do not have to be completely filled
+
+  Point 1 and 2 are pretty clear, we won't look at them in 
+  detail right now.
+
+  Point 3 is important in the merge function. In the result
+  we can have several trees of the same size, and they will
+  not be ordered in descending (or ascending) order.
+
+  Point 4 is only important for the Decrese Key function (which
+  will be ignored here). In detail, the Decrese Key is
+  realized by just cutting the decresed node, and its children,
+  from the tree, and inserting it into the list of trees. In some
+  cases the parent itself will also be cutted. Since we do not
+  implement this function we can ignore the problem. From this
+  also follows, that we only work with fully filled Binomial
+  Heaps, introduced in the lesson and implemented in BinHeap.thy
+
+  Everything further important will be introduced (and maybe 
+  prooven) at the corresponding section.\<close>
+  
+subsection Datatype
+text \<open>The heap itself is a collection of (Binomial) trees. 
+  usually the tree with the minimal root is saved with a 
+  pointer. We will save it as a second parameter. Some functions
+  (like get min or delete min) will get simpler, others (deconsolidate)
+  will get harder) \<close>
+datatype 'a fibHeap =  Empty (*sometimes needed, mostly for del_min*)
+  | Heap (min:"'a tree") (trees:"'a tree list")
+definition init:: "'a fibHeap" where "init = Empty"    (*for \<Phi> function *)
+
+
+subsection Multiset
+text\<open>Before looking on the invariants we look at creating sets\<close>
+
+fun mset_heap:: "'a::linorder fibHeap \<Rightarrow> 'a multiset" where
+  "mset_heap (Heap n t) = mset_tree n  + (\<Sum>tree\<in>#mset t. mset_tree tree)"
+  |"mset_heap Empty = {#}"
+
+text\<open>We have following invariants:
+  - EVERY tree fulfills the heap property
+  - the min-tree has the smallest root
+  - if the min-tree is Empty the whole tree must be Empty (which is given by
+      the fact, that an 'a tree structure can't be empty...\<close>
+  
+fun invar_heaptrees_list:: "'a::linorder tree list \<Rightarrow> bool" where
+  "invar_heaptrees_list [] = True"
+  |"invar_heaptrees_list (x#xs) = (otree_invar x \<and> invar_heaptrees_list xs)"
+  
+fun invar_heaptrees:: "'a::linorder fibHeap \<Rightarrow> bool" where
+  "invar_heaptrees (Heap n t) = ((invar_heaptrees_list t) \<and> (otree_invar n))"
+|"invar_heaptrees Empty = True"
+  
+fun invar_min_smallest:: "'a::linorder fibHeap \<Rightarrow> bool" where
+  "invar_min_smallest Empty = True"
+  |"invar_min_smallest (Heap (Node rk a chld) t) \<longleftrightarrow>
+    (\<forall>x\<in>#mset_heap (Heap (Node rk a chld) t). a \<le> x)"
+
+definition invar:: "'a::linorder fibHeap \<Rightarrow> bool" where
+  "invar h \<longleftrightarrow> invar_heaptrees h \<and> invar_min_smallest h"
+        
+(* often needed: if x is in a list of correct heaps x is correct *)  
+lemma invar_list[simp]:
+ assumes "invar_heaptrees_list xs"
+ assumes "x\<in># mset xs"
+ shows "otree_invar x"
+   using assms
+  apply(induction xs arbitrary:x)
+    apply(auto)
+   done     
+     
+lemma invar_list2:"(\<forall>x\<in>#mset xs. otree_invar x) = invar_heaptrees_list xs"
+  by(induction xs) auto
+    
+lemma invar_list_combine[simp]:
+  assumes "invar_heaptrees_list xs"
+  assumes "invar_heaptrees_list ys"
+  shows "invar_heaptrees_list (xs@ys)"
+  using assms by(induction xs arbitrary:ys)auto
+    
+lemma invar_list_children:
+  "otree_invar (Node rk a chlds) \<Longrightarrow> invar_heaptrees_list chlds"
+  by(induction chlds arbitrary:rk a) auto
+    
+     
+subsection Functions
+text \<open>most important for a heap; get the minimal element\<close>
+fun getMin:: "'a fibHeap \<Rightarrow> 'a" where 
+  "getMin (Heap (Node _ a _) _) = a"
+|"getMin Empty = undefined"
+   
+theorem getMin_finds_min:
+  assumes "h \<noteq> Empty"
+  assumes "invar h"
+  assumes "x\<in>#mset_heap h"
+  shows "getMin h \<le> x"
+proof(cases h)
+  case Empty
+  then show ?thesis using assms(1) by auto
+next
+  case (Heap nde ts)
+    (* idea: show that get-min returns element from min-tree, show that this must be
+    smallest element (invariant) and combine *)
+  obtain rk a chld  where node: "nde = Node rk a chld" 
+    using tree.exhaust_sel by blast
+
+  then have min: "getMin h = a" using Heap by auto
+      
+  have "invar_min_smallest h" using assms(2) unfolding invar_def by auto
+  then have "\<forall>x\<in>#mset_heap h. a \<le> x" using node Heap invar_min_smallest.simps by blast
+      
+  then show ?thesis using assms(3) min by blast
+qed  
+    
+text\<open>before doing anything else; we merge two Heaps.
+  Merging is simple and fast: the tree lists become one and the
+  min-pointer shows to the smaller of the two trees.
+
+  Since we do not work with a pointer we check which heap had
+  the smaller min-element. This one gets the min-position, the
+  other tree is added to the tree list\<close>
+fun merge:: "'a::linorder fibHeap \<Rightarrow> 'a fibHeap \<Rightarrow> 'a fibHeap" where
+  "merge (Heap (Node r1 a1 t1) tl1) (Heap (Node r2 a2 t2) tl2)
+    = (if a1 < a2 then (Heap (Node r1 a1 t1) ((Node r2 a2 t2) # tl1 @ tl2))
+    else (Heap (Node r2 a2 t2) ((Node r1 a1 t1) # tl1 @ tl2))
+  )"
+  |"merge Empty h = h"
+  |"merge h Empty = h"
+    
+lemma merge_invar1_aux:
+  assumes "invar_heaptrees_list tl1"
+  assumes "invar_heaptrees_list tl2"
+  shows "invar_heaptrees_list (tl1@tl2)"
+    using assms
+ by(induction tl1 arbitrary:tl2) auto
+    
+lemma merge_invar1:
+  assumes "invar_heaptrees h1"
+  assumes "invar_heaptrees h2"
+  shows "invar_heaptrees (merge h1 h2)"
+  using assms
+  by(induction h1 h2 rule:merge.induct) (auto simp:merge_invar1_aux)
+    
+lemma merge_invar2:
+  assumes "invar_min_smallest h1"
+  assumes "invar_min_smallest h2"
+  shows "invar_min_smallest (merge h1 h2)"
+  using assms
+  apply(induction h1 h2 rule:merge.induct)
+    apply(auto)
+    apply force+
+  done
+      
+theorem merge_invar:
+  assumes "invar h1"
+  assumes "invar h2"
+  shows "invar (merge h1 h2)"
+    using assms
+    unfolding invar_def
+      by(auto simp:merge_invar1 merge_invar2)
+    
+theorem merge_combines_msets[simp]:
+  shows "mset_heap h1 + mset_heap h2 = mset_heap (merge h1 h2)"
+  by(induction h1 h2 rule:merge.induct) auto
+  
+text \<open>Inputting an element is simply merging a singleton with the list\<close>
+definition insert:: "'a::linorder fibHeap \<Rightarrow> 'a \<Rightarrow> 'a fibHeap" where
+  "insert h i = merge h (Heap (Node 1 i []) [])"
+  
+theorem insert_invar:
+  assumes "invar h"
+  shows "invar (insert h x)"
+proof -
+  (*you have to show isabelle that the created singleton fullfills the invar ... *)
+  have singleton_invar: "invar (Heap (Node 1 x []) [])"
+    unfolding invar_def by auto
+  
+      
+  thus ?thesis using singleton_invar assms 
+  unfolding insert_def
+      by(auto simp:merge_invar)
+qed
+  
+
+text\<open>After deleting the minimum we have to consolidate the list. This
+  means we combine the trees of same size. The movement reminds of the
+  binary addition of binomial trees.
+
+  This works as follows: We have an array (realized as list), with exactly
+  one space for every size of a tree. Then we iterate over the trees, one
+  by one. If the corresponding field in the array is free the current
+  tree gets inserted. If not, we merge the trees and re-insert them into
+  the list of the heap (so later it gets inserted as larger tree)
+
+  For the function: The first list is the list of the Heap, the second
+  list represents the array (which should be empty at the beginning).\<close>
+
+  
+fun option_to_trees:: "(('a tree option) list) \<Rightarrow> 'a tree list" where
+"option_to_trees [] = []"
+|"option_to_trees (x#xs) = (case x of None \<Rightarrow> option_to_trees xs
+    | Some t \<Rightarrow> t#option_to_trees xs)"
+  
+function insert_carry:: "'a::linorder tree \<Rightarrow> ('a tree option) list \<Rightarrow> ('a tree option) list" where
+"insert_carry t lst = (
+  if rank t < length lst then
+    case (lst! (rank t)) of
+      None \<Rightarrow> lst[rank t:= Some t]
+      |Some t2 \<Rightarrow> insert_carry (link t t2) (lst[rank t:=None])
+  else undefined)" 
+  by pat_completeness auto
+termination
+  apply (relation "measure (\<lambda>(t,lst). length (filter (op\<noteq>None) lst))")
+  apply simp
+  apply clarsimp  
+  subgoal for t lst x2  
+    apply (rewrite in "_ < \<hole>" id_take_nth_drop[of _ lst], assumption)
+    apply (rewrite in "\<hole> < _" id_take_nth_drop[of _ lst], assumption)
+    apply (simp add: upd_conv_take_nth_drop ord_class.min_def)
+    done
+  done
+    
+fun consolidate:: "'a::linorder tree list \<Rightarrow> ('a tree option) list \<Rightarrow> 'a tree list" where
+  "consolidate [] list = option_to_trees list"
+ |"consolidate (t#ts) list = consolidate ts (insert_carry t list)"
+  
+text \<open>we need to know how large the array for consolidate has to be. Worst case is that
+  every tree in the list has the same size (rank). An Array of (highest rank +  log_2 (n))
+  must be enough.\<close>
+fun num_nones:: "'a::linorder tree list \<Rightarrow> nat" where
+  "num_nones [] = 1"                              
+|"num_nones xs = Max (\<Union>t\<in>set xs. {rank t}) + nat (floor(log 2 (length xs)))"
+
+text \<open>The following functions could've been combined, but this would
+  make everything much more complicated\<close>
+  
+fun find_smallest_tree:: "'a::linorder tree list \<Rightarrow> 'a tree \<times> 'a tree list" where
+  "find_smallest_tree [t] = (t,[])"
+ |"find_smallest_tree (t#ts) = (let (t',ts') = find_smallest_tree ts
+                     in if root t \<le> root t' then (t,t'#ts') else (t',t#ts'))"
+ |"find_smallest_tree [] = undefined"
+   
+lemma mset_find_smallest_tree:
+  assumes "find_smallest_tree va = (x,xs)"
+  assumes "va \<noteq> []"
+  shows "mset va = mset xs + {# x #}"
+  using assms 
+  by(induction va arbitrary:x xs rule:find_smallest_tree.induct)(auto split:if_splits prod.splits)
+      
+fun find_min:: "'a::linorder tree list \<Rightarrow> 'a fibHeap" where
+  "find_min [] = Empty"
+|"find_min x = (let (t,ts) = find_smallest_tree x in Heap t ts)"
+  
+fun delmin:: "'a::linorder fibHeap \<Rightarrow> 'a fibHeap" where
+  "delmin (Heap (Node rk a chlds) tlst) = 
+    find_min 
+      (consolidate
+        (chlds@tlst) (* combine children of min with rest of list *)
+        (replicate (num_nones (chlds@tlst)) None) (*create 'array' for consolidate *)
+      )"
+|"delmin Empty = undefined"
+  
+fun correctOpts:: "(('a::linorder) tree option) list \<Rightarrow> bool" where
+  "correctOpts [] = True"
+ |"correctOpts (x#xs) = (case x of None \<Rightarrow> correctOpts xs
+      |Some t \<Rightarrow> (otree_invar t \<and> correctOpts xs))"
+  
+lemma delmin_invar_aux3:
+  assumes "find_smallest_tree lst = (x,xs)"
+  assumes "lst \<noteq> []"
+  shows "x\<in># mset lst"
+  using assms
+by(induction lst arbitrary: x xs rule:find_smallest_tree.induct)(auto split:if_splits prod.splits)
+      
+lemma delmin_invar_aux2:
+  assumes "invar_heaptrees_list tlst"
+  shows "invar_heaptrees (find_min tlst)"
+  using assms
+proof (induction tlst)
+  case Nil
+  then show ?case using assms by auto
+next
+  case (Cons t ts)
+  obtain x lst where A: "find_smallest_tree (t # ts) = (x,lst)"
+    using Cons assms 
+    by (meson surj_pair) (* why the f*** did i need sledgehammer for this o.O *)
+        
+  have B: "t#ts \<noteq> []" 
+    by simp
+  have "x \<in># mset (t#ts)" using A B
+      using delmin_invar_aux3 by fastforce
+  then have otree_x: "otree_invar x" using Cons
+      by(auto)       
+        
+    have a: "\<forall>y \<in># mset (t#ts). otree_invar y" using Cons
+      by(auto)
+    have b: "mset lst = mset (t#ts) - {#x#}" using Cons a assms
+      using A mset_find_smallest_tree by fastforce
+    have c: "\<forall>y \<in># mset(lst). otree_invar y" using a b Cons assms
+        using in_diffD by force
+        
+    have invar_lst: "invar_heaptrees_list lst" 
+          using c invar_list2 by auto
+        
+    show ?case using Cons A
+       by(auto split:prod.split simp:otree_x invar_lst)
+   qed
+     
+(* As it took too long I had to give up, and I did not even try to proove correctness *)
+lemma delmin_invar_aux4:
+  assumes "invar_heaptrees_list lst"
+    assumes "\<forall>t\<in>set lst. rank t < length nones"
+    shows "invar_heaptrees_list(consolidate lst nones)"
+      using assms
+  sorry
+    
+theorem delmin_invar:
+  assumes "invar_heaptrees h"
+  assumes "h \<noteq> Empty"
+  shows "invar_heaptrees (delmin h)"
+  using assms
+    proof(induction h rule:delmin.induct) (*dont ask why i took induction. But when i realized it was to much to change...*)
+      case (1 rk a chlds tlst)
+      have a: "invar_heaptrees_list tlst" using assms 1 by auto
+      have "otree_invar (Node rk a chlds)" using 1 by auto
+      then have b: "invar_heaptrees_list chlds" 
+        using invar_list_children by blast
+          
+      have A: "invar_heaptrees_list (chlds@tlst)" using a b by auto
+           
+      have B: "\<forall>t \<in> set (chlds@tlst). rank t < length (replicate (num_nones (chlds @ tlst)) None)" 
+        sorry
+          
+      show ?case using assms A 1 B
+        apply(auto)
+        apply(auto simp:delmin_invar_aux2 delmin_invar_aux4)
+     done
+    next
+      case 2
+      then show ?case using assms by auto
+    qed
+      
+theorem delmin_corr:  
+  assumes "invar_heaptrees h"
+  assumes "h \<noteq> Empty"
+  shows "mset_heap (delmin h) = mset_heap h - {#getMin h#}"
+  using assms
+    proof (cases h)
+      case Empty
+      then show ?thesis using assms by auto
+    next
+      case (Heap x21 x22)
+      obtain  rk a chlds where asNode: "Node rk a chlds = x21"
+        by (metis otree_invar.cases)
+      have "a = getMin h" using Heap asNode by auto
+          
+       show ?thesis using Heap
+        apply(auto) (*mainly show that helper functions do not change mset*)
+          sorry
+    qed
+  
+subsection \<open>Complexity\<close>
+  
+subsection \<open>Timing functions\<close>
+text\<open>The Fibonacci Heap has amortized complexity, so we will need timing functions
+  for the operations and we will need an amortizing function. After defining them
+  we will show the time complexity, but not for the delMin function (as it is definitely
+  too complicated by now...)\<close>
+  
+text\<open>Normally the potential function is t(S)+2m(S) where t(S) is the number of trees
+  and m(S) is the number of marked nodes. Since we never mark nodes we simply can
+  use the number of trees:\<close>  
+fun \<Phi>:: "'a fibHeap \<Rightarrow> int" where
+  "\<Phi> Empty = 0"
+ |"\<Phi> (Heap _ ts) = 1 + length ts"
+
+(*showing \<Phi> lemmas is simple: *)   
+theorem \<Phi>_non_neg: "\<Phi> hp \<ge> 0"
+by(cases hp) auto
+    
+theorem \<Phi>_init: "\<Phi> init = 0" unfolding init_def by simp
+  
+    
+text \<open>In the timing functions sometimes we have to 'cheat. Concretely:
+  - We assume double linked lists with constant linking time\<close>
+  
+fun t_getMin :: "'a fibHeap \<Rightarrow> nat" where 
+  "t_getMin (Heap n lst) = 1"
+|"t_getMin Empty = 1" (*simpler than saying undef*)
+  
+text \<open>getMin constant (does not change the heap so amortizing not necessarry)\<close>  
+theorem "t_getMin h \<le> 1" by (cases h) auto
+      
+fun t_merge:: "'a::linorder fibHeap \<Rightarrow> 'a fibHeap \<Rightarrow> int" where 
+    "t_merge (Heap (Node r1 a1 t1) tl1) (Heap (Node r2 a2 t2) tl2)
+    = (if a1 < a2 then 2 else 2)+1" (* both cases just have one list-insert + one list-append *)
+  |"t_merge Empty h = 1"
+  |"t_merge h Empty = 1"
+
+text\<open>merge amortized constant\<close>
+theorem "t_merge a b + \<Phi>(merge a b) - (\<Phi> a + \<Phi> b) \<le> 3"
+  by(induction a b rule:t_merge.induct) auto
+    
+definition t_insert:: "'a::linorder fibHeap \<Rightarrow> 'a \<Rightarrow> int" where 
+"t_insert h i =  t_merge h (Heap (Node 1 i []) [])"
+
+theorem "t_insert h a + \<Phi>(insert h a) - \<Phi> h \<le> 4"
+  unfolding t_insert_def insert_def
+  by(induction h "(Heap (Node 1 a [])[])" rule:t_merge.induct)auto
+
+    
+end
+  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Somogyi_Daniel_daniel.somogyi@tum.de_625/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,142 @@
+(* Author: Tobias Nipkow *)
+
+theory hw13
+imports "~~/src/HOL/Library/Multiset"
+begin
+
+(*
+to clarify:
+  I just copied the Pairing_Heap theory and updated the datatype.
+  Then I 'corrected' the functions, lemmas and theories s.t. they
+  fit the new definitions.
+  The two aux-lemmas were my helpers for the delete-lemmas...
+*)  
+  
+subsection \<open>Definitions\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+  
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) =  x"
+| "get_min _ = undefined"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then (Some (Hp x (Hp y ly # lx))) 
+      else (Some (Hp y (Hp x lx # ly))))"
+
+hide_const (open) insert
+
+fun insert :: "'a \<Rightarrow> ('a :: linorder) heap \<Rightarrow> 'a heap" where
+"insert x h = merge (Some (Hp x [])) h"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h" 
+| "merge_pairs (h1 # h2 # hs) = 
+    merge (merge (Some h1) (Some h2)) (merge_pairs hs)"
+
+fun del_min :: "('a :: linorder) heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs hs"
+
+
+subsection \<open>Correctness Proofs\<close>
+
+subsubsection \<open>Invariants\<close>
+
+fun pheap :: "('a :: linorder) heap \<Rightarrow> bool" where
+"pheap None = True" |
+"pheap (Some (Hp x hs)) 
+    = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> pheap (Some h))"
+
+lemma pheap_merge: "pheap h1 \<Longrightarrow> pheap h2 \<Longrightarrow> pheap (merge h1 h2)"
+by (induction h1 h2 rule: merge.induct) fastforce+
+
+lemma pheap_insert: "pheap h \<Longrightarrow> pheap (insert x h)"
+by (auto simp: pheap_merge)
+
+lemma pheap_merge_pairs: "\<forall>h \<in> set hs. pheap (Some h) \<Longrightarrow> pheap (merge_pairs hs)"
+by(induction hs rule: merge_pairs.induct) (auto simp: pheap_merge)
+
+lemma aux: "pheap (Some (Hp x hs)) \<Longrightarrow> \<forall>h \<in> set hs. pheap (Some h)"   
+  by(cases "Some (Hp x hs)") auto
+
+lemma pheap_del_min: 
+  assumes "pheap h"
+shows "pheap (del_min h)"
+proof (cases h)
+  case None
+  then show ?thesis by auto
+next
+  case (Some a)
+  then obtain hp hs where intro_hs:"a = (Hp hp hs)"
+    by (meson option.inject option.simps(3) pheap.elims(2) pheap.elims(3))
+      (* oh i love sledgehammer *)
+  
+  have "\<forall>h\<in>set hs. pheap (Some h)" 
+      using Some assms intro_hs by auto
+      
+  thus ?thesis using Some intro_hs pheap_merge_pairs[of hs]
+      by auto
+qed
+  
+subsubsection \<open>Functional Correctness\<close>
+  
+(* We need to make the hp to heaps. used by mapping for the hp list *)  
+fun hp_to_Heap:: "'a hp \<Rightarrow> 'a hp option" where
+  "hp_to_Heap h = Some h"
+         
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap None = {#}" |
+"mset_heap (Some (Hp x hs)) =
+  {#x#} + Union_mset(mset(map mset_heap (map hp_to_Heap hs)))"
+
+lemma get_min_in: "get_min (Some h) \<in> set_hp(h)"
+by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk>pheap (Some h); x \<in> set_hp(h)\<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by(cases h)(auto)
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_insert: "mset_heap (insert a h) = {#a#} + mset_heap h"
+by(cases h) (auto simp add: mset_merge insert_def add_ac)
+  
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) 
+  = Union_mset(image_mset mset_heap (mset (map hp_to_Heap hs)))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+
+lemma aux2 : "mset_heap  (Some (Hp x hs)) 
+  = mset_heap (merge_pairs hs) + {#x#}"
+  apply(induction hs rule:merge_pairs.induct)
+    apply(auto simp:mset_merge)
+    done
+
+lemma mset_del_min: "mset_heap (del_min h) 
+  = mset_heap h - {#get_min h#}"
+proof (cases h)
+  case None
+  then show ?thesis by auto
+next
+  case (Some a)
+  obtain x hs where hs_def: "a = Hp x hs"
+    by (meson get_min_in hp.set_cases)
+  then show ?thesis using aux2[of x hs] hs_def Some by auto
+      
+qed
+
+(* only realized at the end that i'm missing this fun: *)  
+  
+fun mset_hp:: "'a hp \<Rightarrow> 'a multiset" where
+  "mset_hp (Hp x hs) = {#x#}
+      + Union_mset(mset(map mset_hp hs))"
+  
+(* maybe doing mset_heap first would've simplify the proofs
+whatever... *)  
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Somogyi_Daniel_daniel.somogyi@tum.de_625/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,5 @@
+Using temporary directory '/tmp/tmp.Ax0inQokM6'
+Files in /tmp/eval-625-2zyZiJ: FiboHeap.thy  hw13.thy
+More than one submission file
+Runner terminated with exit code 1.
+Test execution terminated with exit code 1.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Stevens_Lukas_lukas.stevens@tum.de_617/Ex13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,72 @@
+(*<*)
+theory Ex13
+  imports "../Thys/Skew_Heap" 
+begin
+(*>*)
+    
+text \<open>
+  \Homework{Pairing Heap}{28.~07.~2017}
+
+The datatype of pairing heaps defined in the theory \verb!Thys/Pairing_Heap!
+comes with the unstated invariant that \<open>Empty\<close> occurs only at the root.
+We can avoid this invariant by a slightly different representation:
+\<close>
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+text \<open>Carry out the development with this new representation. 
+Restrict  yourself to the \<open>get_min\<close> and \<open>delete_min\<close> operations.
+That is, define the following functions (and any auxiliary function required)
+\<close>
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp a _)) = a"
+  
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+  "merge (Hp x lx) (Hp y ly) = 
+    (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h" 
+| "merge_pairs (h1 # h2 # hs) = 
+  (case (merge_pairs hs) of
+    None \<Rightarrow> Some (merge h1 h2) |
+    Some hp \<Rightarrow> Some (merge hp (merge h1 h2)))"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = None" |
+  "del_min (Some (Hp a list)) = merge_pairs list"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+  "php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where 
+  "mset_hp (Hp a list) = {#a#} + Union_mset (mset (map mset_hp list))"
+  
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = {#}" |
+  "mset_heap (Some hp) = mset_hp hp"
+
+(* HINT: Start with a copy of the original lemmas, and modify as needed *)  
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)"
+  by(cases h) auto
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+  by(cases h) auto
+ 
+lemma mset_merge: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+  by(induction h1 h2 rule: merge.induct) auto
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset (image_mset mset_hp (mset hs))"
+  by(induction hs rule: merge_pairs.induct) (auto simp add: mset_merge split: option.split)
+    
+lemma mset_del_min: "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+  by(cases h) (auto simp add: mset_merge_pairs)
+
+(*<*)  
+end
+(*>*)
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Stevens_Lukas_lukas.stevens@tum.de_617/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Stwe_Daniel_daniel.stuewe@tum.de_649/HW13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,51 @@
+theory HW13
+  imports "Thys/Pairing_Heap"
+begin
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+fun get_min  :: "('a :: linorder) heap \<Rightarrow> 'a" where
+  "get_min (Some (Hp x _)) = x"
+  
+fun merge :: "('a :: linorder) hp \<Rightarrow> 'a hp \<Rightarrow> 'a hp" where
+"merge (Hp x lx) (Hp y ly) = 
+    (if x < y then Hp x (Hp y ly # lx) else Hp y (Hp x lx # ly))"
+  
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+  "merge_pairs [] = None"
+| "merge_pairs [h] = Some h" 
+| "merge_pairs (h1 # h2 # hs) = Some (case merge_pairs hs of
+                     Some h \<Rightarrow>  merge (merge h1 h2) h | None \<Rightarrow> merge h1 h2)"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+  "del_min None = None"
+| "del_min (Some (Hp x hs)) = merge_pairs hs"
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + \<Union># mset (map mset_hp hs)"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+  "mset_heap None = 0"
+| "mset_heap (Some h) = mset_hp h" 
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+by (induction h) auto
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+by (induction h) auto
+
+lemma mset_merge[simp]: "mset_hp (merge h1 h2) = mset_hp h1 + mset_hp h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_merge_pairs[simp]: "mset_heap (merge_pairs hs) = \<Union># mset (map mset_hp hs)"
+by(induction hs rule: merge_pairs.induct)(auto split: option.splits)
+  
+lemma mset_del_min: 
+  "mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+by(induction h) auto
+  
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Stwe_Daniel_daniel.stuewe@tum.de_649/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Wauligmann_Martin_martin.wauligmann@tum.de_641/hw13.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,55 @@
+theory hw13
+imports "~~/src/HOL/Library/Tree_Multiset"
+begin
+
+datatype 'a hp = Hp 'a "'a hp list"
+type_synonym 'a heap = "'a hp option"
+
+fun get_min :: "('a :: linorder) heap \<Rightarrow> 'a" where
+"get_min (Some (Hp x _)) = x"
+
+fun merge :: "('a :: linorder) heap \<Rightarrow> 'a heap \<Rightarrow> 'a heap" where
+"merge h None = h" |
+"merge None h = h" |
+"merge (Some (Hp x lx)) (Some (Hp y ly)) = 
+    (if x < y then Some (Hp x (Hp y ly # lx)) else Some( Hp y (Hp x lx # ly)))"
+
+fun merge_pairs :: "('a :: linorder) hp list \<Rightarrow> 'a heap" where
+"merge_pairs [] = None" |
+"merge_pairs [h] = Some h" |
+"merge_pairs (h1 # h2 # hs) = merge (merge (Some h1) (Some h2)) (merge_pairs hs)"
+
+fun del_min :: "'a :: linorder heap \<Rightarrow> 'a heap" where
+"del_min None = None" |
+"del_min (Some (Hp x hs)) = merge_pairs hs"
+
+
+fun php :: "('a :: linorder) hp \<Rightarrow> bool" where
+"php (Hp x hs) = (\<forall>h \<in> set hs. (\<forall>y \<in> set_hp h. x \<le> y) \<and> php h)"
+
+fun mset_hp :: "'a hp \<Rightarrow>'a multiset" where
+"mset_hp (Hp x hs) = {#x#} + Union_mset(mset(map mset_hp hs))"
+
+fun mset_heap :: "'a heap \<Rightarrow>'a multiset" where
+"mset_heap None = {#}" |
+"mset_heap (Some h) = mset_hp h"
+ 
+  
+theorem get_min_in: "php h \<Longrightarrow> get_min (Some h) \<in> set_hp(h)" 
+by(cases h)(auto)
+
+lemma get_min_min: "\<lbrakk> php h; x \<in> set_hp(h) \<rbrakk> \<Longrightarrow> get_min (Some h) \<le> x"
+by(cases h)(auto)
+
+
+lemma mset_merge: "mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2"
+by(induction h1 h2 rule: merge.induct)(auto simp: add_ac)
+
+lemma mset_merge_pairs: "mset_heap (merge_pairs hs) = Union_mset(image_mset mset_hp(mset hs))"
+by(induction hs rule: merge_pairs.induct)(auto simp: mset_merge)
+  
+lemma mset_del_min: 
+  "php h \<Longrightarrow> mset_heap (del_min (Some h)) = mset_hp h - {#get_min(Some h)#}"
+by(cases h) (auto simp: mset_merge_pairs)
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/Wauligmann_Martin_martin.wauligmann@tum.de_641/testoutput.html	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,24 @@
+
+<html>
+<head>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
+</head>
+<body>
+<h3>1/1 test cases passed!</h3>
+
+<table class="table">
+<thead>
+<tr>
+<th>Test Case</th><th>Passed</th>
+</tr>
+</thead>
+<tbody>
+
+<tr><td>check_build</td><td>Passed</td></tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/13/meta.csv	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,20 @@
+"612","jonas.keinholz@tum.de","Keinholz","Jonas","http://vmnipkow3.in.tum.de/web/submissions/612"
+"613","julian.biendarra@tum.de","Biendarra","Julian","http://vmnipkow3.in.tum.de/web/submissions/613"
+"614","shuwei.hu@tum.de","Hu","Shuwei","http://vmnipkow3.in.tum.de/web/submissions/614"
+"616","f.hellauer@tum.de","Hellauer","Fabian","http://vmnipkow3.in.tum.de/web/submissions/616"
+"617","lukas.stevens@tum.de","Stevens","Lukas","http://vmnipkow3.in.tum.de/web/submissions/617"
+"620","antoine.saporta@tum.de","Saporta","Antoine Jacques","http://vmnipkow3.in.tum.de/web/submissions/620"
+"621","jonas.raedle@tum.de","Rdle","Karl Jonas","http://vmnipkow3.in.tum.de/web/submissions/621"
+"622","max.haslbeck@mytum.de","Haslbeck","Maximilian","http://vmnipkow3.in.tum.de/web/submissions/622"
+"623","ga48kog@mytum.de","Erhard","Julian","http://vmnipkow3.in.tum.de/web/submissions/623"
+"624","jochen.guenther@mytum.de","Gnther","Jochen","http://vmnipkow3.in.tum.de/web/submissions/624"
+"625","daniel.somogyi@tum.de","Somogyi","Daniel","http://vmnipkow3.in.tum.de/web/submissions/625"
+"626","fabio.madge@tum.de","Madge Pimentel","Fabio","http://vmnipkow3.in.tum.de/web/submissions/626"
+"627","ga96vup@mytum.de","Ouyang","Lena","http://vmnipkow3.in.tum.de/web/submissions/627"
+"630","simon.rosskopf@tum.de","Rokopf","Simon","http://vmnipkow3.in.tum.de/web/submissions/630"
+"635","markus.grosser@tum.de","Groer","Markus","http://vmnipkow3.in.tum.de/web/submissions/635"
+"641","martin.wauligmann@tum.de","Wauligmann","Martin","http://vmnipkow3.in.tum.de/web/submissions/641"
+"643","maximilian.schaeffeler@tum.de","Schffeler","Maximilian","http://vmnipkow3.in.tum.de/web/submissions/643"
+"645","friedrich.kurz@tum.de","Kurz","Friedrich","http://vmnipkow3.in.tum.de/web/submissions/645"
+"649","daniel.stuewe@tum.de","Stwe","Daniel","http://vmnipkow3.in.tum.de/web/submissions/649"
+"650","ga95luy@mytum.de","Hutzler","Matthias","http://vmnipkow3.in.tum.de/web/submissions/650"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Biendarra_Julian_julian.biendarra@tum.de_632/matroids.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,620 @@
+
+(*\<Rightarrow>Manuel*)
+theory matroids
+  imports Main
+begin
+
+(*
+Theory of independent systems and matroids
+
+based on the material of "Combinatorial Optimization (MA 4502)",
+SoSe 2017, from José Soto
+
+which is based on "Lee: A First Course in Combinatorial Optimization,
+Cambridge Texts in Applied Mathematics, 2004"
+
+The main part is the Greedy Algorithm and the optimality proof for the
+Greedy Algorithm for matroids.
+*)
+
+locale independent_system =
+  fixes E :: "'a set"
+  fixes I :: "'a set set"
+  assumes powerset: "A \<in> I \<Longrightarrow> A \<subseteq> E"
+  and finite_E: "finite E"
+  and I1: "{} \<in> I"
+  and I2: "\<And>X Y. X \<subseteq> Y \<Longrightarrow> Y \<in> I \<Longrightarrow> X \<in> I"
+begin
+
+abbreviation "base X B \<equiv> B \<subseteq> X \<and> B \<in> I \<and> (\<forall>e \<in> X - B. B \<union> {e} \<notin> I)"
+definition "rank X = Max (card ` {Y. Y \<subseteq> X \<and> Y \<in> I})"
+abbreviation "circuit X \<equiv> X \<subseteq> E \<and> X \<notin> I \<and> (\<forall>e\<in>X. X - {e} \<in> I)"
+abbreviation "circuits \<equiv> {X. circuit X}"
+
+(* finite *)
+lemma finite_I: "finite I"
+  using finite_E powerset
+  by (meson Sup_le_iff finite_UnionD finite_subset)
+
+lemma finite_ind_set:
+  assumes "A \<in> I"
+  shows "finite A"
+  using assms finite_E powerset 
+  by (simp add: rev_finite_subset)
+
+(* bases *)
+lemma exist_base:
+  assumes "X \<subseteq> E"
+  shows "\<exists>B. base X B"
+proof -
+  from finite_E assms have "finite X" by (simp add: finite_subset)
+  then show ?thesis
+  proof (induction X rule: finite_induct)
+    case empty
+    from I1 show ?case by simp
+  next
+    case (insert x F)
+    then obtain B where B: "base F B" by auto
+    show ?case
+    proof (cases "B \<union> {x} \<in> I")
+      case True
+      from B have "(\<forall>e \<in> F - B. B \<union> {e} \<notin> I)" by simp
+      have "(\<forall>e \<in> F - (B \<union> {x}). B \<union> {x} \<union> {e} \<notin> I)"
+      proof
+        fix e
+        assume "e \<in> F - (B \<union> {x})"
+        then have "e \<in> F - B" by simp
+        with B have "B \<union> {e} \<notin> I" by simp
+        with I2[of "B \<union> {e}" "B \<union> {x} \<union> {e}"] show "B \<union> {x} \<union> {e} \<notin> I" by auto
+      qed
+      with B True have "base (insert x F) (insert x B)"
+        by auto
+      then show ?thesis by blast
+    next
+      case False
+      with B show ?thesis by auto
+    qed
+  qed
+qed
+
+(* circuits *)
+lemma C1:
+  shows "{} \<notin> circuits"
+by (simp add: I1)
+
+lemma C2:
+  assumes "X \<in> circuits"
+  assumes "Y \<in> circuits"
+  assumes "X \<subseteq> Y"
+  shows "X = Y"
+proof (rule ccontr)
+  assume "X \<noteq> Y"
+  with assms(3) obtain e where e: "e \<in> Y - X" by blast
+  with assms(2) have ind: "Y - {e} \<in> I" by simp
+  with e assms(3) have "X \<subseteq> Y - {e}" by auto
+  with ind assms(1) I2 show False by simp
+qed
+
+(* rank *)
+lemma R1:
+  assumes "finite X"
+  shows "rank X \<in> {0..card X}"
+proof -
+  from finite_I have finite: "finite (card ` {Y. Y \<subseteq> X \<and> Y \<in> I})" by simp
+  have "card X \<ge> rank X"
+  proof (rule ccontr)
+    assume "\<not> rank X \<le> card X"
+    then have asm: "rank X > card X" by simp
+    from I1 have "card {} \<in> card ` {Y. Y \<subseteq> X \<and> Y \<in> I}" by force
+    with Max_in[OF finite] have "Max (card ` {Y. Y \<subseteq> X \<and> Y \<in> I}) \<in> card ` {Y. Y \<subseteq> X \<and> Y \<in> I}"
+      unfolding rank_def
+      by auto
+    with asm have "\<exists>Y \<subseteq> X. Y \<in> I \<and> card Y > card X"
+      unfolding rank_def
+      by auto
+    then obtain Y where "Y \<subseteq> X \<and> card Y > card X" by auto
+    with card_mono[OF assms, of Y] show False by simp
+  qed
+  then show ?thesis by simp
+qed
+
+lemma R2:
+  assumes "X \<subseteq> Y"
+  shows "rank X \<le> rank Y"
+proof -
+  from assms have *: "card ` {Z. Z \<subseteq> X \<and> Z \<in> I} \<subseteq> card ` {Z. Z \<subseteq> Y \<and> Z \<in> I}"
+    by auto
+  from finite_I have "finite (card ` {Z. Z \<subseteq> Y \<and> Z \<in> I})"
+    by simp
+  with Max_mono[OF *] I1 show ?thesis
+    unfolding rank_def
+    by auto
+qed
+
+lemma rank_ind:
+  assumes "X \<in> I"
+  shows "rank X = card X"
+proof -
+  from finite_ind_set assms have "finite X" by simp
+  from finite_I have finite: "finite (card ` {Y. Y \<subseteq> X \<and> Y \<in> I})" by simp
+  also from assms have "card X \<in> card ` {Y. Y \<subseteq> X \<and> Y \<in> I}" by simp
+  ultimately have "card X \<le> rank X" unfolding rank_def by auto
+  also from R1[OF `finite X`] have "rank X \<le> card X" by simp
+  finally show ?thesis ..
+qed
+
+end
+
+
+locale matroid =
+  fixes E :: "'a set"
+  fixes I :: "'a set set"
+  assumes independent: "independent_system E I"
+  and I3: "\<And>X Y. X \<in> I \<Longrightarrow> Y \<in> I \<Longrightarrow> card X < card Y \<Longrightarrow> \<exists>e \<in> Y - X. X \<union> {e} \<in> I"
+begin
+  
+sublocale independent_system by (rule independent)
+
+lemma I3':
+  assumes "X \<in> I"
+  assumes "Y \<in> I"
+  assumes "card X \<le> card Y"
+  shows "\<exists>Z. X \<subseteq> Z \<and> Z \<in> I \<and> card Y = card Z"
+proof -
+  from finite_ind_set assms(2) have "finite Y" by simp
+  from this assms show ?thesis
+  proof (induction Y arbitrary: X rule: finite_induct)
+    case empty
+    with I1 finite_ind_set show ?case by auto
+  next
+    case (insert x F)
+    from I2[OF _ insert.prems(2), of F] have "F \<in> I"
+      by (simp add: subset_insertI)
+    show ?case
+      proof (cases "card X = card (insert x F)")
+        case True
+        with `X \<in> I` have "X \<subseteq> X \<and> X \<in> I \<and> card (insert x F) = card X"
+          by simp
+        then show ?thesis by auto
+      next
+        case False
+        with `card X \<le> card (insert x F)` `x \<notin> F` `finite F`
+          have "card X \<le> card F" by simp
+        from insert.IH[OF `X \<in> I` `F \<in> I` this]
+          obtain Z where "X \<subseteq> Z" "Z \<in> I" and "card F = card Z"
+            by auto
+        with `F \<in> I` finite_ind_set `x \<notin> F` have "card Z + 1 = card (insert x F)"
+          by simp
+        then have "card Z < card (insert x F)" by simp
+        from I3[OF `Z \<in> I` `insert x F \<in> I` this]
+          obtain e where "e \<in> insert x F - Z" and "Z \<union> {e} \<in> I"
+          by auto
+        with `card Z + 1 = card (insert x F)` `X \<subseteq> Z` `Z \<in> I` finite_ind_set
+          have "X \<subseteq> insert e Z \<and> insert e Z \<in> I \<and> card (insert x F) = card (insert e Z)"
+          by auto
+        then show ?thesis by auto
+      qed
+  qed
+qed
+
+(* base *)
+lemma
+  assumes "base X A"
+  assumes "base X B"
+  shows "card A = card B"
+proof (rule ccontr)
+  assume asm: "card A \<noteq> card B"
+  show False
+    proof (cases "card A < card B")
+      case True
+      from assms(1) have "A \<in> I" by simp
+      also from assms(2) have "B \<in> I" by simp
+      ultimately obtain e where "e \<in> B - A" and "A \<union> {e} \<in> I" using I3 True by blast
+      with assms(2) have "e \<in> X - A" by auto
+      with assms(1) have "A \<union> {e} \<notin> I" by simp
+      with `A \<union> {e} \<in> I` show ?thesis by simp
+    next
+      case False
+      with asm have False': "card B < card A" by simp
+      from assms(1) have "A \<in> I" by simp
+      also from assms(2) have "B \<in> I" by simp
+      ultimately obtain e where "e \<in> A - B" and "B \<union> {e} \<in> I" using I3 False' by blast
+      with assms(1) have "e \<in> X - B" by auto
+      with assms(2) have "B \<union> {e} \<notin> I" by simp
+      with `B \<union> {e} \<in> I` show ?thesis by simp
+    qed
+qed
+
+(* rank *)
+lemma rank_base:
+  assumes "base X B"
+  shows "rank X = card B"
+proof -
+  from finite_ind_set assms have "finite B" by simp
+  from finite_I have finite: "finite (card ` {Y. Y \<subseteq> X \<and> Y \<in> I})" by simp
+  also from assms have B_in: "card B \<in> card ` {Y. Y \<subseteq> X \<and> Y \<in> I}" by simp
+  ultimately have "card B \<le> rank X" unfolding rank_def by auto
+  also have "rank X \<le> card B"
+  proof (rule ccontr)
+    assume asm: "\<not> rank X \<le> card B"
+    from Max_in[OF finite] B_in have "rank X \<in> card ` {Y. Y \<subseteq> X \<and> Y \<in> I}"
+      unfolding rank_def by auto
+    then obtain Y where "card Y = rank X" and "Y \<subseteq> X" and "Y \<in> I"
+      by auto
+    with asm have "card Y > card B" by simp
+    with I3 assms `Y \<in> I` obtain e where "e \<in> Y - B" and "B \<union> {e} \<in> I"
+      by blast
+    with `Y \<subseteq> X` have "e \<in> X - B" by auto
+    with `B \<union> {e} \<in> I` assms show False by simp
+  qed
+  finally show ?thesis ..
+qed
+
+(* Greedy *)
+fun greedy_s :: "'a list \<Rightarrow> 'a  list" where
+  "greedy_s [] = []" |
+  "greedy_s (e#es) = (
+    if set (e # greedy_s es) \<in> I
+    then e # greedy_s es
+    else greedy_s es)"
+
+fun greedy :: "('a \<Rightarrow> nat) \<Rightarrow> 'a set" where
+  "greedy w = set (greedy_s (linorder.sorted_list_of_set (\<lambda>a b. w a \<le> w b) E))"
+
+lemma greedy_property:
+  assumes "i < length es"
+  assumes "es ! i \<notin> set (greedy_s es)"
+  shows "set (greedy_s es) \<union> {es ! i} \<notin> I"
+  using assms
+  proof (induction es arbitrary: i rule: greedy_s.induct)
+    case 1
+    then show ?case by simp
+  next
+    case (2 e es)
+    show ?case
+      proof(cases i)
+        case 0
+        with 2 show ?thesis by auto
+      next
+        case (Suc nat)
+        with 2(1)[of nat] 2(4) 2(5)
+          I2[of "insert (es ! nat) (set (greedy_s es))"
+            "insert (es ! nat) (insert e (set (greedy_s es)))"]
+          subset_insertI2[OF subset_insertI[of "set (greedy_s es)" "e"]]
+          show ?thesis
+          by auto
+      qed
+  qed
+
+lemma greedy_s_sublist:
+  shows "greedy_s es \<in> set (sublists es)"
+proof (induction es)
+  case Nil
+  then show ?case by simp
+next
+  case (Cons e es)
+  have "sublists (e#es) = map (op # e) (sublists es) @ (sublists es)"
+    by (meson sublists.simps(2))
+  with Cons.IH show ?case
+    by auto
+qed
+
+lemma greedy_s_subset:
+  shows "set (greedy_s es) \<subseteq> set es"
+  by (induction es) auto
+
+lemma greedy_s_distinct:
+  assumes "distinct es"
+  shows "distinct (greedy_s es)"
+  using assms greedy_s_subset
+  by (induction es) auto
+
+lemma greedy_s_sorted:
+  assumes "class.linorder leq le"
+  assumes "linorder.sorted leq es"
+  shows "linorder.sorted leq (greedy_s es)"
+  using assms
+  proof (induction es rule: greedy_s.induct)
+    case 1
+    then show ?case by simp
+  next
+    case (2 e es)
+    then show ?case
+    proof (cases "set (e # greedy_s es) \<in> I")
+      case True
+      from linorder.sorted_Cons[OF 2(4)] 2(5)
+        have *: "linorder.sorted leq es \<and> (\<forall>y\<in>set es. leq e y)"
+        by simp
+      with 2(1)[OF 2(4)] have **: "linorder.sorted leq (greedy_s es)"
+        by simp
+      from * greedy_s_subset have "\<forall>y\<in>set (greedy_s es). leq e y" by auto
+      with linorder.sorted_Cons[OF 2(4), of e "greedy_s es"] ** show ?thesis
+        by auto
+    next
+      case False
+      with 2 linorder.sorted_Cons[OF 2(4)] show ?thesis by auto
+    qed
+  qed
+
+lemma greedy_s_take:
+  shows "set (greedy_s (drop k es)) \<subseteq> set (greedy_s es)"
+proof (induction es arbitrary: k)
+  case (Cons a es)
+  then show ?case
+    by (cases k) auto
+qed simp
+
+lemma greedy_s_result:
+  assumes "distinct es"
+  assumes "k < length es"
+  assumes "p < length (greedy_s es)"
+  assumes "es ! k = greedy_s es ! p"
+  shows "greedy_s (drop (k+1) es) = drop (p+1) (greedy_s es)"
+  using assms
+proof (induction es arbitrary: k p)
+  case (Cons a es)
+  from greedy_s_subset[of es]
+    have in_set: "i < length (greedy_s es) \<Longrightarrow> greedy_s es ! i \<in> set es" for i
+    by auto
+  from Cons show ?case
+  proof (cases k)
+    case 0
+    with Cons in_set show ?thesis by (cases p) auto
+  next
+    case (Suc nat)
+    with Cons in_set show ?thesis by (cases p) auto
+  qed
+qed simp
+
+lemma greedy_sol_independent:
+  fixes w :: "'a \<Rightarrow> nat"
+  shows "greedy w \<in> I"
+proof -
+  define es where es: "es = linorder.sorted_list_of_set (\<lambda>a b. w a \<le> w b) E"
+  have "set (greedy_s es) \<in> I"
+   by (induction es rule: greedy_s.induct) (auto simp: I1)
+  with es show ?thesis by simp
+qed
+
+lemma greedy_sol_base:
+  fixes w :: "'a \<Rightarrow> nat"
+  assumes "inj w"
+  shows "base E (greedy w)"
+proof -
+  from assms(1)
+    have linorder: "class.linorder (\<lambda>a b. w a \<le> w b) (\<lambda>a b. w a < w b)"
+    unfolding class.linorder_def class.order_def class.linorder_axioms_def
+      class.preorder_def class.order_axioms_def
+    by (auto simp: injD)
+
+  define es where es: "es = linorder.sorted_list_of_set (\<lambda>a b. w a \<le> w b) E"
+  have "\<forall>e\<in>E - greedy w. greedy w \<union> {e} \<notin> I"
+  proof
+    fix e
+    assume asm: "e \<in> E - greedy w"
+    with es linorder.sorted_list_of_set[OF linorder finite_E]
+      have "e \<in> set es" by simp
+    then obtain i where "es ! i = e" and i_le: "i < length es"
+      by (auto simp: in_set_conv_nth)
+    with asm es have "es ! i \<notin> set (greedy_s es)" by simp
+    from greedy_property[OF i_le this] es `es ! i = e`
+      show "greedy w \<union> {e} \<notin> I" by simp
+  qed
+  with greedy_sol_independent powerset show ?thesis by simp 
+qed
+
+theorem greedy_local_optimal:
+  fixes w :: "'a \<Rightarrow> nat"
+  (* further TODO: get rid of constraint `ind w` *)
+  assumes "inj w"
+  assumes "T \<in> I"
+  assumes "card T = card (greedy w)"
+  shows "sum w (greedy w) \<ge> sum w T"
+proof (rule ccontr)
+  assume asm: "\<not> (sum w (greedy w) \<ge> sum w T)"
+  define S where S: "S = greedy w"
+  define k where k: "k = card S"
+  define ss where ss: "ss = linorder.sorted_list_of_set (\<lambda>a b. w a \<le> w b) S"
+  define ts where ts: "ts = linorder.sorted_list_of_set (\<lambda>a b. w a \<le> w b) T"
+  define es where es: "es = linorder.sorted_list_of_set (\<lambda>a b. w a \<le> w b) E"
+  from assms(1)
+    have linorder: "class.linorder (\<lambda>a b. w a \<le> w b) (\<lambda>a b. w a < w b)"
+    unfolding class.linorder_def class.order_def class.linorder_axioms_def
+      class.preorder_def class.order_axioms_def
+    by (auto simp: injD)
+  from S greedy_sol_independent have S_ind: "S \<in> I" by simp
+  with finite_ind_set have finite_S: "finite S"
+    by simp
+  from ss linorder.sorted_list_of_set[OF linorder finite_S]
+    have sorted_ss: "linorder.sorted (\<lambda>a b. w a \<le> w b) ss"
+    and distinct_ss: "distinct ss"
+    and ss_S: "set ss = S"
+    by auto
+  from assms finite_ind_set have finite_T: "finite T"
+    by simp
+  from ts linorder.sorted_list_of_set[OF linorder finite_T]
+    have sorted_ts: "linorder.sorted (\<lambda>a b. w a \<le> w b) ts"
+    and distinct_ts: "distinct ts"
+    and ts_T: "set ts = T"
+    by auto
+  from es linorder.sorted_list_of_set[OF linorder finite_E]
+    have sorted_es: "linorder.sorted (\<lambda>a b. w a \<le> w b) es"
+    and distinct_es: "distinct es"
+    and es_E: "set es = E"
+    by auto
+  from k distinct_card distinct_ss ss_S have k_ss: "k = length ss" by auto
+  from k distinct_card distinct_ts ts_T assms S have k_ts: "k = length ts" by fastforce
+
+  from es S have "set (greedy_s es) = S" by simp
+  with ss linorder.sorted_list_of_set_sort_remdups[OF linorder, of "greedy_s es"]
+    have "ss = linorder.sort_key (\<lambda>a b. w a \<le> w b) (\<lambda>x. x) (remdups (greedy_s es))"
+    by simp
+  also from greedy_s_distinct[OF distinct_es] distinct_remdups_id[of "greedy_s es"]
+    have "\<dots> = linorder.sort_key (\<lambda>a b. w a \<le> w b) (\<lambda>x. x) (greedy_s es)"
+    by presburger
+  also from greedy_s_sorted[OF linorder sorted_es]
+      linorder.sorted_sort_id[OF linorder, of "greedy_s es"]
+    have "\<dots> = greedy_s es"
+    by simp
+  finally have "ss = greedy_s es" .
+
+  have "\<exists>p \<in> {0..<k}. w (ts ! p) > w (ss ! p)"
+  proof (rule ccontr)
+    assume "\<not>(\<exists>p \<in> {0..<k}. w (ts ! p) > w (ss ! p))"
+    then have asm2: "\<forall>p \<in> {0..<k}. w (ts ! p) \<le> w (ss ! p)" by auto
+    from distinct_ts ts_T sum_code[of w ts] distinct_remdups_id[of ts]
+      have "sum w T = sum_list (map w ts)"
+      by simp
+    also have "\<dots> = (\<Sum>p\<in>{0..<k}. w (ts ! p))"
+      by (auto simp: sum_list_sum_nth k_ts)
+    also from sum_mono[of "{0..<k}" "\<lambda>p. w (ts ! p)"  "\<lambda>p. w (ss ! p)"] asm2
+      have "\<dots> \<le> (\<Sum>p\<in>{0..<k}. w (ss ! p))"
+      by simp
+    also have "\<dots> = sum_list (map w ss)"
+      by (auto simp: sum_list_sum_nth k_ss)
+    also from distinct_ss ss_S sum_code[of w ss] distinct_remdups_id[of ss]
+      have "\<dots> = sum w S"
+      by simp
+    finally show False using S asm by simp
+  qed
+  then obtain p where p_ind: "p\<in>{0..<k}" and w_p: "w (ss ! p) < w (ts ! p)" by blast
+  define T' where T': "T' = set (drop p ts)"
+  define S' where S': "S' = set (drop (p+1) ss)"
+
+  from T' S' distinct_ts distinct_ss p_ind k_ss k_ts have "card S' < card T'"
+    by (auto simp: distinct_card)
+  have "S' \<subseteq> S" using ss_S S' set_drop_subset[of _ ss]
+    by simp
+  with I2 S_ind have "S' \<in> I"
+    by simp
+  have "T' \<subseteq> T" using ts_T T' set_drop_subset[of _ ts]
+    by simp
+  with I2 assms have "T' \<in> I"
+    by simp
+  with `card S' < card T'` `S' \<in> I` I3
+    obtain t where t: "t\<in>T' - S'" and t_ind: "S' \<union> {t} \<in> I"
+      by blast
+  from t T' in_set_conv_nth[of t "drop p ts"]
+    obtain i where "drop p ts ! i = t" and "i<length (drop p ts)"
+    by blast
+  with linorder.sorted_nth_mono[OF linorder linorder.sorted_drop[OF
+      linorder sorted_ts, of p], of 0 i] p_ind k_ts
+    have "w (ts ! p) \<le> w t"
+    by auto
+  with w_p have "w (ss ! p) < w t"
+    by simp
+
+  from ss_S powerset S_ind es_E nth_mem p_ind k_ss 
+    have "ss ! p \<in> set es"
+    by auto
+  then obtain j where "es ! j = ss ! p" and "j < length es"
+    by (auto simp: in_set_conv_nth)
+
+  from set_drop_subset[of p ts] t T' ts_T assms(2) powerset es_E
+    have "t \<in> set es"
+    by auto
+  then obtain l where "es ! l = t" and "l < length es"
+    by (auto simp: in_set_conv_nth)
+  from linorder.sorted_nth_mono[OF linorder sorted_es _ `j < length es`,
+      of l] `es ! j = ss ! p` `es ! l = t` `w t > w (ss ! p)`
+    have "j < l"
+    by fastforce
+
+  from `j < l` `l < length es` have l: "l-j-1 < length (drop (j + 1) es)"
+    by simp
+  from `l < length es` `es ! l = t` `j < l` have t': "drop (j+1) es ! (l-j-1) = t"
+    by simp
+  from greedy_s_result[of es j p, OF distinct_es] `es ! j = ss ! p`
+      `ss = greedy_s es` p_ind k_ss `j < length es`
+    have greedy_res: "greedy_s (drop (j + 1) es) = drop (p + 1) ss"
+      by simp
+  with t' S' `t \<in> T' - S'`
+    have "drop (j+1) es ! (l-j-1) \<notin> set (greedy_s (drop (j+1) es))"
+    by simp
+  from S' greedy_res greedy_property[OF l this] t'
+    have "S' \<union> {t} \<notin> I"
+      by simp
+  with `S' \<union> {t} \<in> I` show False by simp
+qed
+
+theorem greedy_optimal:
+  fixes w :: "'a \<Rightarrow> nat"
+  assumes "inj w"
+  shows "greedy w \<in> I \<and> (\<forall>T \<in> I. sum w (greedy w) \<ge> sum w T)"
+proof -
+  from greedy_sol_independent have ind: "greedy w \<in> I" by simp
+  also have "\<forall>T \<in> I. sum w (greedy w) \<ge> sum w T"
+  proof
+    fix T
+    assume "T \<in> I"
+    show "sum w (greedy w) \<ge> sum w T"
+    proof (cases "card T \<le> card (greedy w)")
+      case True
+      from I3'[OF `T \<in> I` ind True]
+        obtain T' where T': "T \<subseteq> T' \<and> T' \<in> I \<and> card (greedy w) = card T'"
+        by blast
+      with finite_ind_set[of T'] have "sum w T \<le> sum w T'"
+        by (auto simp: sum_mono2)
+      also from T' greedy_local_optimal[OF assms] have "sum w T' \<le> sum w (greedy w)"
+        by simp
+      finally show ?thesis .
+    next
+      case False
+      then have False': "card (greedy w) < card T" by simp
+      with I3[OF ind `T \<in> I` False'] obtain e where "e \<in> T - greedy w" and "greedy w \<union> {e} \<in> I"
+        by blast
+      with `T \<in> I` powerset have "e \<in> E - greedy w" by auto
+      from greedy_sol_base[OF assms(1)] have "base E (greedy w)" by simp
+      with `e \<in> E - greedy w` have "greedy w \<union> {e} \<notin> I" by simp
+      with `greedy w \<union> {e} \<in> I` have False by simp
+      then show ?thesis by simp
+    qed
+  qed
+  ultimately show ?thesis ..
+qed
+
+end
+
+(* example: uniform matroid *)
+lemma uniform_matroid:
+  fixes E :: "'a set"
+  fixes r :: nat
+  assumes "finite E"
+  shows "matroid E {X. X \<subseteq> E \<and> card X \<le> r}"
+proof
+  from assms show "finite E" .
+next
+  fix X Y :: "'a set"
+  assume 1: "X \<subseteq> Y"
+  assume 2: "Y \<in> {X. X \<subseteq> E \<and> card X \<le> r}"
+  then have 3: "Y \<subseteq> E" by simp
+  from 2 have 4: "card Y \<le> r" by simp
+  from card_mono[OF finite_subset[OF 3 assms] 1] 1 3 4
+    have "X \<subseteq> E \<and> card X \<le> r" by auto
+  then show "X \<in> {X. X \<subseteq> E \<and> card X \<le> r}" by simp
+next
+  fix X Y :: "'a set"
+  assume 1: "X \<in> {X. X \<subseteq> E \<and> card X \<le> r}"
+  assume 2: "Y \<in> {X. X \<subseteq> E \<and> card X \<le> r}"
+  assume 3: "card X < card Y"
+  from 3 have "Y - X \<noteq> {}"
+    by (metis "1" assms card_empty diff_card_le_card_Diff finite_subset mem_Collect_eq not_le zero_less_diff)
+  then obtain e where e: "e \<in> Y - X" by blast
+  with 1 2 have subset: "X \<union> {e} \<subseteq> E" by auto
+  from e finite_subset[OF subset assms]
+    have "card (X \<union> {e}) = card X + 1"
+    by (auto simp: card_insert_if)
+  also from 3 have "card X + 1 \<le> card Y" by simp
+  also from 2 have "card Y \<le> r" by simp
+  finally have "X \<union> {e} \<in> {X. X \<subseteq> E \<and> card X \<le> r}"
+    using subset by simp
+  with e show "\<exists>e\<in>Y - X. X \<union> {e} \<in> {X. X \<subseteq> E \<and> card X \<le> r}"
+    by auto
+qed auto
+
+interpretation uniform_matroid_ex: matroid "{1::nat..10}" "{X. X \<subseteq> {1..10} \<and> card X \<le> 5}"
+  by (rule uniform_matroid) simp
+
+term uniform_matroid_ex.greedy
+thm uniform_matroid_ex.greedy_optimal
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Biendarra_Julian_julian.biendarra@tum.de_632/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,2 @@
+Using temporary directory '/tmp/tmp.Gsk4eN0mmX'
+Exercise path '/home/admin/suites/exbeoriginal' not found
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Erhard_Julian_ga48kog@mytum.de_655/quadtrees.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,262 @@
+(*\<Rightarrow> Tobias*)
+theory quadtrees
+imports Complex_Main
+begin
+  
+type_synonym Point = "real * real"  
+
+definition
+  mapping :: "('a \<rightharpoonup> 'b) \<Rightarrow> ('a * 'b) set" where
+  "mapping m = {(a, b). m a = Some b}"  
+
+(*Implements a point quadtree: mapping from points to values *)
+(*No duplicate keys are stored*)  
+(*if the y value of the new node is strictly greater than of the root of the exisiting tree, it is inserted in the north, ow in the south*)
+(*if the x value of the new node is strictly greater than of the root of the exisiting tree, it is inserted in the east, ow in the west*)
+datatype 'a quadtree = Leaf |
+                       Node (key: Point) (val: 'a) (NW: "'a quadtree") (NE: "'a quadtree") 
+                                                    (SE: "'a quadtree") (SW: "'a quadtree")
+                                                    
+fun qinsert :: "Point \<Rightarrow> 'a \<Rightarrow> 'a quadtree \<Rightarrow> 'a quadtree" where
+  "qinsert (x,y) v Leaf = Node (x,y) v Leaf Leaf Leaf Leaf" |
+  "qinsert (x,y) v (Node (x2, y2) v2 nw ne se sw) = (if x=x2\<and>y=y2 then Node (x2, y2) v nw ne se sw else
+                                                    (if (y > y2) then (if (x \<le> x2) then Node (x2, y2) v2 (qinsert (x,y) v nw) ne se sw
+                                                                       else  Node (x2, y2) v2 nw (qinsert (x,y) v ne) se sw) else
+                                                                       if ( x > x2) then Node (x2, y2) v2 nw ne (qinsert (x,y) v se) sw
+                                                                       else Node (x2, y2) v2 nw ne se (qinsert (x,y) v sw)))"
+  
+fun qinsert_list :: "'a quadtree \<Rightarrow>(Point * 'a) list \<Rightarrow> 'a quadtree" where
+  "qinsert_list t l = fold (\<lambda>(k,v) acc. qinsert k v acc) l t"
+
+fun list_quadtree :: "'a quadtree \<Rightarrow> (Point * 'a) list" where
+  "list_quadtree Leaf = []" |
+  "list_quadtree (Node (x2, y2) v2 nw ne se sw)  = ((x2,y2), v2) # ((list_quadtree nw) @ (list_quadtree ne) @ (list_quadtree se) @ (list_quadtree sw))"
+   
+  
+fun map_quadtree :: "'a quadtree \<Rightarrow> (Point, 'a) map" where
+  "map_quadtree Leaf = empty" |
+  "map_quadtree (Node (x2, y2) v2 nw ne se sw)  = (\<lambda>(x3, y3). if(x3=x2 \<and>y3=y2) then Some v2 else None) ++ ((map_quadtree nw) ++ (map_quadtree ne) ++ (map_quadtree se) ++ (map_quadtree sw))"
+
+fun mapset_quadtree :: "'a quadtree \<Rightarrow> (Point * 'a) set" where
+  "mapset_quadtree Leaf = {}" |
+  "mapset_quadtree (Node (x2, y2) v2 nw ne se sw)  = insert ((x2,y2),v2) ((mapset_quadtree nw) \<union> (mapset_quadtree ne) \<union> (mapset_quadtree se) \<union> (mapset_quadtree sw))"
+  
+  
+fun set_quadtree :: "'a quadtree \<Rightarrow> 'a set" where
+  "set_quadtree Leaf = {}" |
+  "set_quadtree (Node _ v2 nw ne se sw) = insert v2 ((set_quadtree nw) \<union> (set_quadtree ne) \<union> (set_quadtree se) \<union> (set_quadtree sw))"
+
+fun keyset_quadtree :: "'a quadtree \<Rightarrow> Point set" where
+  "keyset_quadtree Leaf = {}" |
+  "keyset_quadtree (Node k _ nw ne se sw) = insert k ((keyset_quadtree nw) \<union> (keyset_quadtree ne) \<union> (keyset_quadtree se) \<union> (keyset_quadtree sw))"
+   
+  
+fun qlookup :: "Point \<Rightarrow> 'a quadtree \<Rightarrow> 'a option" where
+  "qlookup _ Leaf = None" |
+  "qlookup (x, y) (Node (x2, y2) v2 nw ne se sw)  =  (if x=x2 \<and> y=y2 then Some v2 else
+                                                          if ( y > y2) then
+                                                               if (x\<le>x2) then (qlookup (x,y) nw)
+                                                                         else (qlookup (x,y) ne) 
+                                                          else if(x>x2) then (qlookup (x,y) se)
+                                                                         else  (qlookup (x,y) sw)) "
+
+fun n :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+"n (_,y) (_,y2) = (y > y2)"   
+
+fun e :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+"e (x,_) (x2,_) = (x > x2)"   
+
+fun s :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+  "s p p2 = ( \<not> n p p2)"
+
+fun w :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+  "w p p2 = ( \<not> e p p2)"  
+  
+(*checks whether first arg is nw of second*)  
+fun isnw :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+"isnw p p2 = (n p p2 \<and> w p p2)"  
+
+fun isne :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+"isne p p2 = (n p p2 \<and> e p p2)"  
+
+fun issw :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+"issw p p2 = (s p p2 \<and> w p p2 \<and> p \<noteq> p2)"  
+
+fun isse :: "Point \<Rightarrow> Point \<Rightarrow> bool" where
+"isse p p2 = (s p p2 \<and> e p p2)"  
+
+
+(* checks whether the all nodes in the subtree of the first argument are in the 
+   north west of the point given as the second argument*)
+fun nwOf :: "'a quadtree \<Rightarrow> Point \<Rightarrow> bool" where
+  "nwOf Leaf _ = True" |
+  "nwOf node p2 = (\<forall>p \<in> (keyset_quadtree node) . isnw p p2 )"
+  
+fun neOf :: "'a quadtree \<Rightarrow> Point \<Rightarrow> bool" where
+  "neOf Leaf _ = True" |
+  "neOf node p2 = (\<forall>p \<in> (keyset_quadtree node) . isne p p2)"
+
+fun seOf :: "'a quadtree \<Rightarrow> Point \<Rightarrow> bool" where
+  "seOf Leaf _ = True" |
+  "seOf node p2 = (\<forall>p \<in> (keyset_quadtree node) . isse p p2)"
+  
+fun swOf :: "'a quadtree \<Rightarrow> Point \<Rightarrow> bool" where
+  "swOf Leaf _ = True" |
+  "swOf node p2 = (\<forall>p \<in> (keyset_quadtree node) . issw p p2)"
+(*end of helper functions*)  
+  
+fun invar :: "'a quadtree \<Rightarrow> bool" where
+  "invar Leaf = True" |
+  "invar (Node p _ nw ne se sw) \<longleftrightarrow> nwOf nw p \<and> neOf ne p \<and> seOf se p \<and> swOf sw p \<and>
+                                    invar nw \<and> invar ne \<and> invar se \<and> invar sw"
+
+fun delete :: "Point \<Rightarrow> 'a quadtree \<Rightarrow> 'a quadtree" where
+  "delete _  Leaf = Leaf" |
+  "delete (x,y) (Node (x2, y2) v nw ne se sw) = (if x=x2 \<and> y=y2 then  qinsert_list Leaf (tl (list_quadtree (Node (x2, y2) v nw ne se sw))) else 
+                                                (if y > y2 then (if x < x2 then (Node (x2,y2) v  (delete (x,y) nw) ne se sw) 
+                                                                else (Node (x2, y2) v nw (delete (x,y) ne) se sw ))
+                                                else (if x \<le> x2 then (Node (x2,y2) v nw ne sw  (delete (x,y) sw)) 
+                                                                else (Node (x2, y2) v nw ne (delete (x,y) se) sw ))))"
+
+lemma ks: " keyset_quadtree(qinsert (x,y) v t) = keyset_quadtree(t) \<union> {(x,y)}" 
+  apply (induction t)
+   apply (auto split: if_splits)
+    done      
+      
+lemma qinsert_non_Leaf: "qinsert (x,y) v t \<noteq> Leaf" 
+  apply (cases t)
+   apply (auto split: if_splits)
+    done
+      
+lemma "invar t \<Longrightarrow> invar (qinsert (x,y) v t)"
+proof (induction t  rule:qinsert.induct)
+  case (1 x y v)
+  then show ?case by simp
+next
+  case (2 x y v x2 y2 v2 nw ne se sw)
+  have "x=x2 \<and> y=y2 \<or> \<not>(x=x2 \<and> y=y2)" by blast
+  then show ?case 
+  proof
+    assume "x=x2 \<and> y=y2"
+    then show ?case using 2 by simp
+  next 
+    assume ne:"\<not>(x=x2 \<and> y=y2)"
+    then show ?case 
+    proof -
+    have "x\<le>x2 \<or> x>x2" by force
+    then show ?case
+    proof
+      assume xs: "x\<le>x2"
+        have "y\<le>y2 \<or> y>y2" by force
+        then show ?case
+        proof
+          assume ys: "y\<le>y2"
+          have swi:"invar sw" using 2 by simp
+          have nwi:"invar nw" using 2 by simp
+          have nei:"invar ne" using 2 by simp
+          have sei: "invar se" using 2 by simp
+              
+          have "invar (qinsert (x, y) v sw)" using 2(4) xs ys ne  swi by auto
+   
+          have swo: "swOf sw (x2,y2)" using 2(5) by simp
+              
+          have ksq: "(\<forall>p \<in> (keyset_quadtree sw) . issw p (x2,y2))" apply (cases sw) apply simp using swo 2(5) by simp
+              
+          let ?qi =  "(qinsert (x, y) v sw)"
+          have a: "swOf ?qi (x2,y2)  = (\<forall>p \<in> (keyset_quadtree ?qi) . issw p (x2,y2)) " using qinsert_non_Leaf[of x y v sw]  by (smt swOf.elims(2) swOf.elims(3))
+          also have b:"... = (\<forall>p \<in> (keyset_quadtree sw \<union> {(x,y)}) . issw p (x2,y2))" using ks[of x y v sw]  by simp
+          also have c: "... = True" using ksq xs ys ne by simp 
+              
+          have d:"invar (qinsert (x, y) v (Node (x2, y2) v2 nw ne se sw)) = invar ( (Node (x2, y2) v2 nw ne se (qinsert (x, y) v sw)))" using xs ys ne by auto
+          have e: "... = True " using a b c 2 by force
+          
+          from d e show ?case by simp
+        next
+          assume ys: "y2 < y"
+          have swi:"invar sw" using 2 by simp
+          have nwi:"invar nw" using 2 by simp
+          have nei:"invar ne" using 2 by simp
+          have sei: "invar se" using 2 by simp
+              
+          have "invar (qinsert (x, y) v nw)" using 2 xs ys  swi by auto
+   
+          have nwo: "nwOf nw (x2,y2)" using 2 by simp
+              
+          have ksq: "(\<forall>p \<in> (keyset_quadtree nw) . isnw p (x2,y2))" apply (cases nw) apply simp using nwo 2 by simp
+              
+          let ?qi =  "(qinsert (x, y) v nw)"
+          have a: "nwOf ?qi (x2,y2)  = (\<forall>p \<in> (keyset_quadtree ?qi) . isnw p (x2,y2)) " using qinsert_non_Leaf[of x y v nw]  by (smt nwOf.elims(2) nwOf.elims(3))
+          also have b:"... = (\<forall>p \<in> (keyset_quadtree nw \<union> {(x,y)}) . isnw p (x2,y2))" using ks[ of x y v nw]  by simp
+          also have c: "... = True" using ksq xs ys by simp    
+              
+          have d:"invar (qinsert (x, y) v (Node (x2, y2) v2 nw ne se sw)) = invar ( (Node (x2, y2) v2 (qinsert (x, y) v nw) ne se  sw))" using xs ys by simp
+          have e: "... = True " using a b c 2 by force
+          from d e show ?case by simp
+      qed
+    next
+        assume xs: "x>x2"
+        have "y\<le>y2 \<or> y>y2" by force
+        then show ?case
+        proof
+          assume ys: "y\<le>y2"
+          have swi:"invar sw" using 2 by simp
+          have nwi:"invar nw" using 2 by simp
+          have nei:"invar ne" using 2 by simp
+          have sei: "invar se" using 2 by simp
+              
+          have "invar (qinsert (x, y) v se)" using 2(3) xs ys  sei by auto
+   
+          have seo: "seOf se (x2,y2)" using 2(5) by simp
+              
+          have ksq: "(\<forall>p \<in> (keyset_quadtree se) . isse p (x2,y2))" apply (cases se) apply simp using seo 2(5) by simp
+              
+          let ?qi =  "(qinsert (x, y) v se)"
+          have a: "seOf ?qi (x2,y2)  = (\<forall>p \<in> (keyset_quadtree ?qi) . isse p (x2,y2)) " using qinsert_non_Leaf[of x y v se]  by (smt seOf.elims(2) seOf.elims(3))
+          also have b:"... = (\<forall>p \<in> (keyset_quadtree se \<union> {(x,y)}) . isse p (x2,y2))" using ks[ of x y v se]  by simp
+          also have c: "... = True" using ksq xs ys by simp 
+              
+          have d:"invar (qinsert (x, y) v (Node (x2, y2) v2 nw ne se sw)) = invar ( (Node (x2, y2) v2 nw ne (qinsert (x, y) v se)  sw))" using xs ys by simp
+          have e: "... = True " using a b c 2 by force
+          
+          from d e show ?case by simp
+        next
+          assume ys: "y2 < y"
+          have swi:"invar sw" using 2 by simp
+          have nwi:"invar nw" using 2 by simp
+          have nei:"invar ne" using 2 by simp
+          have sei: "invar se" using 2 by simp
+              
+          have "invar (qinsert (x, y) v ne)" using 2 xs ys  nei by auto
+   
+          have neo: "neOf ne (x2,y2)" using 2 by simp
+              
+          have ksq: "(\<forall>p \<in> (keyset_quadtree ne) . isne p (x2,y2))" apply (cases ne) apply simp using neo 2 by simp
+              
+          let ?qi =  "(qinsert (x, y) v ne)"
+          have a: "neOf ?qi (x2,y2)  = (\<forall>p \<in> (keyset_quadtree ?qi) . isne p (x2,y2)) " using qinsert_non_Leaf[of x y v ne]  by (smt neOf.elims(2) neOf.elims(3))
+          also have b:"... = (\<forall>p \<in> (keyset_quadtree ne \<union> {(x,y)}) . isne p (x2,y2))" using ks[ of x y v ne]  by simp
+          also have c: "... = True" using ksq xs ys by simp    
+              
+          have d:"invar (qinsert (x, y) v (Node (x2, y2) v2 nw ne se sw)) = invar ( (Node (x2, y2) v2 nw (qinsert (x, y) v ne) se  sw))" using xs ys by simp
+          have e: "... = True " using a b c 2 by force
+          from d e show ?case by simp
+      qed
+    qed
+    qed
+  qed
+qed
+
+lemma ins_set: "(x,y)\<notin>keyset_quadtree t \<Longrightarrow> set_quadtree(qinsert (x,y) v t) = set_quadtree(t) \<union> {v}" 
+  apply (induction t)
+   apply force
+   apply force
+   done  
+
+lemma  "invar t\<Longrightarrow> mapset_quadtree(qinsert (x,y) v t) = {((xe,ye),v)\<in> mapset_quadtree(t). \<not>(xe=x \<and>ye=y)} \<union> {((x,y), v)}"    
+  sorry
+    
+(*Tests*)  
+value "qinsert (0,0) 1 (qinsert (2,2) 3 (qinsert (1,3) 3 Leaf))"  
+value "list_quadtree (qinsert (0,0) 1 (qinsert (2,2) 3 (qinsert (1,3) 3 Leaf)))"
+value "delete (1,3) (qinsert (0,0) 1 (qinsert (2,2) 3 (qinsert (1,3) 3 Leaf)))"
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Erhard_Julian_ga48kog@mytum.de_655/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,2 @@
+Using temporary directory '/tmp/tmp.8G3jCZptOH'
+Exercise path '/home/admin/suites/exbeoriginal' not found
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Groer_Markus_markus.grosser@tum.de_636/Arbitrary_Precision.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,236 @@
+theory Arbitrary_Precision
+  imports Main
+begin
+
+text \<open>
+  Arbitrary precision arithmetic on lists of bits. Only multiplication and addition have been
+  implemented and proven.
+\<close>
+
+section \<open>Type Definition and Conversions\<close>
+
+type_synonym bitlist = "bool list"
+
+fun bitlist_of_nat :: "nat \<Rightarrow> bitlist" where
+  "bitlist_of_nat 0 = []"
+| "bitlist_of_nat n = odd n # bitlist_of_nat (n div 2)"
+
+fun nat_of_bitlist :: "bitlist \<Rightarrow> nat" where
+  "nat_of_bitlist [] = 0"
+| "nat_of_bitlist (b#bs) = (if b then 1 else 0) + 2 * nat_of_bitlist bs"
+
+section \<open>Optimality\<close>
+
+text \<open>
+  A bitlist is considered optimal if it has no leading zeroes.
+\<close>
+
+definition optimal :: "bitlist \<Rightarrow> bool" where
+  "optimal bl = (last bl \<or> bl = [])"
+
+lemma optimal_cons[simp]: "bs \<noteq> [] \<Longrightarrow> optimal (b#bs) = optimal bs"
+  unfolding optimal_def by simp
+
+lemma optimal_nat_of_bitlist_ne_zero: "\<lbrakk>optimal bs; bs \<noteq> []\<rbrakk> \<Longrightarrow> nat_of_bitlist bs \<noteq> 0"
+  by (induction bs; fastforce simp: optimal_def)
+
+lemma nat_of_bitlist_bitlist_of_nat[simp]: "nat_of_bitlist (bitlist_of_nat n) = n"
+proof (induction n rule: less_induct)
+  case (less x)
+  then show ?case by (cases x) auto
+qed
+
+lemma bitlist_of_nat_nat_of_bitlist[simp]: "optimal bl \<Longrightarrow> bitlist_of_nat (nat_of_bitlist bl) = bl"
+proof (induction bl)
+  case Nil
+  then show ?case by simp
+next
+  case (Cons b bs)
+  then show ?case proof (cases b)
+    case True
+    then have "optimal bs" using Cons unfolding optimal_def by auto
+    then show ?thesis using Cons True by auto
+  next
+    case False
+    then have "bs \<noteq> []" using Cons.prems unfolding optimal_def by auto
+    then have "nat_of_bitlist bs \<noteq> 0"
+      using Cons.prems by (simp add: optimal_nat_of_bitlist_ne_zero)
+    then have "2 * nat_of_bitlist bs \<noteq> 0" by simp
+    then have "\<exists>n. 2 * nat_of_bitlist bs = Suc n" by presburger
+    moreover have "\<not> odd (2 * nat_of_bitlist bs)" by simp
+    moreover have "(2 * nat_of_bitlist bs) div 2 = nat_of_bitlist bs" by simp
+    ultimately have
+      "bitlist_of_nat (2 * nat_of_bitlist bs) = False # bitlist_of_nat (nat_of_bitlist bs)"
+      by force
+    then show ?thesis using Cons False by (auto simp: \<open>bs \<noteq> []\<close>)
+  qed
+qed
+
+section \<open>Addition\<close>
+
+text \<open>
+  A full adder, as is commonly  implemented in digital logic:
+\<close>
+
+abbreviation full_adder :: "bool \<Rightarrow> bool \<Rightarrow> bool \<Rightarrow> bool * bool" where
+  "full_adder a b c \<equiv> (let ab = a \<noteq> b in ((ab \<noteq> c), (a \<and> b) \<or> (ab \<and> c)))"
+
+fun add_with_carry :: "bitlist \<Rightarrow> bitlist \<Rightarrow> bool \<Rightarrow> bitlist" where
+  "add_with_carry (a#as) (b#bs) c = (let (r, c') = full_adder a b c in r # add_with_carry as bs c')"
+| "add_with_carry (a#as) [] c = (a \<noteq> c) # add_with_carry as [] (a \<and> c)"
+| "add_with_carry [] (b#bs) c = (b \<noteq> c) # add_with_carry [] bs (b \<and> c)"
+| "add_with_carry [] [] c = (if c then [True] else [])"
+
+lemma add_with_carry_empty: "add_with_carry x y c = [] \<Longrightarrow> x = [] \<and> y = [] \<and> \<not>c"
+  by (induction x y c rule: add_with_carry.induct)
+    (auto simp: Let_def)
+
+lemma optimal_add_with_carry[simp]: "\<lbrakk>optimal x; optimal y\<rbrakk> \<Longrightarrow> optimal (add_with_carry x y c)"
+proof (induction x y c rule: add_with_carry.induct)
+  case (1 a as b bs c)
+  let ?r = "fst (full_adder a b c)"
+  let ?c' = "snd (full_adder a b c)"
+  show ?case proof (cases ?c')
+    case True
+    then have "add_with_carry as bs ?c' \<noteq> []" using add_with_carry_empty by meson
+    then show ?thesis
+      using 1 by (auto simp: optimal_def split: if_splits prod.splits)
+  next
+    case False
+    then show ?thesis
+      using 1 optimal_def apply (auto split: prod.splits)
+      using add_with_carry_empty(2)[of as bs False] by fastforce+
+  qed
+next
+  case (2 a as c)
+  then have "\<lbrakk>add_with_carry as [] (a \<and> c) = []; as = []\<rbrakk> \<Longrightarrow> optimal (add_with_carry (a # as) [] c)"
+    using optimal_def by force
+  then show ?case
+    using 2 neq_Nil_conv[of as] neq_Nil_conv[of "add_with_carry as [] (a \<and> c)"] optimal_cons
+    by auto
+next
+  case (3 b bs c)
+  then have "\<lbrakk>add_with_carry [] bs (b \<and> c) = []; bs = []\<rbrakk> \<Longrightarrow> optimal (add_with_carry [] (b # bs) c)"
+    using optimal_def by force
+  then show ?case
+    using 3 neq_Nil_conv[of bs] neq_Nil_conv[of "add_with_carry [] bs (b \<and> c)"] optimal_cons
+    by auto
+next
+  case (4 c)
+  then show ?case by (simp add: optimal_def)
+qed
+
+lemma nat_of_bitlist_add_with_carry[simp]: "nat_of_bitlist (add_with_carry x y c) = nat_of_bitlist x + nat_of_bitlist y + (if c then 1 else 0)"
+  by (induction x y c rule: add_with_carry.induct) auto
+
+definition add_bitlist :: "bitlist \<Rightarrow> bitlist \<Rightarrow> bitlist" where
+  "add_bitlist x y = add_with_carry x y False"
+
+lemma optimal_add_bitlist[simp]: "\<lbrakk>optimal x; optimal y\<rbrakk> \<Longrightarrow> optimal (add_bitlist x y)"
+  unfolding add_bitlist_def by simp
+
+lemma nat_of_bitlist_add_bitlist[simp]: "nat_of_bitlist (add_bitlist x y) = nat_of_bitlist x + nat_of_bitlist y"
+  unfolding add_bitlist_def by simp
+
+section \<open>Multiplication\<close>
+
+text \<open>
+  Naive \(\mathcal{O}(n²)\) implementation, with \(n\) being the number of bits. Since lists don't
+  allow fast random access, I am not even sure how much better Karatsuba or FFT multiplication would
+  fare.
+\<close>
+
+fun mult_bitlist :: "bitlist \<Rightarrow> bitlist \<Rightarrow> bitlist" where
+  "mult_bitlist (a#as) bs =
+  (let r = case mult_bitlist as bs of [] \<Rightarrow> [] | r \<Rightarrow> False # r in
+    if a then add_bitlist bs r else r)"
+| "mult_bitlist [] _ = []"
+
+lemma optimal_mult_bitlist[simp]: "\<lbrakk>optimal x; optimal y\<rbrakk> \<Longrightarrow> optimal (mult_bitlist x y)"
+proof (induction x)
+  case (Cons a as)
+  then have "optimal as" by (cases as) (auto simp: optimal_def)
+  then show ?case using Cons by (auto simp: Let_def split: list.splits)
+qed auto
+
+lemma nat_of_bitlist_mult_bitlist[simp]: "nat_of_bitlist (mult_bitlist x y) = nat_of_bitlist x * nat_of_bitlist y"
+  by (induction x) (auto split: list.splits)
+
+section \<open>Bitshifts\<close>
+
+fun shl_bitlist :: "bitlist \<Rightarrow> nat \<Rightarrow> bitlist" where
+  "shl_bitlist [] _ = []"
+| "shl_bitlist bl n = replicate n False @ bl"
+
+lemma optimal_shl_bitlist[simp]: "optimal x \<Longrightarrow> optimal (shl_bitlist x n)"
+  unfolding optimal_def by (cases x) auto
+
+lemma nat_of_bitlist_shl_bitlist[simp]: "nat_of_bitlist (shl_bitlist x n) = 2 ^ n * nat_of_bitlist x"
+  by (induction n; cases x) auto
+
+definition shr_bitlist :: "bitlist \<Rightarrow> nat \<Rightarrow> bitlist" where
+  "shr_bitlist bl n = drop n bl"
+
+lemma optimal_shr_bitlist[simp]: "optimal x \<Longrightarrow> optimal (shr_bitlist x n)"
+  unfolding shr_bitlist_def optimal_def by (cases x) auto
+
+lemma nat_of_bitlist_shr_bitlist[simp]: "nat_of_bitlist (shr_bitlist x n) = nat_of_bitlist x div 2 ^ n"
+  unfolding shr_bitlist_def proof (induction n arbitrary: x)
+  case (Suc n)
+  then show ?case by (cases x) (auto simp: algebra_simps Divides.div_mult2_eq)
+qed auto
+
+section \<open>Comparisons\<close>
+
+text \<open>
+  I am pretty sure this type is  already defined somewhere:
+\<close>
+
+datatype ordering = EQ | LT | GT
+
+fun cmp_bitlist :: "bitlist \<Rightarrow> bitlist \<Rightarrow> ordering" where
+  "cmp_bitlist [] [] = EQ"
+| "cmp_bitlist [] (_#_) = LT"
+| "cmp_bitlist (_#_) [] = GT"
+| "cmp_bitlist (a#as) (b#bs) =
+  (case cmp_bitlist as bs of
+    EQ \<Rightarrow> if a = b then EQ else if a then GT else LT
+  | r \<Rightarrow> r)"
+
+lemma cmp_bitlist_eq: "\<lbrakk>optimal x; optimal y\<rbrakk> \<Longrightarrow> cmp_bitlist x y = EQ \<longleftrightarrow> nat_of_bitlist x = nat_of_bitlist y"
+proof (induction x y rule: cmp_bitlist.induct)
+  case (4 a as b bs)
+  then show ?case by (auto split: ordering.splits)
+      (fastforce simp: optimal_def double_not_eq_Suc_double Suc_double_not_eq_double)+
+qed (fastforce dest: optimal_nat_of_bitlist_ne_zero)+
+
+lemma cmp_bitlist_lt: "\<lbrakk>optimal x; optimal y\<rbrakk> \<Longrightarrow> cmp_bitlist x y = LT \<longleftrightarrow> nat_of_bitlist x < nat_of_bitlist y"
+proof (induction x y rule: cmp_bitlist.induct)
+  case (4 a as b bs)
+  then show ?case
+    apply (cases a; cases b, auto split: ordering.splits)
+  proof goal_cases
+    case 7 then show ?case by (metis cmp_bitlist_eq lessI optimal_cons optimal_def)
+  next
+    case 9 then show ?case
+      by (metis Suc_1 cmp_bitlist_eq linorder_neqE_nat mult_strict_left_mono not_less_eq
+          optimal_cons optimal_def ordering.distinct(3) zero_less_Suc)
+  qed (fastforce simp: optimal_def)+ (* Dear god I hate myself for this proof *)
+qed (fastforce dest: optimal_nat_of_bitlist_ne_zero)+
+
+lemma cmp_bitlist_gt: "\<lbrakk>optimal x; optimal y\<rbrakk> \<Longrightarrow> cmp_bitlist x y = GT \<longleftrightarrow> nat_of_bitlist x > nat_of_bitlist y"
+proof (induction x y rule: cmp_bitlist.induct)
+  case (4 a as b bs)
+  then show ?case proof (auto split: ordering.splits, goal_cases)
+    case 2
+    then show ?case by (metis cmp_bitlist_eq lessI optimal_cons optimal_def)
+  next
+    case 6
+    then show ?case
+      by (metis cmp_bitlist_eq linorder_neqE_nat mult_strict_left_mono not_less_eq optimal_cons
+          optimal_def ordering.distinct(1) zero_less_numeral)
+  qed (fastforce simp: optimal_def)+ (* Same shit as above :/ *)
+qed (fastforce dest: optimal_nat_of_bitlist_ne_zero)+
+
+end
+
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Groer_Markus_markus.grosser@tum.de_636/user_error_log.txt	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,2 @@
+Using temporary directory '/tmp/tmp.ALSOLpXENs'
+Exercise path '/home/admin/suites/exbeoriginal' not found
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Exercises/hwsubm/OR/Haslbeck_Maximilian_max.haslbeck@mytum.de_640/Pell.thy	Mon Jul 31 09:34:31 2017 +0200
@@ -0,0 +1,933 @@
+(*\<Rightarrow>Manuel*)
+theory Pell
+  imports Analysis
+begin
+
+(*
+The equation
+x^2 + n * y^2 = 1
+has integer solutions in x and y for every non-square n.
+*)
+
+(*
+- Only works with isabelle-dev
+- should also work with Complex Main, but first needs some minor refinements
+*)
+
+(* Lemma by Manuel Eberl *)
+lemma nonneg_root_nat_or_irrat:
+  assumes "x ^ 2 = real a" and "x \<ge> 0"
+  shows   "x \<in> \<nat> \<or> x \<notin> \<rat>"
+proof safe
+  assume "x \<notin> \<nat>" and "x \<in> \<rat>"
+  from Rats_abs_nat_div_natE[OF this(2)]
+    obtain p q :: nat where q_nz [simp]: "q \<noteq> 0" and "abs x = p / q" and coprime: "coprime p q" .
+  with \<open>x \<ge> 0\<close> have x: "x = p / q"
+      by simp
+  with assms have "real (q ^ 2) * real a = real (p ^ 2)"
+    by (simp add: field_simps)
+  also have "real (q ^ 2) * real a = real (q ^ 2 * a)" 
+    by simp
+  finally have "p ^ 2 = q ^ 2 * a"
+    by (subst (asm) of_nat_eq_iff) auto
+  hence "q ^ 2 dvd p ^ 2" 
+    by simp
+  hence "q dvd p"
+    by (rule pow_divs_pow) auto
+  with coprime have "q = 1" 
+    by simp
+  with x and \<open>x \<notin> \<nat>\<close> show False
+    by simp
+qed
+
+(* Lemma by Manuel Eberl *)
+lemma minus_in_Ints_iff [simp]:
+  "-x \<in> \<int> \<longleftrightarrow> x \<in> \<int>"
+  using Ints_minus[of x] Ints_minus[of "-x"] by auto
+
+(* Lemma by Manuel Eberl *)
+lemma root_nat_or_irrat:
+  assumes "x ^ 2 = real a"
+  shows   "x \<in> \<int> \<or> x \<notin> \<rat>"
+proof (cases "x \<ge> 0")
+  case True
+  with nonneg_root_nat_or_irrat[OF assms this] 
+    show ?thesis by (auto simp: Nats_altdef2)
+next
+  case False
+  from assms have "(-x) ^ 2 = real a" 
+    by simp
+  moreover from False have "-x \<ge> 0" 
+    by simp
+  ultimately have "-x \<in> \<nat> \<or> -x \<notin> \<rat>"
+    by (rule nonneg_root_nat_or_irrat)
+  thus ?thesis 
+    by (auto simp: Nats_altdef2)
+qed
+
+lemma sqrt_nat_or_irrat:
+  "sqrt (real a) \<in> \<nat> \<or> sqrt (real a) \<notin> \<rat>"
+  using nonneg_root_nat_or_irrat[of "sqrt a" a] by auto
+
+lemma not_Rats_mult: fixes x y :: real
+  assumes "x \<noteq> 0" "x \<in> \<rat>"  "y \<notin> \<rat>"
+  shows "x * y \<notin> \<rat>"
+proof (rule ccontr)
+  assume 0: "\<not> x * y \<notin> \<rat>"
+  have "(x * y) / x \<in> \<rat>"
+    apply(rule Rats_divide)
+    using 0 assms by auto
+  also have "(x * y) / x = y"
+    using assms by(simp)
+  ultimately show False using assms by simp
+qed
+
+  
+lemma not_Rats_add: fixes x y :: real
+  assumes "x \<in> \<rat>"  "y \<notin> \<rat>"
+  shows "x + y \<notin> \<rat>" "y + x \<notin> \<rat>"
+  using assms Rats_diff by force+
+
+lemma not_Rats_diff: fixes x y :: real
+  assumes "x \<in> \<rat>"  "y \<notin> \<rat>"
+  shows "x - y \<notin> \<rat>" "y - x \<notin> \<rat>"
+  using Rats_diff assms Rats_add by force+
+
+lemma not_Rats_frac: fixes x :: real
+  shows "x \<in> \<rat> \<longleftrightarrow> frac x \<in> \<rat>"
+  apply(rule)
+    unfolding frac_def
+    apply simp
+    using Rats_of_int not_Rats_diff by blast 
+
+lemma pigeonhole: 
+  assumes "finite B" "card A > card B" "A \<subseteq> \<Union>B" 
+  shows "\<exists>x y M. x \<noteq> y \<and> x \<in> A \<and> y \<in> A \<and> M \<in> B \<and> x \<in> M \<and> y \<in> M"
+proof(rule ccontr)
+  assume "\<nexists>x y M. x \<noteq> y \<and> x \<in> A \<and> y \<in> A \<and> M \<in> B \<and> x \<in> M \<and> y \<in> M"
+  then have "\<And>x y M. x \<noteq> y \<Longrightarrow> x \<in> A \<Longrightarrow> y \<in> A \<Longrightarrow> M \<in> B \<Longrightarrow> x \<in> M \<Longrightarrow> y \<notin> M"
+    by blast
+  with assms show False
+  proof(induction "card B" arbitrary: A B)
+    case (Suc x)
+    then have "\<exists>b. b \<in> B"
+      by (metis Suc_n_not_le_n card.empty empty_iff subsetI subset_antisym zero_le)
+    then obtain b where "b \<in> B"
+      by blast
+    with Suc have 0: "card (B - {b}) = card B - 1"
+      by force
+    show ?case
+    proof(cases "A \<inter> b = {}")
+      case True
+      show ?thesis
+        apply(rule Suc(1)[of "B - {b}" A])
+        using 0 Suc apply(simp)
+        using Suc apply(simp)
+          apply(subst 0) using Suc apply(simp)
+        using Suc True apply(fast)
+        using Suc
+        by blast 
+    next
+      case False
+      then have "\<exists>a. a \<in> A \<and> a \<in> b"
+        by auto
+      then obtain a where "a \<in> A" "a \<in> b"
+        by blast
+      then have 3: "\<And>a'. a' \<in> A - {a} \<Longrightarrow> a' \<notin> b"
+        using Suc `b \<in> B` by blast
+      show ?thesis
+        apply(rule Suc(1)[of "B - {b}"  "A - {a}"])
+        using "0" Suc.hyps(2) apply linarith
+           apply (simp add: Suc.prems(1))
+          apply (metis "0" Suc.hyps(2) Suc.prems(2) Suc_lessD Suc_less_SucD \<open>a \<in> A\<close> card_Suc_Diff1 card_infinite diff_Suc_1 finite.emptyI finite.insertI finite_Diff2)
+         defer
+          using Suc.prems(4) apply auto[1]
+          using Suc(5) `a \<in> b` 3
+          by blast
+    qed
+  qed (auto)
+qed
+
+lemma split_that: fixes x y D p q::"'a::field"
+  shows "(x^2 - D * y^2) * (p^2 - D * q^2) = (x*p + D*y*q)^2 - D * (x*q + y*p)^2"
+  by (auto simp add: algebra_simps power2_sum power_mult_distrib semiring_normalization_rules(29))
+
+locale pell =
+  fixes d::real
+  assumes d_greater_zero: "0 < d" and
+          d_non_square: "\<nexists>x. x \<in> \<int> \<and> x ^ 2 = d" and
+          d_nat: "d \<in> \<nat>"
+begin
+
+lemma sqrt_d_not_int: "sqrt d \<notin> \<int>"
+  using d_non_square
+  using d_greater_zero less_eq_real_def real_sqrt_pow2 by blast
+    
+lemma sqrt_d_not_rat: "sqrt d \<notin> \<rat>"
+  by (metis Ints_of_nat Nats_cases d_nat sqrt_d_not_int sqrt_nat_or_irrat)
+
+lemma d_greater_eq_2: "d \<ge> 2"
+proof -
+  have "sqrt d \<noteq> 1"
+    using sqrt_d_not_int by force
+  then have "d \<noteq> 1"
+    by simp
+  show "d \<ge> 2"
+  apply(rule Nats_cases[OF d_nat])
+  using d_greater_zero `d \<noteq> 1` by auto
+qed
+
+lemma sqrt_d_greater_1: "sqrt d > 1"
+  using real_sqrt_gt_1_iff d_greater_eq_2 by simp
+ 
+lemma how_should_i_name_this_one:
+  assumes "(q::nat) > s" "(x::real) \<ge> 1"
+  shows "0 < \<lfloor>q * x\<rfloor> - \<lfloor>s * x\<rfloor>"
+proof -
+  have 0: "\<lfloor>s * x\<rfloor> \<le> s * x"
+    by simp
+  have "0 \<le> x - 1"
+    using assms by simp
+  also have "\<dots> \<le> (int q - int s) * x - 1"
+    using assms by fastforce
+  also have "\<dots> \<le> q * x - 1 - s * x"
+    by (simp add: left_diff_distrib')
+  also have "\<dots> \<le> q * x - 1 - \<lfloor>s * x\<rfloor>"
+    by force
+  also have "\<dots> < \<lfloor>q * x\<rfloor> - \<lfloor>s * x\<rfloor>"
+    by simp
+  finally show ?thesis
+    by simp
+qed
+
+lemma floor_int: "x \<in> \<int> \<longleftrightarrow> floor x = x"
+  by (metis (no_types, hide_lams) Ints_of_int add.inverse_inverse add_uminus_conv_diff 
+cancel_comm_monoid_add_class.diff_cancel floor_uminus_of_int 
+less_add_same_cancel1 not_le not_less_iff_gr_or_eq of_int_minus of_int_of_nat_eq of_nat_nat)
+
+lemma "x \<notin> \<int> \<longleftrightarrow> floor x < x"
+  using floor_int by force+
+
+lemma inj_real_of_int: "inj real_of_int"
+  apply(rule)
+  by simp
+    
+  
+lemma always_smaller:
+  fixes N::nat
+  assumes "N > 0"
+  shows "\<exists>t::int. \<exists>u::int. t > 0 \<and> u > 0 \<and> \<bar>t - u * sqrt d\<bar> < 1 / N \<and> 1 / N \<le> 1/\<bar>u\<bar>"
+proof -
+  define interval_N where "interval_N = (\<lambda>i. { i / N <..<  (i + 1) / N})"
+  define intervals_0_1 where "intervals_0_1 = interval_N ` {0..N - 1}"
+  have 0: "{0..1} - (\<lambda>x. x / N) ` {0..N} \<subseteq> \<Union> intervals_0_1"
+    unfolding intervals_0_1_def interval_N_def apply(clarsimp)
+  proof (goal_cases)
+    case (1 x)
+      note omei = 1
+    have x1: "x < 1"
+    proof(rule ccontr)
+      assume "\<not> x < 1"
+      with 1 have "x = 1"
+        by simp
+      then have "x = N / N"
+        using assms by simp
+      then have "x \<in> (\<lambda>x. real x / real N) ` {0..N}"
+        by fastforce
+      then show False
+        using 1 by simp
+    qed
+    have x0: "0 < x"
+    proof(rule ccontr)
+      assume "\<not> 0 < x"
+      with 1 have "x = 0"
+        by simp
+      then have "x = 0 / N"
+        using assms by simp
+      then have "x \<in> (\<lambda>x. real x / real N) ` {0..N}"
+        by fastforce
+      then show False
+        using 1 by simp
+    qed
+    from x1 x0 have f:  "floor (x * N) \<in> {0..N - Suc 0}"
+      apply(auto)
+      by (metis Groups.add_ac(2) Suc_pred assms le_floor_iff mult.left_neutral not_less 
+        of_int_of_nat_eq of_nat_0_less_iff real_mult_less_iff1 semiring_1_class.of_nat_simps(2) zle_add1_eq_le)
+    have "floor (x * N) \<le> x * N"
+      by simp
+    moreover have "floor (x * N) \<noteq> x * N"
+      proof(rule ccontr, goal_cases)
+        case 1
+        then have "\<exists>n. x * real N = real n"
+          by (metis \<open>\<lfloor>x * real N\<rfloor> \<in> {0..int (N - Suc 0)}\<close> atLeastAtMost_iff nonneg_int_cases of_int_of_nat_eq)
+        then obtain n where n_def: "x * real N = real n"
+          by blast
+        have "n \<le> N"
+          by (metis \<open>x * real N = real n\<close> linordered_semidom_class.of_nat_le_iff mult_left_le_one_le of_nat_0_le_iff omei(2) omei(3))
+        have "x = n / N"
+          using n_def assms
+          by (simp add: nonzero_eq_divide_eq) 
+        then have "x \<in> (\<lambda>x. real x / real N) ` {0..N}"
+          using `n \<le> N` n_def by force
+        then show ?case using omei by blast
+      qed
+      ultimately have "floor (x * N) < x * N"
+        by linarith
+      then have "(floor (x * N)) / N < x"
+        using assms
+        by (simp add: divide_less_eq) 
+      have "x * N < floor (x * N) + 1"
+        by simp
+      then have "x < (floor (x * N) + 1) / N"
+        using assms
+        by (metis nonzero_eq_divide_eq of_nat_0_less_iff order_less_irrefl pos_divide_less_eq)
+      have "floor (x * N) \<in> \<nat>"
+        unfolding Nats_altdef2 apply(auto)
+        apply (simp add: floor_int)
+        by (simp add: omei(2))
+      then have "\<exists>n. floor (x * N) = real n"
+        by (metis Nats_cases of_int_of_nat_eq)
+      then obtain n where n_def: "real n = floor (x * N)"
+        by fastforce
+      then have 3: "x < (real n + 1) / N"
+        using `x < (floor (x * N) + 1) / N` by (simp add: add.commute)
+      from n_def have 4:  "n \<in> {0..N - 1}"
+        using f by fastforce
+      have 5: "n / N < x"
+        using n_def `(floor (x * N)) / N < x` by simp
+      show ?case using 3 4 5
+          by auto
+  qed
+  have 1: "(\<lambda>x. frac (x * sqrt d)) ` {1..N+1} \<subseteq> \<Union> intervals_0_1"
+    apply(rule subset_trans[OF _ 0]) apply(rule) apply(rule)
+      apply(auto)[1]
+     apply (simp add: frac_lt_1 less_eq_real_def)
+    subgoal for x
+      apply(subgoal_tac "x \<notin> \<rat>")
+      subgoal apply(rule)
+          proof (goal_cases)
+            case 1
+            from 1(3) have "\<exists>n \<in> {0..N}. n / N = x"
+              by blast
+            show ?case
+              using "1"(2) Rats_divide Rats_of_nat \<open>\<exists>n\<in>{0..N}. real n / real N = x\<close> by blast
+          qed
+      apply(auto)
+      apply(subst (asm) not_Rats_frac[symmetric])
+      by (simp add: not_Rats_mult sqrt_d_not_rat)
+    done
+  have "card intervals_0_1 = N"
+    unfolding intervals_0_1_def interval_N_def
+    apply(subst card_image)
+    subgoal apply(rule) proof(auto, goal_cases)
+      case (1 x y)
+      have "Inf {real x / real N<..<(real x + 1) / real N} = real x / real N"
+        using `N > 0` by (auto intro!: cInf_greaterThanLessThan divide_strict_right_mono)
+      moreover have "Inf {real y / real N<..<(real y + 1) / real N} = real y / real N"
<