diff --git a/src/Doc/Prog_Prove/Basics.thy b/src/Doc/Prog_Prove/Basics.thy --- a/src/Doc/Prog_Prove/Basics.thy +++ b/src/Doc/Prog_Prove/Basics.thy @@ -1,155 +1,155 @@ (*<*) theory Basics imports Main begin (*>*) text\ This chapter introduces HOL as a functional programming language and shows how to prove properties of functional programs by induction. \section{Basics} \subsection{Types, Terms and Formulas} \label{sec:TypesTermsForms} HOL is a typed logic whose type system resembles that of functional programming languages. Thus there are \begin{description} \item[base types,] in particular \<^typ>\bool\, the type of truth values, \<^typ>\nat\, the type of natural numbers ($\mathbb{N}$), and \indexed{\<^typ>\int\}{int}, the type of mathematical integers ($\mathbb{Z}$). \item[type constructors,] in particular \list\, the type of lists, and \set\, the type of sets. Type constructors are written postfix, i.e., after their arguments. For example, \<^typ>\nat list\ is the type of lists whose elements are natural numbers. \item[function types,] denoted by \\\. \item[type variables,] denoted by \<^typ>\'a\, \<^typ>\'b\, etc., like in ML\@. \end{description} Note that \<^typ>\'a \ 'b list\ means \noquotes{@{typ[source]"'a \ ('b list)"}}, not \<^typ>\('a \ 'b) list\: postfix type constructors have precedence over \\\. \conceptidx{Terms}{term} are formed as in functional programming by applying functions to arguments. If \f\ is a function of type \\\<^sub>1 \ \\<^sub>2\ and \t\ is a term of type \\\<^sub>1\ then \<^term>\f t\ is a term of type \\\<^sub>2\. We write \t :: \\ to mean that term \t\ has type \\\. \begin{warn} There are many predefined infix symbols like \+\ and \\\. The name of the corresponding binary function is \<^term>\(+)\, not just \+\. That is, \<^term>\x + y\ is nice surface syntax (``syntactic sugar'') for \noquotes{@{term[source]"(+) x y"}}. \end{warn} HOL also supports some basic constructs from functional programming: \begin{quote} \(if b then t\<^sub>1 else t\<^sub>2)\\\ \(let x = t in u)\\\ \(case t of pat\<^sub>1 \ t\<^sub>1 | \ | pat\<^sub>n \ t\<^sub>n)\ \end{quote} \begin{warn} The above three constructs must always be enclosed in parentheses if they occur inside other constructs. \end{warn} Terms may also contain \\\-abstractions. For example, \<^term>\\x. x\ is the identity function. \conceptidx{Formulas}{formula} are terms of type \bool\. There are the basic constants \<^term>\True\ and \<^term>\False\ and the usual logical connectives (in decreasing order of precedence): \\\, \\\, \\\, \\\. \conceptidx{Equality}{equality} is available in the form of the infix function \=\ of type \<^typ>\'a \ 'a \ bool\. It also works for formulas, where it means ``if and only if''. \conceptidx{Quantifiers}{quantifier} are written \<^prop>\\x. P\ and \<^prop>\\x. P\. Isabelle automatically computes the type of each variable in a term. This is called \concept{type inference}. Despite type inference, it is sometimes necessary to attach an explicit \concept{type constraint} (or \concept{type annotation}) to a variable or term. The syntax is \t :: \\ as in \mbox{\noquotes{@{term[source] "m + (n::nat)"}}}. Type constraints may be needed to disambiguate terms involving overloaded functions such as \+\. Finally there are the universal quantifier \\\\index{$4@\isasymAnd} and the implication \\\\index{$3@\isasymLongrightarrow}. They are part of the Isabelle framework, not the logic HOL. Logically, they agree with their HOL counterparts \\\ and \\\, but operationally they behave differently. This will become clearer as we go along. \begin{warn} Right-arrows of all kinds always associate to the right. In particular, the formula \A\<^sub>1 \ A\<^sub>2 \ A\<^sub>3\ means \A\<^sub>1 \ (A\<^sub>2 \ A\<^sub>3)\. The (Isabelle-specific\footnote{To display implications in this style in Isabelle/jEdit you need to set Plugins $>$ Plugin Options $>$ Isabelle/General $>$ Print Mode to ``\texttt{brackets}'' and restart.}) notation \mbox{\\ A\<^sub>1; \; A\<^sub>n \ \ A\} is short for the iterated implication \mbox{\A\<^sub>1 \ \ \ A\<^sub>n \ A\}. Sometimes we also employ inference rule notation: \inferrule{\mbox{\A\<^sub>1\}\\ \mbox{\\\}\\ \mbox{\A\<^sub>n\}} {\mbox{\A\}} \end{warn} \subsection{Theories} \label{sec:Basic:Theories} Roughly speaking, a \concept{theory} is a named collection of types, functions, and theorems, much like a module in a programming language. All Isabelle text needs to go into a theory. The general format of a theory \T\ is \begin{quote} \indexed{\isacom{theory}}{theory} \T\\\ \indexed{\isacom{imports}}{imports} \T\<^sub>1 \ T\<^sub>n\\\ \isacom{begin}\\ \emph{definitions, theorems and proofs}\\ \isacom{end} \end{quote} where \T\<^sub>1 \ T\<^sub>n\ are the names of existing theories that \T\ is based on. The \T\<^sub>i\ are the direct \conceptidx{parent theories}{parent theory} of \T\. Everything defined in the parent theories (and their parents, recursively) is automatically visible. Each theory \T\ must reside in a \concept{theory file} named \T.thy\. \begin{warn} HOL contains a theory \<^theory>\Main\\index{Main@\<^theory>\Main\}, the union of all the basic predefined theories like arithmetic, lists, sets, etc. Unless you know what you are doing, always include \Main\ as a direct or indirect parent of all your theories. \end{warn} In addition to the theories that come with the Isabelle/HOL distribution (see \<^url>\https://isabelle.in.tum.de/library/HOL\) there is also the \emph{Archive of Formal Proofs} at \<^url>\https://isa-afp.org\, a growing collection of Isabelle theories that everybody can contribute to. \subsection{Quotation Marks} The textual definition of a theory follows a fixed syntax with keywords like -\isacommand{begin} and \isacommand{datatype}. Embedded in this syntax are +\isacom{begin} and \isacom{datatype}. Embedded in this syntax are the types and formulas of HOL. To distinguish the two levels, everything HOL-specific (terms and types) must be enclosed in quotation marks: \texttt{"}\dots\texttt{"}. Quotation marks around a single identifier can be dropped. When Isabelle prints a syntax error message, it refers to the HOL syntax as the \concept{inner syntax} and the enclosing theory language as the \concept{outer syntax}. \ifsem\else \subsection{Proof State} \begin{warn} By default Isabelle/jEdit does not show the proof state but this tutorial refers to it frequently. You should tick the ``Proof state'' box to see the proof state in the output window. \end{warn} \fi \ (*<*) end (*>*) diff --git a/src/Doc/Prog_Prove/Bool_nat_list.thy b/src/Doc/Prog_Prove/Bool_nat_list.thy --- a/src/Doc/Prog_Prove/Bool_nat_list.thy +++ b/src/Doc/Prog_Prove/Bool_nat_list.thy @@ -1,503 +1,503 @@ (*<*) theory Bool_nat_list imports Complex_Main begin (*>*) text\ \vspace{-4ex} \section{\texorpdfstring{Types \<^typ>\bool\, \<^typ>\nat\ and \list\}{Types bool, nat and list}} These are the most important predefined types. We go through them one by one. Based on examples we learn how to define (possibly recursive) functions and prove theorems about them by induction and simplification. \subsection{Type \indexed{\<^typ>\bool\}{bool}} The type of boolean values is a predefined datatype @{datatype[display] bool} with the two values \indexed{\<^const>\True\}{True} and \indexed{\<^const>\False\}{False} and with many predefined functions: \\\, \\\, \\\, \\\, etc. Here is how conjunction could be defined by pattern matching: \ fun conj :: "bool \ bool \ bool" where "conj True True = True" | "conj _ _ = False" text\Both the datatype and function definitions roughly follow the syntax of functional programming languages. \subsection{Type \indexed{\<^typ>\nat\}{nat}} Natural numbers are another predefined datatype: @{datatype[display] nat}\index{Suc@\<^const>\Suc\} All values of type \<^typ>\nat\ are generated by the constructors \0\ and \<^const>\Suc\. Thus the values of type \<^typ>\nat\ are \0\, \<^term>\Suc 0\, \<^term>\Suc(Suc 0)\, etc. There are many predefined functions: \+\, \*\, \\\, etc. Here is how you could define your own addition: \ fun add :: "nat \ nat \ nat" where "add 0 n = n" | "add (Suc m) n = Suc(add m n)" text\And here is a proof of the fact that \<^prop>\add m 0 = m\:\ lemma add_02: "add m 0 = m" apply(induction m) apply(auto) done (*<*) lemma "add m 0 = m" apply(induction m) (*>*) txt\The \isacom{lemma} command starts the proof and gives the lemma a name, \add_02\. Properties of recursively defined functions need to be established by induction in most cases. Command \isacom{apply}\(induction m)\ instructs Isabelle to start a proof by induction on \m\. In response, it will show the following proof state\ifsem\footnote{See page \pageref{proof-state} for how to display the proof state.}\fi: @{subgoals[display,indent=0]} The numbered lines are known as \emph{subgoals}. The first subgoal is the base case, the second one the induction step. The prefix \\m.\ is Isabelle's way of saying ``for an arbitrary but fixed \m\''. The \\\ separates assumptions from the conclusion. The command \isacom{apply}\(auto)\ instructs Isabelle to try and prove all subgoals automatically, essentially by simplifying them. Because both subgoals are easy, Isabelle can do it. The base case \<^prop>\add 0 0 = 0\ holds by definition of \<^const>\add\, and the induction step is almost as simple: \add\<^latex>\~\(Suc m) 0 = Suc(add m 0) = Suc m\ using first the definition of \<^const>\add\ and then the induction hypothesis. In summary, both subproofs rely on simplification with function definitions and the induction hypothesis. As a result of that final \isacom{done}, Isabelle associates the lemma just proved with its name. You can now inspect the lemma with the command \ thm add_02 txt\which displays @{thm[show_question_marks,display] add_02} The free variable \m\ has been replaced by the \concept{unknown} \?m\. There is no logical difference between the two but there is an operational one: unknowns can be instantiated, which is what you want after some lemma has been proved. Note that there is also a proof method \induct\, which behaves almost like \induction\; the difference is explained in \autoref{ch:Isar}. \begin{warn} Terminology: We use \concept{lemma}, \concept{theorem} and \concept{rule} interchangeably for propositions that have been proved. \end{warn} \begin{warn} Numerals (\0\, \1\, \2\, \dots) and most of the standard arithmetic operations (\+\, \-\, \*\, \\\, \<\, etc.) are overloaded: they are available not just for natural numbers but for other types as well. For example, given the goal \x + 0 = x\, there is nothing to indicate that you are talking about natural numbers. Hence Isabelle can only infer that \<^term>\x\ is of some arbitrary type where \0\ and \+\ exist. As a consequence, you will be unable to prove the goal. % To alert you to such pitfalls, Isabelle flags numerals without a % fixed type in its output: @ {prop"x+0 = x"}. In this particular example, you need to include an explicit type constraint, for example \x+0 = (x::nat)\. If there is enough contextual information this may not be necessary: \<^prop>\Suc x = x\ automatically implies \x::nat\ because \<^term>\Suc\ is not overloaded. \end{warn} \subsubsection{An Informal Proof} Above we gave some terse informal explanation of the proof of \<^prop>\add m 0 = m\. A more detailed informal exposition of the lemma might look like this: \bigskip \noindent \textbf{Lemma} \<^prop>\add m 0 = m\ \noindent \textbf{Proof} by induction on \m\. \begin{itemize} \item Case \0\ (the base case): \<^prop>\add 0 0 = 0\ holds by definition of \<^const>\add\. \item Case \<^term>\Suc m\ (the induction step): We assume \<^prop>\add m 0 = m\, the induction hypothesis (IH), and we need to show \add (Suc m) 0 = Suc m\. The proof is as follows:\smallskip \begin{tabular}{@ {}rcl@ {\quad}l@ {}} \<^term>\add (Suc m) 0\ &\=\& \<^term>\Suc(add m 0)\ & by definition of \add\\\ &\=\& \<^term>\Suc m\ & by IH \end{tabular} \end{itemize} Throughout this book, \concept{IH} will stand for ``induction hypothesis''. We have now seen three proofs of \<^prop>\add m 0 = 0\: the Isabelle one, the terse four lines explaining the base case and the induction step, and just now a model of a traditional inductive proof. The three proofs differ in the level of detail given and the intended reader: the Isabelle proof is for the machine, the informal proofs are for humans. Although this book concentrates on Isabelle proofs, it is important to be able to rephrase those proofs as informal text comprehensible to a reader familiar with traditional mathematical proofs. Later on we will introduce an Isabelle proof language that is closer to traditional informal mathematical language and is often directly readable. \subsection{Type \indexed{\list\}{list}} Although lists are already predefined, we define our own copy for demonstration purposes: \ (*<*) apply(auto) done declare [[names_short]] (*>*) datatype 'a list = Nil | Cons 'a "'a list" (*<*) for map: map (*>*) text\ \begin{itemize} \item Type \<^typ>\'a list\ is the type of lists over elements of type \<^typ>\'a\. Because \<^typ>\'a\ is a type variable, lists are in fact \concept{polymorphic}: the elements of a list can be of arbitrary type (but must all be of the same type). \item Lists have two constructors: \<^const>\Nil\, the empty list, and \<^const>\Cons\, which puts an element (of type \<^typ>\'a\) in front of a list (of type \<^typ>\'a list\). Hence all lists are of the form \<^const>\Nil\, or \<^term>\Cons x Nil\, or \<^term>\Cons x (Cons y Nil)\, etc. \item \isacom{datatype} requires no quotation marks on the left-hand side, but on the right-hand side each of the argument types of a constructor needs to be enclosed in quotation marks, unless it is just an identifier (e.g., \<^typ>\nat\ or \<^typ>\'a\). \end{itemize} We also define two standard functions, append and reverse:\ fun app :: "'a list \ 'a list \ 'a list" where "app Nil ys = ys" | "app (Cons x xs) ys = Cons x (app xs ys)" fun rev :: "'a list \ 'a list" where "rev Nil = Nil" | "rev (Cons x xs) = app (rev xs) (Cons x Nil)" text\By default, variables \xs\, \ys\ and \zs\ are of \list\ type. -Command \indexed{\isacommand{value}}{value} evaluates a term. For example,\ +Command \indexed{\isacom{value}}{value} evaluates a term. For example,\ value "rev(Cons True (Cons False Nil))" text\yields the result \<^value>\rev(Cons True (Cons False Nil))\. This works symbolically, too:\ value "rev(Cons a (Cons b Nil))" text\yields \<^value>\rev(Cons a (Cons b Nil))\. \medskip Figure~\ref{fig:MyList} shows the theory created so far. Because \list\, \<^const>\Nil\, \<^const>\Cons\, etc.\ are already predefined, Isabelle prints qualified (long) names when executing this theory, for example, \MyList.Nil\ instead of \<^const>\Nil\. To suppress the qualified names you can insert the command \texttt{declare [[names\_short]]}. This is not recommended in general but is convenient for this unusual example. % Notice where the %quotations marks are needed that we mostly sweep under the carpet. In %particular, notice that \isacom{datatype} requires no quotation marks on the %left-hand side, but that on the right-hand side each of the argument %types of a constructor needs to be enclosed in quotation marks. \begin{figure}[htbp] \begin{alltt} \input{MyList.thy}\end{alltt} \caption{A theory of lists} \label{fig:MyList} \index{comment} \end{figure} \subsubsection{Structural Induction for Lists} Just as for natural numbers, there is a proof principle of induction for lists. Induction over a list is essentially induction over the length of the list, although the length remains implicit. To prove that some property \P\ holds for all lists \xs\, i.e., \mbox{\<^prop>\P(xs)\}, you need to prove \begin{enumerate} \item the base case \<^prop>\P(Nil)\ and \item the inductive case \<^prop>\P(Cons x xs)\ under the assumption \<^prop>\P(xs)\, for some arbitrary but fixed \x\ and \xs\. \end{enumerate} This is often called \concept{structural induction} for lists. \subsection{The Proof Process} We will now demonstrate the typical proof process, which involves the formulation and proof of auxiliary lemmas. Our goal is to show that reversing a list twice produces the original list.\ theorem rev_rev [simp]: "rev(rev xs) = xs" txt\Commands \isacom{theorem} and \isacom{lemma} are interchangeable and merely indicate the importance we attach to a proposition. Via the bracketed attribute \simp\ we also tell Isabelle to make the eventual theorem a \conceptnoidx{simplification rule}: future proofs involving simplification will replace occurrences of \<^term>\rev(rev xs)\ by \<^term>\xs\. The proof is by induction:\ apply(induction xs) txt\ As explained above, we obtain two subgoals, namely the base case (\<^const>\Nil\) and the induction step (\<^const>\Cons\): @{subgoals[display,indent=0,margin=65]} Let us try to solve both goals automatically: \ apply(auto) txt\Subgoal~1 is proved, and disappears; the simplified version of subgoal~2 becomes the new subgoal~1: @{subgoals[display,indent=0,margin=70]} In order to simplify this subgoal further, a lemma suggests itself. \subsubsection{A First Lemma} We insert the following lemma in front of the main theorem: \ (*<*) oops (*>*) lemma rev_app [simp]: "rev(app xs ys) = app (rev ys) (rev xs)" txt\There are two variables that we could induct on: \xs\ and \ys\. Because \<^const>\app\ is defined by recursion on the first argument, \xs\ is the correct one: \ apply(induction xs) txt\This time not even the base case is solved automatically:\ apply(auto) txt\ \vspace{-5ex} @{subgoals[display,goals_limit=1]} Again, we need to abandon this proof attempt and prove another simple lemma first. \subsubsection{A Second Lemma} We again try the canonical proof procedure: \ (*<*) oops (*>*) lemma app_Nil2 [simp]: "app xs Nil = xs" apply(induction xs) apply(auto) done text\ Thankfully, this worked. Now we can continue with our stuck proof attempt of the first lemma: \ lemma rev_app [simp]: "rev(app xs ys) = app (rev ys) (rev xs)" apply(induction xs) apply(auto) txt\ We find that this time \auto\ solves the base case, but the induction step merely simplifies to @{subgoals[display,indent=0,goals_limit=1]} The missing lemma is associativity of \<^const>\app\, which we insert in front of the failed lemma \rev_app\. \subsubsection{Associativity of \<^const>\app\} The canonical proof procedure succeeds without further ado: \ (*<*)oops(*>*) lemma app_assoc [simp]: "app (app xs ys) zs = app xs (app ys zs)" apply(induction xs) apply(auto) done (*<*) lemma rev_app [simp]: "rev(app xs ys) = app (rev ys)(rev xs)" apply(induction xs) apply(auto) done theorem rev_rev [simp]: "rev(rev xs) = xs" apply(induction xs) apply(auto) done (*>*) text\ Finally the proofs of @{thm[source] rev_app} and @{thm[source] rev_rev} succeed, too. \subsubsection{Another Informal Proof} Here is the informal proof of associativity of \<^const>\app\ corresponding to the Isabelle proof above. \bigskip \noindent \textbf{Lemma} \<^prop>\app (app xs ys) zs = app xs (app ys zs)\ \noindent \textbf{Proof} by induction on \xs\. \begin{itemize} \item Case \Nil\: \ \<^prop>\app (app Nil ys) zs = app ys zs\ \=\ \mbox{\<^term>\app Nil (app ys zs)\} \ holds by definition of \app\. \item Case \Cons x xs\: We assume \begin{center} \hfill \<^term>\app (app xs ys) zs\ \=\ \<^term>\app xs (app ys zs)\ \hfill (IH) \end{center} and we need to show \begin{center} \<^prop>\app (app (Cons x xs) ys) zs = app (Cons x xs) (app ys zs)\.\end{center} The proof is as follows:\smallskip \begin{tabular}{@ {}l@ {\quad}l@ {}} \<^term>\app (app (Cons x xs) ys) zs\\\ \= app (Cons x (app xs ys)) zs\ & by definition of \app\\\ \= Cons x (app (app xs ys) zs)\ & by definition of \app\\\ \= Cons x (app xs (app ys zs))\ & by IH\\ \= app (Cons x xs) (app ys zs)\ & by definition of \app\ \end{tabular} \end{itemize} \medskip \noindent Didn't we say earlier that all proofs are by simplification? But in both cases, going from left to right, the last equality step is not a simplification at all! In the base case it is \<^prop>\app ys zs = app Nil (app ys zs)\. It appears almost mysterious because we suddenly complicate the term by appending \Nil\ on the left. What is really going on is this: when proving some equality \mbox{\<^prop>\s = t\}, both \s\ and \t\ are simplified until they ``meet in the middle''. This heuristic for equality proofs works well for a functional programming context like ours. In the base case both \<^term>\app (app Nil ys) zs\ and \<^term>\app Nil (app ys zs)\ are simplified to \<^term>\app ys zs\, the term in the middle. \subsection{Predefined Lists} \label{sec:predeflists} Isabelle's predefined lists are the same as the ones above, but with more syntactic sugar: \begin{itemize} \item \[]\ is \indexed{\<^const>\Nil\}{Nil}, \item \<^term>\x # xs\ is \<^term>\Cons x xs\\index{Cons@\<^const>\Cons\}, \item \[x\<^sub>1, \, x\<^sub>n]\ is \x\<^sub>1 # \ # x\<^sub>n # []\, and \item \<^term>\xs @ ys\ is \<^term>\app xs ys\. \end{itemize} There is also a large library of predefined functions. The most important ones are the length function \length :: 'a list \ nat\\index{length@\<^const>\length\} (with the obvious definition), and the \indexed{\<^const>\map\}{map} function that applies a function to all elements of a list: \begin{isabelle} \isacom{fun} \<^const>\map\ \::\ @{typ[source] "('a \ 'b) \ 'a list \ 'b list"} \isacom{where}\\ \"\@{thm list.map(1) [of f]}\" |\\\ \"\@{thm list.map(2) [of f x xs]}\"\ \end{isabelle} \ifsem Also useful are the \concept{head} of a list, its first element, and the \concept{tail}, the rest of the list: \begin{isabelle}\index{hd@\<^const>\hd\} \isacom{fun} \hd :: 'a list \ 'a\\\ \<^prop>\hd(x#xs) = x\ \end{isabelle} \begin{isabelle}\index{tl@\<^const>\tl\} \isacom{fun} \tl :: 'a list \ 'a list\\\ \<^prop>\tl [] = []\ \|\\\ \<^prop>\tl(x#xs) = xs\ \end{isabelle} Note that since HOL is a logic of total functions, \<^term>\hd []\ is defined, but we do not know what the result is. That is, \<^term>\hd []\ is not undefined but underdefined. \fi % From now on lists are always the predefined lists. \ifsem\else \subsection{Types \<^typ>\int\ and \<^typ>\real\} In addition to \<^typ>\nat\ there are also the types \<^typ>\int\ and \<^typ>\real\, the mathematical integers and real numbers. As mentioned above, numerals and most of the standard arithmetic operations are overloaded. In particular they are defined on \<^typ>\int\ and \<^typ>\real\. \begin{warn} There are two infix exponentiation operators: \<^term>\(^)\ for \<^typ>\nat\ and \<^typ>\int\ (with exponent of type \<^typ>\nat\ in both cases) and \<^term>\(powr)\ for \<^typ>\real\. \end{warn} \begin{warn} Type \<^typ>\int\ is already part of theory \<^theory>\Main\, but in order to use \<^typ>\real\ as well, you have to import theory \<^theory>\Complex_Main\ instead of \<^theory>\Main\. \end{warn} There are three coercion functions that are inclusions and do not lose information: \begin{quote} \begin{tabular}{rcl} \<^const>\int\ &\::\& \<^typ>\nat \ int\\\ \<^const>\real\ &\::\& \<^typ>\nat \ real\\\ \<^const>\real_of_int\ &\::\& \<^typ>\int \ real\\\ \end{tabular} \end{quote} Isabelle inserts these inclusions automatically once you import \Complex_Main\. If there are multiple type-correct completions, Isabelle chooses an arbitrary one. For example, the input \noquotes{@{term[source] "(i::int) + (n::nat)"}} has the unique type-correct completion \<^term>\(i::int) + int(n::nat)\. In contrast, \noquotes{@{term[source] "((n::nat) + n) :: real"}} has two type-correct completions, \noquotes{@{term[source]"real(n+n)"}} and \noquotes{@{term[source]"real n + real n"}}. There are also the coercion functions in the other direction: \begin{quote} \begin{tabular}{rcl} \<^const>\nat\ &\::\& \<^typ>\int \ nat\\\ \<^const>\floor\ &\::\& \<^typ>\real \ int\\\ \<^const>\ceiling\ &\::\& \<^typ>\real \ int\\\ \end{tabular} \end{quote} \fi \subsection*{Exercises} \begin{exercise} Use the \isacom{value} command to evaluate the following expressions: @{term[source] "1 + (2::nat)"}, @{term[source] "1 + (2::int)"}, @{term[source] "1 - (2::nat)"} and @{term[source] "1 - (2::int)"}. \end{exercise} \begin{exercise} Start from the definition of \<^const>\add\ given above. Prove that \<^const>\add\ is associative and commutative. Define a recursive function \double\ \::\ \<^typ>\nat \ nat\ and prove \<^prop>\double m = add m m\. \end{exercise} \begin{exercise} Define a function \count ::\ \<^typ>\'a \ 'a list \ nat\ that counts the number of occurrences of an element in a list. Prove \<^prop>\count x xs \ length xs\. \end{exercise} \begin{exercise} Define a recursive function \snoc ::\ \<^typ>\'a list \ 'a \ 'a list\ that appends an element to the end of a list. With the help of \snoc\ define a recursive function \reverse ::\ \<^typ>\'a list \ 'a list\ that reverses a list. Prove \<^prop>\reverse(reverse xs) = xs\. \end{exercise} \begin{exercise} Define a recursive function \sum_upto ::\ \<^typ>\nat \ nat\ such that \mbox{\sum_upto n\} \=\ \0 + ... + n\ and prove \<^prop>\ sum_upto (n::nat) = n * (n+1) div 2\. \end{exercise} \ (*<*) end (*>*) diff --git a/src/Doc/Prog_Prove/Isar.thy b/src/Doc/Prog_Prove/Isar.thy --- a/src/Doc/Prog_Prove/Isar.thy +++ b/src/Doc/Prog_Prove/Isar.thy @@ -1,1242 +1,1242 @@ (*<*) theory Isar imports LaTeXsugar begin declare [[quick_and_dirty]] (*>*) text\ Apply-scripts are unreadable and hard to maintain. The language of choice for larger proofs is \concept{Isar}. The two key features of Isar are: \begin{itemize} \item It is structured, not linear. \item It is readable without its being run because you need to state what you are proving at any given point. \end{itemize} Whereas apply-scripts are like assembly language programs, Isar proofs are like structured programs with comments. A typical Isar proof looks like this: \text\ \begin{tabular}{@ {}l} \isacom{proof}\\ \quad\isacom{assume} \"\$\mathit{formula}_0$\"\\\ \quad\isacom{have} \"\$\mathit{formula}_1$\"\ \quad\isacom{by} \simp\\\ \quad\vdots\\ \quad\isacom{have} \"\$\mathit{formula}_n$\"\ \quad\isacom{by} \blast\\\ \quad\isacom{show} \"\$\mathit{formula}_{n+1}$\"\ \quad\isacom{by} \\\\\ \isacom{qed} \end{tabular} \text\ It proves $\mathit{formula}_0 \Longrightarrow \mathit{formula}_{n+1}$ (provided each proof step succeeds). The intermediate \isacom{have} statements are merely stepping stones on the way towards the \isacom{show} statement that proves the actual goal. In more detail, this is the Isar core syntax: \medskip \begin{tabular}{@ {}lcl@ {}} \textit{proof} &=& \indexed{\isacom{by}}{by} \textit{method}\\ &$\mid$& \indexed{\isacom{proof}}{proof} [\textit{method}] \ \textit{step}$^*$ \ \indexed{\isacom{qed}}{qed} \end{tabular} \medskip \begin{tabular}{@ {}lcl@ {}} \textit{step} &=& \indexed{\isacom{fix}}{fix} \textit{variables} \\ &$\mid$& \indexed{\isacom{assume}}{assume} \textit{proposition} \\ &$\mid$& [\indexed{\isacom{from}}{from} \textit{fact}$^+$] (\indexed{\isacom{have}}{have} $\mid$ \indexed{\isacom{show}}{show}) \ \textit{proposition} \ \textit{proof} \end{tabular} \medskip \begin{tabular}{@ {}lcl@ {}} \textit{proposition} &=& [\textit{name}:] \"\\textit{formula}\"\ \end{tabular} \medskip \begin{tabular}{@ {}lcl@ {}} \textit{fact} &=& \textit{name} \ $\mid$ \ \dots \end{tabular} \medskip \noindent A proof can either be an atomic \isacom{by} with a single proof method which must finish off the statement being proved, for example \auto\, or it can be a \isacom{proof}--\isacom{qed} block of multiple steps. Such a block can optionally begin with a proof method that indicates how to start off the proof, e.g., \mbox{\(induction xs)\}. A step either assumes a proposition or states a proposition together with its proof. The optional \isacom{from} clause indicates which facts are to be used in the proof. Intermediate propositions are stated with \isacom{have}, the overall goal is stated with \isacom{show}. A step can also introduce new local variables with \isacom{fix}. Logically, \isacom{fix} introduces \\\-quantified variables, \isacom{assume} introduces the assumption of an implication (\\\) and \isacom{have}/\isacom{show} introduce the conclusion. Propositions are optionally named formulas. These names can be referred to in later \isacom{from} clauses. In the simplest case, a fact is such a name. But facts can also be composed with \OF\ and \of\ as shown in \autoref{sec:forward-proof} --- hence the \dots\ in the above grammar. Note that assumptions, intermediate \isacom{have} statements and global lemmas all have the same status and are thus collectively referred to as \conceptidx{facts}{fact}. Fact names can stand for whole lists of facts. For example, if \f\ is defined by command \isacom{fun}, \f.simps\ refers to the whole list of recursion equations defining \f\. Individual facts can be selected by writing \f.simps(2)\, whole sublists by writing \f.simps(2-4)\. \section{Isar by Example} We show a number of proofs of Cantor's theorem that a function from a set to its powerset cannot be surjective, illustrating various features of Isar. The constant \<^const>\surj\ is predefined. \ lemma "\ surj(f :: 'a \ 'a set)" proof assume 0: "surj f" from 0 have 1: "\A. \a. A = f a" by(simp add: surj_def) from 1 have 2: "\a. {x. x \ f x} = f a" by blast from 2 show "False" by blast qed text\ The \isacom{proof} command lacks an explicit method by which to perform the proof. In such cases Isabelle tries to use some standard introduction rule, in the above case for \\\: \[ \inferrule{ \mbox{@{thm (prem 1) notI}}} {\mbox{@{thm (concl) notI}}} \] In order to prove \<^prop>\~ P\, assume \P\ and show \False\. Thus we may assume \mbox{\noquotes{@{prop [source] "surj f"}}}. The proof shows that names of propositions may be (single!) digits --- meaningful names are hard to invent and are often not necessary. Both \isacom{have} steps are obvious. The second one introduces the diagonal set \<^term>\{x. x \ f x}\, the key idea in the proof. If you wonder why \2\ directly implies \False\: from \2\ it follows that \<^prop>\a \ f a \ a \ f a\. \subsection{\indexed{\this\}{this}, \indexed{\isacom{then}}{then}, \indexed{\isacom{hence}}{hence} and \indexed{\isacom{thus}}{thus}} Labels should be avoided. They interrupt the flow of the reader who has to scan the context for the point where the label was introduced. Ideally, the proof is a linear flow, where the output of one step becomes the input of the next step, piping the previously proved fact into the next proof, like in a UNIX pipe. In such cases the predefined name \this\ can be used to refer to the proposition proved in the previous step. This allows us to eliminate all labels from our proof (we suppress the \isacom{lemma} statement): \ (*<*) lemma "\ surj(f :: 'a \ 'a set)" (*>*) proof assume "surj f" from this have "\a. {x. x \ f x} = f a" by(auto simp: surj_def) from this show "False" by blast qed text\We have also taken the opportunity to compress the two \isacom{have} steps into one. To compact the text further, Isar has a few convenient abbreviations: \medskip \begin{tabular}{r@ {\quad=\quad}l} \isacom{then} & \isacom{from} \this\\\ \isacom{thus} & \isacom{then} \isacom{show}\\ \isacom{hence} & \isacom{then} \isacom{have} \end{tabular} \medskip \noindent With the help of these abbreviations the proof becomes \ (*<*) lemma "\ surj(f :: 'a \ 'a set)" (*>*) proof assume "surj f" hence "\a. {x. x \ f x} = f a" by(auto simp: surj_def) thus "False" by blast qed text\ There are two further linguistic variations: \medskip \begin{tabular}{r@ {\quad=\quad}l} (\isacom{have}$\mid$\isacom{show}) \ \textit{prop} \ \indexed{\isacom{using}}{using} \ \textit{facts} & \isacom{from} \ \textit{facts} \ (\isacom{have}$\mid$\isacom{show}) \ \textit{prop}\\ \indexed{\isacom{with}}{with} \ \textit{facts} & \isacom{from} \ \textit{facts} \isa{this} \end{tabular} \medskip \noindent The \isacom{using} idiom de-emphasizes the used facts by moving them behind the proposition. \subsection{Structured Lemma Statements: \indexed{\isacom{fixes}}{fixes}, \indexed{\isacom{assumes}}{assumes}, \indexed{\isacom{shows}}{shows}} \index{lemma@\isacom{lemma}} Lemmas can also be stated in a more structured fashion. To demonstrate this feature with Cantor's theorem, we rephrase \noquotes{@{prop[source]"\ surj f"}} a little: \ lemma fixes f :: "'a \ 'a set" assumes s: "surj f" shows "False" txt\The optional \isacom{fixes} part allows you to state the types of variables up front rather than by decorating one of their occurrences in the formula with a type constraint. The key advantage of the structured format is the \isacom{assumes} part that allows you to name each assumption; multiple assumptions can be separated by \isacom{and}. The \isacom{shows} part gives the goal. The actual theorem that will come out of the proof is \noquotes{@{prop[source]"surj f \ False"}}, but during the proof the assumption \noquotes{@{prop[source]"surj f"}} is available under the name \s\ like any other fact. \ proof - have "\ a. {x. x \ f x} = f a" using s by(auto simp: surj_def) thus "False" by blast qed text\ \begin{warn} Note the hyphen after the \isacom{proof} command. It is the null method that does nothing to the goal. Leaving it out would be asking Isabelle to try some suitable introduction rule on the goal \<^const>\False\ --- but there is no such rule and \isacom{proof} would fail. \end{warn} In the \isacom{have} step the assumption \noquotes{@{prop[source]"surj f"}} is now referenced by its name \s\. The duplication of \noquotes{@{prop[source]"surj f"}} in the above proofs (once in the statement of the lemma, once in its proof) has been eliminated. Stating a lemma with \isacom{assumes}-\isacom{shows} implicitly introduces the name \indexed{\assms\}{assms} that stands for the list of all assumptions. You can refer to individual assumptions by \assms(1)\, \assms(2)\, etc., thus obviating the need to name them individually. \section{Proof Patterns} We show a number of important basic proof patterns. Many of them arise from the rules of natural deduction that are applied by \isacom{proof} by default. The patterns are phrased in terms of \isacom{show} but work for \isacom{have} and \isacom{lemma}, too. \ifsem\else \subsection{Logic} \fi We start with two forms of \concept{case analysis}: starting from a formula \P\ we have the two cases \P\ and \<^prop>\~P\, and starting from a fact \<^prop>\P \ Q\ we have the two cases \P\ and \Q\: \text_raw\ \begin{tabular}{@ {}ll@ {}} \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "R" proof-(*>*) show "R" proof cases assume "P" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "R" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ next assume "\ P" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "R" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)oops(*>*) text_raw \} \end{minipage}\index{cases@\cases\} & \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "R" proof-(*>*) have "P \ Q" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ then show "R" proof assume "P" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "R" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ next assume "Q" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "R" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)oops(*>*) text_raw \} \end{minipage} \end{tabular} \medskip \begin{isamarkuptext}% How to prove a logical equivalence: \end{isamarkuptext}% \isa{% \ (*<*)lemma "P\Q" proof-(*>*) show "P \ Q" proof assume "P" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "Q" (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ next assume "Q" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "P" (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ qed(*<*)qed(*>*) text_raw \} \medskip \begin{isamarkuptext}% Proofs by contradiction (@{thm[source] ccontr} stands for ``classical contradiction''): \end{isamarkuptext}% \begin{tabular}{@ {}ll@ {}} \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "\ P" proof-(*>*) show "\ P" proof assume "P" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "False" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)oops(*>*) text_raw \} \end{minipage} & \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "P" proof-(*>*) show "P" proof (rule ccontr) assume "\P" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "False" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)oops(*>*) text_raw \} \end{minipage} \end{tabular} \medskip \begin{isamarkuptext}% How to prove quantified formulas: \end{isamarkuptext}% \begin{tabular}{@ {}ll@ {}} \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "\x. P x" proof-(*>*) show "\x. P(x)" proof fix x text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "P(x)" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)oops(*>*) text_raw \} \end{minipage} & \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "\x. P(x)" proof-(*>*) show "\x. P(x)" proof text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "P(witness)" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed (*<*)oops(*>*) text_raw \} \end{minipage} \end{tabular} \medskip \begin{isamarkuptext}% In the proof of \noquotes{@{prop[source]"\x. P(x)"}}, the step \indexed{\isacom{fix}}{fix}~\x\ introduces a locally fixed variable \x\ into the subproof, the proverbial ``arbitrary but fixed value''. Instead of \x\ we could have chosen any name in the subproof. In the proof of \noquotes{@{prop[source]"\x. P(x)"}}, \witness\ is some arbitrary term for which we can prove that it satisfies \P\. How to reason forward from \noquotes{@{prop[source] "\x. P(x)"}}: \end{isamarkuptext}% \ (*<*)lemma True proof- assume 1: "\x. P x"(*>*) have "\x. P(x)" (*<*)by(rule 1)(*>*)text_raw\\ \isasymproof\\\ then obtain x where p: "P(x)" by blast (*<*)oops(*>*) text\ After the \indexed{\isacom{obtain}}{obtain} step, \x\ (we could have chosen any name) is a fixed local variable, and \p\ is the name of the fact \noquotes{@{prop[source] "P(x)"}}. This pattern works for one or more \x\. As an example of the \isacom{obtain} command, here is the proof of Cantor's theorem in more detail: \ lemma "\ surj(f :: 'a \ 'a set)" proof assume "surj f" hence "\a. {x. x \ f x} = f a" by(auto simp: surj_def) then obtain a where "{x. x \ f x} = f a" by blast hence "a \ f a \ a \ f a" by blast thus "False" by blast qed text_raw\ \begin{isamarkuptext}% Finally, how to prove set equality and subset relationship: \end{isamarkuptext}% \begin{tabular}{@ {}ll@ {}} \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "A = (B::'a set)" proof-(*>*) show "A = B" proof show "A \ B" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ next show "B \ A" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)qed(*>*) text_raw \} \end{minipage} & \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "A <= (B::'a set)" proof-(*>*) show "A \ B" proof fix x assume "x \ A" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "x \ B" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)qed(*>*) text_raw \} \end{minipage} \end{tabular} \begin{isamarkuptext}% \ifsem\else \subsection{Chains of (In)Equations} In textbooks, chains of equations (and inequations) are often displayed like this: \begin{quote} \begin{tabular}{@ {}l@ {\qquad}l@ {}} $t_1 = t_2$ & \isamath{\,\langle\mathit{justification}\rangle}\\ $\phantom{t_1} = t_3$ & \isamath{\,\langle\mathit{justification}\rangle}\\ \quad $\vdots$\\ $\phantom{t_1} = t_n$ & \isamath{\,\langle\mathit{justification}\rangle} \end{tabular} \end{quote} The Isar equivalent is this: \begin{samepage} \begin{quote} -\isakeyword{have} \"t\<^sub>1 = t\<^sub>2"\ \isasymproof\\ -\isakeyword{also have} \"... = t\<^sub>3"\ \isasymproof\\ +\isacom{have} \"t\<^sub>1 = t\<^sub>2"\ \isasymproof\\ +\isacom{also have} \"... = t\<^sub>3"\ \isasymproof\\ \quad $\vdots$\\ -\isakeyword{also have} \"... = t\<^sub>n"\ \isasymproof \\ -\isakeyword{finally show} \"t\<^sub>1 = t\<^sub>n"\\ \texttt{.} +\isacom{also have} \"... = t\<^sub>n"\ \isasymproof \\ +\isacom{finally show} \"t\<^sub>1 = t\<^sub>n"\\ \texttt{.} \end{quote} \end{samepage} \noindent The ``\...\'' and ``\.\'' deserve some explanation: \begin{description} \item[``\...\''] is literally three dots. It is the name of an unknown that Isar automatically instantiates with the right-hand side of the previous equation. In general, if \this\ is the theorem \<^term>\p t\<^sub>1 t\<^sub>2\ then ``\...\'' stands for \t\<^sub>2\. \item[``\.\''] (a single dot) is a proof method that solves a goal by one of the -assumptions. This works here because the result of \isakeyword{finally} +assumptions. This works here because the result of \isacom{finally} is the theorem \mbox{\t\<^sub>1 = t\<^sub>n\}, -\isakeyword{show} \"t\<^sub>1 = t\<^sub>n"\ states the theorem explicitly, -and ``\.\'' proves the theorem with the result of \isakeyword{finally}. +\isacom{show} \"t\<^sub>1 = t\<^sub>n"\ states the theorem explicitly, +and ``\.\'' proves the theorem with the result of \isacom{finally}. \end{description} The above proof template also works for arbitrary mixtures of \=\, \\\ and \<\, for example: \begin{quote} -\isakeyword{have} \"t\<^sub>1 < t\<^sub>2"\ \isasymproof\\ -\isakeyword{also have} \"... = t\<^sub>3"\ \isasymproof\\ +\isacom{have} \"t\<^sub>1 < t\<^sub>2"\ \isasymproof\\ +\isacom{also have} \"... = t\<^sub>3"\ \isasymproof\\ \quad $\vdots$\\ -\isakeyword{also have} \"... \ t\<^sub>n"\ \isasymproof \\ -\isakeyword{finally show} \"t\<^sub>1 < t\<^sub>n"\\ \texttt{.} +\isacom{also have} \"... \ t\<^sub>n"\ \isasymproof \\ +\isacom{finally show} \"t\<^sub>1 < t\<^sub>n"\\ \texttt{.} \end{quote} -The relation symbol in the \isakeyword{finally} step needs to be the most precise one +The relation symbol in the \isacom{finally} step needs to be the most precise one possible. In the example above, you must not write \t\<^sub>1 \ t\<^sub>n\ instead of \mbox{\t\<^sub>1 < t\<^sub>n\}. \begin{warn} Isabelle only supports \=\, \\\ and \<\ but not \\\ and \>\ in (in)equation chains (by default). \end{warn} If you want to go beyond merely using the above proof patterns and want to -understand what \isakeyword{also} and \isakeyword{finally} mean, read on. +understand what \isacom{also} and \isacom{finally} mean, read on. There is an Isar theorem variable called \calculation\, similar to \this\. -When the first \isakeyword{also} in a chain is encountered, Isabelle sets -\calculation := this\. In each subsequent \isakeyword{also} step, +When the first \isacom{also} in a chain is encountered, Isabelle sets +\calculation := this\. In each subsequent \isacom{also} step, Isabelle composes the theorems \calculation\ and \this\ (i.e.\ the two previous (in)equalities) using some predefined set of rules including transitivity of \=\, \\\ and \<\ but also mixed rules like \<^prop>\\ x \ y; y < z \ \ x < z\. The result of this composition is assigned to \calculation\. Consider \begin{quote} -\isakeyword{have} \"t\<^sub>1 \ t\<^sub>2"\ \isasymproof\\ -\isakeyword{also} \isakeyword{have} \"... < t\<^sub>3"\ \isasymproof\\ -\isakeyword{also} \isakeyword{have} \"... = t\<^sub>4"\ \isasymproof\\ -\isakeyword{finally show} \"t\<^sub>1 < t\<^sub>4"\\ \texttt{.} +\isacom{have} \"t\<^sub>1 \ t\<^sub>2"\ \isasymproof\\ +\isacom{also} \isacom{have} \"... < t\<^sub>3"\ \isasymproof\\ +\isacom{also} \isacom{have} \"... = t\<^sub>4"\ \isasymproof\\ +\isacom{finally show} \"t\<^sub>1 < t\<^sub>4"\\ \texttt{.} \end{quote} -After the first \isakeyword{also}, \calculation\ is \"t\<^sub>1 \ t\<^sub>2"\, -and after the second \isakeyword{also}, \calculation\ is \"t\<^sub>1 < t\<^sub>3"\. -The command \isakeyword{finally} is short for \isakeyword{also from} \calculation\. -Therefore the \isakeyword{also} hidden in \isakeyword{finally} sets \calculation\ +After the first \isacom{also}, \calculation\ is \"t\<^sub>1 \ t\<^sub>2"\, +and after the second \isacom{also}, \calculation\ is \"t\<^sub>1 < t\<^sub>3"\. +The command \isacom{finally} is short for \isacom{also from} \calculation\. +Therefore the \isacom{also} hidden in \isacom{finally} sets \calculation\ to \t\<^sub>1 < t\<^sub>4\ and the final ``\texttt{.}'' succeeds. For more information on this style of proof see @{cite "BauerW-TPHOLs01"}. \fi \section{Streamlining Proofs} \subsection{Pattern Matching and Quotations} In the proof patterns shown above, formulas are often duplicated. This can make the text harder to read, write and maintain. Pattern matching is an abbreviation mechanism to avoid such duplication. Writing \begin{quote} \isacom{show} \ \textit{formula} \(\\indexed{\isacom{is}}{is} \textit{pattern}\)\ \end{quote} matches the pattern against the formula, thus instantiating the unknowns in the pattern for later use. As an example, consider the proof pattern for \\\: \end{isamarkuptext}% \ (*<*)lemma "formula\<^sub>1 \ formula\<^sub>2" proof-(*>*) show "formula\<^sub>1 \ formula\<^sub>2" (is "?L \ ?R") proof assume "?L" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "?R" (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ next assume "?R" text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show "?L" (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ qed(*<*)qed(*>*) text\Instead of duplicating \formula\<^sub>i\ in the text, we introduce the two abbreviations \?L\ and \?R\ by pattern matching. Pattern matching works wherever a formula is stated, in particular with \isacom{have} and \isacom{lemma}. The unknown \indexed{\?thesis\}{thesis} is implicitly matched against any goal stated by \isacom{lemma} or \isacom{show}. Here is a typical example:\ lemma "formula" proof - text_raw\\\\mbox{}\quad$\vdots$\\\mbox{}\hspace{-1.4ex}\ show ?thesis (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ qed text\ Unknowns can also be instantiated with \indexed{\isacom{let}}{let} commands \begin{quote} \isacom{let} \?t\ = \"\\textit{some-big-term}\"\ \end{quote} Later proof steps can refer to \?t\: \begin{quote} \isacom{have} \"\\dots \?t\ \dots\"\ \end{quote} \begin{warn} Names of facts are introduced with \name:\ and refer to proved theorems. Unknowns \?X\ refer to terms or formulas. \end{warn} Although abbreviations shorten the text, the reader needs to remember what they stand for. Similarly for names of facts. Names like \1\, \2\ and \3\ are not helpful and should only be used in short proofs. For longer proofs, descriptive names are better. But look at this example: \begin{quote} \isacom{have} \ \x_gr_0: "x > 0"\\\ $\vdots$\\ \isacom{from} \x_gr_0\ \dots \end{quote} The name is longer than the fact it stands for! Short facts do not need names; one can refer to them easily by quoting them: \begin{quote} \isacom{have} \ \"x > 0"\\\ $\vdots$\\ \isacom{from} \`x>0`\ \dots\index{$IMP053@\`...`\} \end{quote} Note that the quotes around \x>0\ are \conceptnoidx{back quotes}. They refer to the fact not by name but by value. \subsection{\indexed{\isacom{moreover}}{moreover}} \index{ultimately@\isacom{ultimately}} Sometimes one needs a number of facts to enable some deduction. Of course one can name these facts individually, as shown on the right, but one can also combine them with \isacom{moreover}, as shown on the left: \text_raw\ \begin{tabular}{@ {}ll@ {}} \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "P" proof-(*>*) have "P\<^sub>1" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ moreover have "P\<^sub>2" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ moreover text_raw\\\$\vdots$\\\hspace{-1.4ex}\(*<*)have "True" ..(*>*) moreover have "P\<^sub>n" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ ultimately have "P" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ (*<*)oops(*>*) text_raw \} \end{minipage} & \qquad \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "P" proof-(*>*) have lab\<^sub>1: "P\<^sub>1" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ have lab\<^sub>2: "P\<^sub>2" (*<*)sorry(*>*)text_raw\\ \isasymproof\ text_raw\\\$\vdots$\\\hspace{-1.4ex}\ have lab\<^sub>n: "P\<^sub>n" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ from lab\<^sub>1 lab\<^sub>2 text_raw\\ $\dots$\\\ have "P" (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ (*<*)oops(*>*) text_raw \} \end{minipage} \end{tabular} \begin{isamarkuptext}% The \isacom{moreover} version is no shorter but expresses the structure a bit more clearly and avoids new names. \subsection{Local Lemmas} Sometimes one would like to prove some lemma locally within a proof, a lemma that shares the current context of assumptions but that has its own assumptions and is generalized over its locally fixed variables at the end. This is simply an extension of the basic \indexed{\isacom{have}}{have} construct: \begin{quote} \indexed{\isacom{have}}{have} \B\\ \indexed{\isacom{if}}{if} \name:\ \A\<^sub>1 \ A\<^sub>m\\ \indexed{\isacom{for}}{for} \x\<^sub>1 \ x\<^sub>n\\\ \isasymproof \end{quote} proves \\ A\<^sub>1; \ ; A\<^sub>m \ \ B\ where all \x\<^sub>i\ have been replaced by unknowns \?x\<^sub>i\. As an example we prove a simple fact about divisibility on integers. The definition of \dvd\ is @{thm dvd_def}. \end{isamarkuptext}% \ lemma fixes a b :: int assumes "b dvd (a+b)" shows "b dvd a" proof - have "\k'. a = b*k'" if asm: "a+b = b*k" for k proof show "a = b*(k - 1)" using asm by(simp add: algebra_simps) qed then show ?thesis using assms by(auto simp add: dvd_def) qed text\ \subsection*{Exercises} \exercise Give a readable, structured proof of the following lemma: \ lemma assumes T: "\x y. T x y \ T y x" and A: "\x y. A x y \ A y x \ x = y" and TA: "\x y. T x y \ A x y" and "A x y" shows "T x y" (*<*)oops(*>*) text\ \endexercise \exercise Give a readable, structured proof of the following lemma: \ lemma "\ys zs. xs = ys @ zs \ (length ys = length zs \ length ys = length zs + 1)" (*<*)oops(*>*) text\ Hint: There are predefined functions @{const_typ take} and @{const_typ drop} such that \take k [x\<^sub>1,\] = [x\<^sub>1,\,x\<^sub>k]\ and \drop k [x\<^sub>1,\] = [x\<^bsub>k+1\<^esub>,\]\. Let sledgehammer find and apply the relevant \<^const>\take\ and \<^const>\drop\ lemmas for you. \endexercise \section{Case Analysis and Induction} \subsection{Datatype Case Analysis} \index{case analysis|(} We have seen case analysis on formulas. Now we want to distinguish which form some term takes: is it \0\ or of the form \<^term>\Suc n\, is it \<^term>\[]\ or of the form \<^term>\x#xs\, etc. Here is a typical example proof by case analysis on the form of \xs\: \ lemma "length(tl xs) = length xs - 1" proof (cases xs) assume "xs = []" thus ?thesis by simp next fix y ys assume "xs = y#ys" thus ?thesis by simp qed text\\index{cases@\cases\|(}Function \tl\ (''tail'') is defined by @{thm list.sel(2)} and @{thm list.sel(3)}. Note that the result type of \<^const>\length\ is \<^typ>\nat\ and \<^prop>\0 - 1 = (0::nat)\. This proof pattern works for any term \t\ whose type is a datatype. The goal has to be proved for each constructor \C\: \begin{quote} \isacom{fix} \ \x\<^sub>1 \ x\<^sub>n\ \isacom{assume} \"t = C x\<^sub>1 \ x\<^sub>n"\ \end{quote}\index{case@\isacom{case}|(} Each case can be written in a more compact form by means of the \isacom{case} command: \begin{quote} \isacom{case} \(C x\<^sub>1 \ x\<^sub>n)\ \end{quote} This is equivalent to the explicit \isacom{fix}-\isacom{assume} line but also gives the assumption \"t = C x\<^sub>1 \ x\<^sub>n"\ a name: \C\, like the constructor. Here is the \isacom{case} version of the proof above: \ (*<*)lemma "length(tl xs) = length xs - 1"(*>*) proof (cases xs) case Nil thus ?thesis by simp next case (Cons y ys) thus ?thesis by simp qed text\Remember that \Nil\ and \Cons\ are the alphanumeric names for \[]\ and \#\. The names of the assumptions are not used because they are directly piped (via \isacom{thus}) into the proof of the claim. \index{case analysis|)} \subsection{Structural Induction} \index{induction|(} \index{structural induction|(} We illustrate structural induction with an example based on natural numbers: the sum (\\\) of the first \n\ natural numbers (\{0..n::nat}\) is equal to \mbox{\<^term>\n*(n+1) div 2::nat\}. Never mind the details, just focus on the pattern: \ lemma "\{0..n::nat} = n*(n+1) div 2" proof (induction n) show "\{0..0::nat} = 0*(0+1) div 2" by simp next fix n assume "\{0..n::nat} = n*(n+1) div 2" thus "\{0..Suc n} = Suc n*(Suc n+1) div 2" by simp qed text\Except for the rewrite steps, everything is explicitly given. This makes the proof easily readable, but the duplication means it is tedious to write and maintain. Here is how pattern matching can completely avoid any duplication:\ lemma "\{0..n::nat} = n*(n+1) div 2" (is "?P n") proof (induction n) show "?P 0" by simp next fix n assume "?P n" thus "?P(Suc n)" by simp qed text\The first line introduces an abbreviation \?P n\ for the goal. Pattern matching \?P n\ with the goal instantiates \?P\ to the function \<^term>\\n. \{0..n::nat} = n*(n+1) div 2\. Now the proposition to be proved in the base case can be written as \?P 0\, the induction hypothesis as \?P n\, and the conclusion of the induction step as \?P(Suc n)\. Induction also provides the \isacom{case} idiom that abbreviates the \isacom{fix}-\isacom{assume} step. The above proof becomes \ (*<*)lemma "\{0..n::nat} = n*(n+1) div 2"(*>*) proof (induction n) case 0 show ?case by simp next case (Suc n) thus ?case by simp qed text\ The unknown \?case\\index{case?@\?case\|(} is set in each case to the required claim, i.e., \?P 0\ and \mbox{\?P(Suc n)\} in the above proof, without requiring the user to define a \?P\. The general pattern for induction over \<^typ>\nat\ is shown on the left-hand side: \text_raw\ \begin{tabular}{@ {}ll@ {}} \begin{minipage}[t]{.4\textwidth} \isa{% \ (*<*)lemma "P(n::nat)" proof -(*>*) show "P(n)" proof (induction n) case 0 text_raw\\\\mbox{}\ \ $\vdots$\\\mbox{}\hspace{-1ex}\ show ?case (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ next case (Suc n) text_raw\\\\mbox{}\ \ $\vdots$\\\mbox{}\hspace{-1ex}\ show ?case (*<*)sorry(*>*) text_raw\\ \isasymproof\\\ qed(*<*)qed(*>*) text_raw \} \end{minipage} & \begin{minipage}[t]{.4\textwidth} ~\\ ~\\ \isacom{let} \?case = "P(0)"\\\ ~\\ ~\\ ~\\[1ex] \isacom{fix} \n\ \isacom{assume} \Suc: "P(n)"\\\ \isacom{let} \?case = "P(Suc n)"\\\ \end{minipage} \end{tabular} \medskip \ text\ On the right side you can see what the \isacom{case} command on the left stands for. In case the goal is an implication, induction does one more thing: the proposition to be proved in each case is not the whole implication but only its conclusion; the premises of the implication are immediately made assumptions of that case. That is, if in the above proof we replace \isacom{show}~\"P(n)"\ by \mbox{\isacom{show}~\"A(n) \ P(n)"\} then \isacom{case}~\0\ stands for \begin{quote} \isacom{assume} \ \0: "A(0)"\\\ \isacom{let} \?case = "P(0)"\ \end{quote} and \isacom{case}~\(Suc n)\ stands for \begin{quote} \isacom{fix} \n\\\ \isacom{assume} \Suc:\ \begin{tabular}[t]{l}\"A(n) \ P(n)"\\\\"A(Suc n)"\\end{tabular}\\ \isacom{let} \?case = "P(Suc n)"\ \end{quote} The list of assumptions \Suc\ is actually subdivided into \Suc.IH\, the induction hypotheses (here \A(n) \ P(n)\), and \Suc.prems\, the premises of the goal being proved (here \A(Suc n)\). Induction works for any datatype. Proving a goal \\ A\<^sub>1(x); \; A\<^sub>k(x) \ \ P(x)\ by induction on \x\ generates a proof obligation for each constructor \C\ of the datatype. The command \isacom{case}~\(C x\<^sub>1 \ x\<^sub>n)\ performs the following steps: \begin{enumerate} \item \isacom{fix} \x\<^sub>1 \ x\<^sub>n\ \item \isacom{assume} the induction hypotheses (calling them \C.IH\\index{IH@\.IH\}) and the premises \mbox{\A\<^sub>i(C x\<^sub>1 \ x\<^sub>n)\} (calling them \C.prems\\index{prems@\.prems\}) and calling the whole list \C\ \item \isacom{let} \?case = "P(C x\<^sub>1 \ x\<^sub>n)"\ \end{enumerate} \index{structural induction|)} \ifsem\else \subsection{Computation Induction} \index{rule induction} In \autoref{sec:recursive-funs} we introduced computation induction and its realization in Isabelle: the definition of a recursive function \f\ via \isacom{fun} proves the corresponding computation induction rule called \f.induct\. Induction with this rule looks like in \autoref{sec:recursive-funs}, but now with \isacom{proof} instead of \isacom{apply}: \begin{quote} \isacom{proof} (\induction x\<^sub>1 \ x\<^sub>k rule: f.induct\) \end{quote} Just as for structural induction, this creates several cases, one for each defining equation for \f\. By default (if the equations have not been named by the user), the cases are numbered. That is, they are started by \begin{quote} \isacom{case} (\i x y ...\) \end{quote} where \i = 1,...,n\, \n\ is the number of equations defining \f\, and \x y ...\ are the variables in equation \i\. Note the following: \begin{itemize} \item Although \i\ is an Isar name, \i.IH\ (or similar) is not. You need double quotes: "\i.IH\". When indexing the name, write "\i.IH\"(1), not "\i.IH\(1)". \item If defining equations for \f\ overlap, \isacom{fun} instantiates them to make them nonoverlapping. This means that one user-provided equation may lead to several equations and thus to several cases in the induction rule. These have names of the form "\i_j\", where \i\ is the number of the original equation and the system-generated \j\ indicates the subcase. \end{itemize} In Isabelle/jEdit, the \induction\ proof method displays a proof skeleton with all \isacom{case}s. This is particularly useful for computation induction and the following rule induction. \fi \subsection{Rule Induction} \index{rule induction|(} Recall the inductive and recursive definitions of even numbers in \autoref{sec:inductive-defs}: \ inductive ev :: "nat \ bool" where ev0: "ev 0" | evSS: "ev n \ ev(Suc(Suc n))" fun evn :: "nat \ bool" where "evn 0 = True" | "evn (Suc 0) = False" | "evn (Suc(Suc n)) = evn n" text\We recast the proof of \<^prop>\ev n \ evn n\ in Isar. The left column shows the actual proof text, the right column shows the implicit effect of the two \isacom{case} commands:\text_raw\ \begin{tabular}{@ {}l@ {\qquad}l@ {}} \begin{minipage}[t]{.5\textwidth} \isa{% \ lemma "ev n \ evn n" proof(induction rule: ev.induct) case ev0 show ?case by simp next case evSS thus ?case by simp qed text_raw \} \end{minipage} & \begin{minipage}[t]{.5\textwidth} ~\\ ~\\ \isacom{let} \?case = "evn 0"\\\ ~\\ ~\\ \isacom{fix} \n\\\ \isacom{assume} \evSS:\ \begin{tabular}[t]{l} \"ev n"\\\\"evn n"\\end{tabular}\\ \isacom{let} \?case = "evn(Suc(Suc n))"\\\ \end{minipage} \end{tabular} \medskip \ text\ The proof resembles structural induction, but the induction rule is given explicitly and the names of the cases are the names of the rules in the inductive definition. Let us examine the two assumptions named @{thm[source]evSS}: \<^prop>\ev n\ is the premise of rule @{thm[source]evSS}, which we may assume because we are in the case where that rule was used; \<^prop>\evn n\ is the induction hypothesis. \begin{warn} Because each \isacom{case} command introduces a list of assumptions named like the case name, which is the name of a rule of the inductive definition, those rules now need to be accessed with a qualified name, here @{thm[source] ev.ev0} and @{thm[source] ev.evSS}. \end{warn} In the case @{thm[source]evSS} of the proof above we have pretended that the system fixes a variable \n\. But unless the user provides the name \n\, the system will just invent its own name that cannot be referred to. In the above proof, we do not need to refer to it, hence we do not give it a specific name. In case one needs to refer to it one writes \begin{quote} \isacom{case} \(evSS m)\ \end{quote} like \isacom{case}~\(Suc n)\ in earlier structural inductions. The name \m\ is an arbitrary choice. As a result, case @{thm[source] evSS} is derived from a renamed version of rule @{thm[source] evSS}: \ev m \ ev(Suc(Suc m))\. Here is an example with a (contrived) intermediate step that refers to \m\: \ lemma "ev n \ evn n" proof(induction rule: ev.induct) case ev0 show ?case by simp next case (evSS m) have "evn(Suc(Suc m)) = evn m" by simp - thus ?case using \evn m\ by blast + thus ?case using `evn m` by blast qed text\ \indent In general, let \I\ be a (for simplicity unary) inductively defined predicate and let the rules in the definition of \I\ be called \rule\<^sub>1\, \dots, \rule\<^sub>n\. A proof by rule induction follows this pattern:\index{inductionrule@\induction ... rule:\} \ (*<*) inductive I where rule\<^sub>1: "I()" | rule\<^sub>2: "I()" | rule\<^sub>n: "I()" lemma "I x \ P x" proof-(*>*) show "I x \ P x" proof(induction rule: I.induct) case rule\<^sub>1 text_raw\\\[-.4ex]\mbox{}\ \ $\vdots$\\[-.4ex]\mbox{}\hspace{-1ex}\ show ?case (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ next text_raw\\\[-.4ex]$\vdots$\\[-.4ex]\mbox{}\hspace{-1ex}\ (*<*) case rule\<^sub>2 show ?case sorry (*>*) next case rule\<^sub>n text_raw\\\[-.4ex]\mbox{}\ \ $\vdots$\\[-.4ex]\mbox{}\hspace{-1ex}\ show ?case (*<*)sorry(*>*)text_raw\\ \isasymproof\\\ qed(*<*)qed(*>*) text\ One can provide explicit variable names by writing \isacom{case}~\(rule\<^sub>i x\<^sub>1 \ x\<^sub>k)\, thus renaming the first \k\ free variables in rule \i\ to \x\<^sub>1 \ x\<^sub>k\, going through rule \i\ from left to right. \subsection{Assumption Naming} \label{sec:assm-naming} In any induction, \isacom{case}~\name\ sets up a list of assumptions also called \name\, which is subdivided into three parts: \begin{description} \item[\name.IH\]\index{IH@\.IH\} contains the induction hypotheses. \item[\name.hyps\]\index{hyps@\.hyps\} contains all the other hypotheses of this case in the induction rule. For rule inductions these are the hypotheses of rule \name\, for structural inductions these are empty. \item[\name.prems\]\index{prems@\.prems\} contains the (suitably instantiated) premises of the statement being proved, i.e., the \A\<^sub>i\ when proving \\ A\<^sub>1; \; A\<^sub>n \ \ A\. \end{description} \begin{warn} Proof method \induct\ differs from \induction\ only in this naming policy: \induct\ does not distinguish \IH\ from \hyps\ but subsumes \IH\ under \hyps\. \end{warn} More complicated inductive proofs than the ones we have seen so far often need to refer to specific assumptions --- just \name\ or even \name.prems\ and \name.IH\ can be too unspecific. This is where the indexing of fact lists comes in handy, e.g., \name.IH(2)\ or \name.prems(1-2)\. \subsection{Rule Inversion} \label{sec:rule-inversion} \index{rule inversion|(} Rule inversion is case analysis of which rule could have been used to derive some fact. The name \conceptnoidx{rule inversion} emphasizes that we are reasoning backwards: by which rules could some given fact have been proved? For the inductive definition of \<^const>\ev\, rule inversion can be summarized like this: @{prop[display]"ev n \ n = 0 \ (\k. n = Suc(Suc k) \ ev k)"} The realisation in Isabelle is a case analysis. A simple example is the proof that \<^prop>\ev n \ ev (n - 2)\. We already went through the details informally in \autoref{sec:Logic:even}. This is the Isar proof: \ (*<*) notepad begin fix n (*>*) assume "ev n" from this have "ev(n - 2)" proof cases case ev0 thus "ev(n - 2)" by (simp add: ev.ev0) next case (evSS k) thus "ev(n - 2)" by (simp add: ev.evSS) qed (*<*) end (*>*) text\The key point here is that a case analysis over some inductively defined predicate is triggered by piping the given fact (here: \isacom{from}~\this\) into a proof by \cases\. Let us examine the assumptions available in each case. In case \ev0\ we have \n = 0\ and in case \evSS\ we have \<^prop>\n = Suc(Suc k)\ and \<^prop>\ev k\. In each case the assumptions are available under the name of the case; there is no fine-grained naming schema like there is for induction. Sometimes some rules could not have been used to derive the given fact because constructors clash. As an extreme example consider rule inversion applied to \<^prop>\ev(Suc 0)\: neither rule \ev0\ nor rule \evSS\ can yield \<^prop>\ev(Suc 0)\ because \Suc 0\ unifies neither with \0\ nor with \<^term>\Suc(Suc n)\. Impossible cases do not have to be proved. Hence we can prove anything from \<^prop>\ev(Suc 0)\: \ (*<*) notepad begin fix P (*>*) assume "ev(Suc 0)" then have P by cases (*<*) end (*>*) text\That is, \<^prop>\ev(Suc 0)\ is simply not provable:\ lemma "\ ev(Suc 0)" proof assume "ev(Suc 0)" then show False by cases qed text\Normally not all cases will be impossible. As a simple exercise, prove that \mbox{\<^prop>\\ ev(Suc(Suc(Suc 0)))\.} \subsection{Advanced Rule Induction} \label{sec:advanced-rule-induction} So far, rule induction was always applied to goals of the form \I x y z \ \\ where \I\ is some inductively defined predicate and \x\, \y\, \z\ are variables. In some rare situations one needs to deal with an assumption where not all arguments \r\, \s\, \t\ are variables: \begin{isabelle} \isacom{lemma} \"I r s t \ \"\ \end{isabelle} Applying the standard form of rule induction in such a situation will lead to strange and typically unprovable goals. We can easily reduce this situation to the standard one by introducing new variables \x\, \y\, \z\ and reformulating the goal like this: \begin{isabelle} \isacom{lemma} \"I x y z \ x = r \ y = s \ z = t \ \"\ \end{isabelle} Standard rule induction will work fine now, provided the free variables in \r\, \s\, \t\ are generalized via \arbitrary\. However, induction can do the above transformation for us, behind the curtains, so we never need to see the expanded version of the lemma. This is what we need to write: \begin{isabelle} \isacom{lemma} \"I r s t \ \"\\isanewline \isacom{proof}\(induction "r" "s" "t" arbitrary: \ rule: I.induct)\\index{inductionrule@\induction ... rule:\}\index{arbitrary@\arbitrary:\} \end{isabelle} Like for rule inversion, cases that are impossible because of constructor clashes will not show up at all. Here is a concrete example:\ lemma "ev (Suc m) \ \ ev m" proof(induction "Suc m" arbitrary: m rule: ev.induct) fix n assume IH: "\m. n = Suc m \ \ ev m" show "\ ev (Suc n)" proof \ \contradiction\ assume "ev(Suc n)" thus False proof cases \ \rule inversion\ fix k assume "n = Suc k" "ev k" thus False using IH by auto qed qed qed text\ Remarks: \begin{itemize} \item Instead of the \isacom{case} and \?case\ magic we have spelled all formulas out. This is merely for greater clarity. \item We only need to deal with one case because the @{thm[source] ev0} case is impossible. \item The form of the \IH\ shows us that internally the lemma was expanded as explained above: \noquotes{@{prop[source]"ev x \ x = Suc m \ \ ev m"}}. \item The goal \<^prop>\\ ev (Suc n)\ may surprise. The expanded version of the lemma would suggest that we have a \isacom{fix} \m\ \isacom{assume} \<^prop>\Suc(Suc n) = Suc m\ and need to show \<^prop>\\ ev m\. What happened is that Isabelle immediately simplified \<^prop>\Suc(Suc n) = Suc m\ to \<^prop>\Suc n = m\ and could then eliminate \m\. Beware of such nice surprises with this advanced form of induction. \end{itemize} \begin{warn} This advanced form of induction does not support the \IH\ naming schema explained in \autoref{sec:assm-naming}: the induction hypotheses are instead found under the name \hyps\, as they are for the simpler \induct\ method. \end{warn} \index{induction|)} \index{cases@\cases\|)} \index{case@\isacom{case}|)} \index{case?@\?case\|)} \index{rule induction|)} \index{rule inversion|)} \subsection*{Exercises} \exercise Give a structured proof by rule inversion: \ lemma assumes a: "ev(Suc(Suc n))" shows "ev n" (*<*)oops(*>*) text\ \endexercise \begin{exercise} Give a structured proof of \<^prop>\\ ev(Suc(Suc(Suc 0)))\ by rule inversions. If there are no cases to be proved you can close a proof immediately with \isacom{qed}. \end{exercise} \begin{exercise} Recall predicate \star\ from \autoref{sec:star} and \iter\ from Exercise~\ref{exe:iter}. Prove \<^prop>\iter r n x y \ star r x y\ in a structured style; do not just sledgehammer each case of the required induction. \end{exercise} \begin{exercise} Define a recursive function \elems ::\ \<^typ>\'a list \ 'a set\ and prove \<^prop>\x \ elems xs \ \ys zs. xs = ys @ x # zs \ x \ elems ys\. \end{exercise} \begin{exercise} Extend Exercise~\ref{exe:cfg} with a function that checks if some \mbox{\alpha list\} is a balanced string of parentheses. More precisely, define a \mbox{recursive} function \balanced :: nat \ alpha list \ bool\ such that \<^term>\balanced n w\ is true iff (informally) \S (a\<^sup>n @ w)\. Formally, prove that \<^prop>\balanced n w \ S (replicate n a @ w)\ where \<^const>\replicate\ \::\ \<^typ>\nat \ 'a \ 'a list\ is predefined and \<^term>\replicate n x\ yields the list \[x, \, x]\ of length \n\. \end{exercise} \ (*<*) end (*>*) diff --git a/src/Doc/Prog_Prove/document/prelude.tex b/src/Doc/Prog_Prove/document/prelude.tex --- a/src/Doc/Prog_Prove/document/prelude.tex +++ b/src/Doc/Prog_Prove/document/prelude.tex @@ -1,92 +1,95 @@ \usepackage{makeidx} % allows index generation \usepackage{graphicx} % standard LaTeX graphics tool % when including figure files \usepackage{multicol} % used for the two-column index \usepackage[bottom]{footmisc}% places footnotes at page bottom \usepackage{alltt} \usepackage[T1]{fontenc} -\usepackage{ccfonts} +\usepackage[boldsans]{ccfonts} +\DeclareFontSeriesDefault[rm]{bf}{bx}%bf default for rm: bold extended +\DeclareFontSeriesDefault[sf]{bf}{sbc}%bf default for sf: semibold \usepackage[euler-digits]{eulervm} \usepackage{isabelle,isabellesym} \usepackage{mathpartir} \usepackage{amssymb} \renewcommand*\descriptionlabel[1]{\hspace\labelsep \textbf{#1}\hfil} % this should be the last package used \usepackage{xcolor} \definecolor{linkcolor}{rgb}{0,0,0.4} \usepackage[colorlinks=true,linkcolor=linkcolor,citecolor=linkcolor, filecolor=linkcolor,pagecolor=linkcolor, urlcolor=linkcolor]{hyperref} % urls in roman style, theory text in math-similar italics \urlstyle{tt} \isabellestyle{it} \renewcommand{\isadigit}[1]{\ensuremath{#1}} % font size \renewcommand{\isastyle}{\isastyleminor} % indexing \usepackage{ifthen} \newcommand{\indexdef}[3]% {\ifthenelse{\equal{}{#1}}{\index{#3 (#2)|bold}}{\index{#3 (#1\ #2)|bold}}} % section commands \renewcommand{\chapterautorefname}{Chapter} \renewcommand{\sectionautorefname}{Section} \renewcommand{\subsectionautorefname}{Section} \renewcommand{\isamarkupsection}[1]{{\rmfamily\subsection{#1}}} \renewcommand{\isamarkupsubsection}[1]{{\rmfamily\subsubsection{#1}}} % isabelle in-text command font \newcommand{\isacom}[1]{\isa{\isacommand{#1}}} \protected\def\isacharunderscore{\raisebox{2pt}{\_\kern-1.7pt}} \protected\def\isacharunderscorekeyword{\raisebox{2pt}{\_}} % isabelle keyword, adapted from isabelle.sty \renewcommand{\isakeyword}[1] -{\emph{\def\isachardot{.}\def\isacharunderscore{\isacharunderscorekeyword}% -\def\isacharbraceleft{\{}\def\isacharbraceright{\}}\def\bfdefault{sbc}\textbf{#1}}} +{\emph{\sffamily\bfseries% +\def\isachardot{.}\def\isacharunderscore{\isacharunderscorekeyword}% +\def\isacharbraceleft{\{}\def\isacharbraceright{\}}#1}} % add \noindent to text blocks automatically \renewenvironment{isamarkuptext}{\par\isastyletext\begin{isapar}\noindent}{\end{isapar}} \renewenvironment{isamarkuptxt}{\par\isastyletext\begin{isapar}\noindent}{\end{isapar}} \newcommand{\noquotes}[1]{{\renewcommand{\isachardoublequote}{}\renewcommand{\isachardoublequoteopen}{}\renewcommand{\isachardoublequoteclose}{}#1}} \newcommand{\xsymbol}[1]{\texttt{\char`\\\char`<#1>}} %index \newcommand{\conceptnoidx}[1]{\textbf{#1}} \newcommand{\concept}[1]{\conceptnoidx{#1}\index{#1}} \newcommand{\conceptidx}[2]{\conceptnoidx{#1}\index{#2}} \newcommand{\indexed}[2]{#1\index{#2@\protect#1}} \newcommand{\isabox}{\fbox} \newcommand{\bigisabox}[1] {\isabox{\renewcommand{\isanewline}{\\}% \begin{tabular}{l}#1\end{tabular}}} %%%% ``WARNING'' environment: 2 ! characters separated by negative thin space %\def\warnbang{\vtop to 0pt{\vss\hbox{\let\bfdefault=\bfdefaultold\Huge\textbf{!$\!$!}}\vss}} \def\warnbang{\vtop to 0pt{\vss\hbox{\includegraphics[width=3ex, height=5.5ex]{bang}}\vss}} \newenvironment{warn}{\begin{trivlist}\small\item[]\noindent% \begingroup\hangindent=\parindent\hangafter=-2%\clubpenalty=10000% \def\par{\endgraf\endgroup}% \hbox to0pt{\hskip-\hangindent\warnbang\hfill}\ignorespaces} {\par\end{trivlist}} \chardef\isachardoublequote=`\"% \chardef\isachardoublequoteopen=`\"% \chardef\isachardoublequoteclose=`\"% \renewcommand{\isacharbackquoteopen}{\isacharbackquote} \renewcommand{\isacharbackquoteclose}{\isacharbackquote} \hyphenation{Isa-belle}